• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4  * COPYRIGHT:
5  * Copyright (c) 1997-2016, International Business Machines Corporation and
6  * others. All Rights Reserved.
7  ********************************************************************/
8 /*****************************************************************************
9 *
10 * File CLOCTST.C
11 *
12 * Modification History:
13 *        Name                     Description
14 *     Madhu Katragadda            Ported for C API
15 ******************************************************************************
16 */
17 #include "cloctst.h"
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include "cintltst.h"
22 #include "cmemory.h"
23 #include "cstring.h"
24 #include "uparse.h"
25 #include "uresimp.h"
26 #include "uassert.h"
27 
28 #include "unicode/putil.h"
29 #include "unicode/ubrk.h"
30 #include "unicode/uchar.h"
31 #include "unicode/ucol.h"
32 #include "unicode/udat.h"
33 #include "unicode/uloc.h"
34 #include "unicode/umsg.h"
35 #include "unicode/ures.h"
36 #include "unicode/uset.h"
37 #include "unicode/ustring.h"
38 #include "unicode/utypes.h"
39 #include "unicode/ulocdata.h"
40 #include "unicode/uldnames.h"
41 #include "unicode/parseerr.h" /* may not be included with some uconfig switches */
42 #include "udbgutil.h"
43 
44 static void TestNullDefault(void);
45 static void TestNonexistentLanguageExemplars(void);
46 static void TestLocDataErrorCodeChaining(void);
47 static void TestLocDataWithRgTag(void);
48 static void TestLanguageExemplarsFallbacks(void);
49 static void TestDisplayNameBrackets(void);
50 
51 static void TestUnicodeDefines(void);
52 
53 static void TestIsRightToLeft(void);
54 static void TestBadLocaleIDs(void);
55 static void TestBug20370(void);
56 static void TestBug20321UnicodeLocaleKey(void);
57 
58 void PrintDataTable();
59 
60 /*---------------------------------------------------
61   table of valid data
62  --------------------------------------------------- */
63 #define LOCALE_SIZE 9
64 #define LOCALE_INFO_SIZE 28
65 
66 static const char* const rawData2[LOCALE_INFO_SIZE][LOCALE_SIZE] = {
67     /* language code */
68     {   "en",   "fr",   "ca",   "el",   "no",   "zh",   "de",   "es",  "ja"    },
69     /* script code */
70     {   "",     "",     "",     "",     "",     "", "", "", ""  },
71     /* country code */
72     {   "US",   "FR",   "ES",   "GR",   "NO",   "CN", "DE", "", "JP"    },
73     /* variant code */
74     {   "",     "",     "",     "",     "NY",   "", "", "", ""      },
75     /* full name */
76     {   "en_US",    "fr_FR",    "ca_ES",
77         "el_GR",    "no_NO_NY", "zh_Hans_CN",
78         "de_DE@collation=phonebook", "es@collation=traditional",  "ja_JP@calendar=japanese" },
79     /* ISO-3 language */
80     {   "eng",  "fra",  "cat",  "ell",  "nor",  "zho", "deu", "spa", "jpn"   },
81     /* ISO-3 country */
82     {   "USA",  "FRA",  "ESP",  "GRC",  "NOR",  "CHN", "DEU", "", "JPN"   },
83     /* LCID */
84     {   "409", "40c", "403", "408", "814",  "804", "10407", "40a", "411"     },
85 
86     /* display language (English) */
87     {   "English",  "French",   "Catalan", "Greek",    "Norwegian", "Chinese", "German", "Spanish", "Japanese"    },
88     /* display script code (English) */
89     {   "",     "",     "",     "",     "",     "Simplified Han", "", "", ""       },
90     /* display country (English) */
91     {   "United States",    "France",   "Spain",  "Greece",   "Norway", "China", "Germany", "", "Japan"       },
92     /* display variant (English) */
93     {   "",     "",     "",     "",     "NY",  "", "", "", ""       },
94     /* display name (English) */
95     {   "English (United States)", "French (France)", "Catalan (Spain)",
96         "Greek (Greece)", "Norwegian (Norway, NY)", "Chinese (Simplified, China)",
97         "German (Germany, Sort Order=Phonebook Sort Order)", "Spanish (Sort Order=Traditional Sort Order)", "Japanese (Japan, Calendar=Japanese Calendar)" },
98 
99     /* display language (French) */
100     {   "anglais",  "fran\\u00E7ais",   "catalan", "grec",    "norv\\u00E9gien",    "chinois", "allemand", "espagnol", "japonais"     },
101     /* display script code (French) */
102     {   "",     "",     "",     "",     "",     "sinogrammes simplifi\\u00e9s", "", "", ""         },
103     /* display country (French) */
104     {   "\\u00C9tats-Unis",    "France",   "Espagne",  "Gr\\u00E8ce",   "Norv\\u00E8ge",    "Chine", "Allemagne", "", "Japon"       },
105     /* display variant (French) */
106     {   "",     "",     "",     "",     "NY",   "", "", "", ""       },
107     /* display name (French) */
108     {   "anglais (\\u00C9tats-Unis)", "fran\\u00E7ais (France)", "catalan (Espagne)",
109         "grec (Gr\\u00E8ce)", "norv\\u00E9gien (Norv\\u00E8ge, NY)",  "chinois (simplifi\\u00e9, Chine)",
110         "allemand (Allemagne, ordre de tri=ordre de l\\u2019annuaire)", "espagnol (ordre de tri=ordre traditionnel)", "japonais (Japon, calendrier=calendrier japonais)" },
111 
112     /* display language (Catalan) */
113     {   "angl\\u00E8s", "franc\\u00E8s", "catal\\u00E0", "grec",  "noruec", "xin\\u00E8s", "alemany", "espanyol", "japon\\u00E8s"    },
114     /* display script code (Catalan) */
115     {   "",     "",     "",     "",     "",     "han simplificat", "", "", ""         },
116     /* display country (Catalan) */
117     {   "Estats Units", "Fran\\u00E7a", "Espanya",  "Gr\\u00E8cia", "Noruega",  "Xina", "Alemanya", "", "Jap\\u00F3"    },
118     /* display variant (Catalan) */
119     {   "", "", "",                    "", "NY",    "", "", "", ""    },
120     /* display name (Catalan) */
121     {   "angl\\u00E8s (Estats Units)", "franc\\u00E8s (Fran\\u00E7a)", "catal\\u00E0 (Espanya)",
122     "grec (Gr\\u00E8cia)", "noruec (Noruega, NY)", "xin\\u00E8s (simplificat, Xina)",
123     "alemany (Alemanya, ordenaci\\u00F3=ordre de la guia telef\\u00F2nica)", "espanyol (ordenaci\\u00F3=ordre tradicional)", "japon\\u00E8s (Jap\\u00F3, calendari=calendari japon\\u00e8s)" },
124 
125     /* display language (Greek) */
126     {
127         "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac",
128         "\\u0393\\u03b1\\u03bb\\u03bb\\u03b9\\u03ba\\u03ac",
129         "\\u039a\\u03b1\\u03c4\\u03b1\\u03bb\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac",
130         "\\u0395\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac",
131         "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac",
132         "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC",
133         "\\u0393\\u03B5\\u03C1\\u03BC\\u03B1\\u03BD\\u03B9\\u03BA\\u03AC",
134         "\\u0399\\u03C3\\u03C0\\u03B1\\u03BD\\u03B9\\u03BA\\u03AC",
135         "\\u0399\\u03B1\\u03C0\\u03C9\\u03BD\\u03B9\\u03BA\\u03AC"
136     },
137     /* display script code (Greek) */
138 
139     {   "",     "",     "",     "",     "", "\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03bf \\u03a7\\u03b1\\u03bd", "", "", "" },
140     /* display country (Greek) */
141     {
142         "\\u0397\\u03BD\\u03C9\\u03BC\\u03AD\\u03BD\\u03B5\\u03C2 \\u03A0\\u03BF\\u03BB\\u03B9\\u03C4\\u03B5\\u03AF\\u03B5\\u03C2",
143         "\\u0393\\u03b1\\u03bb\\u03bb\\u03af\\u03b1",
144         "\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1",
145         "\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1",
146         "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1",
147         "\\u039A\\u03AF\\u03BD\\u03B1",
148         "\\u0393\\u03B5\\u03C1\\u03BC\\u03B1\\u03BD\\u03AF\\u03B1",
149         "",
150         "\\u0399\\u03B1\\u03C0\\u03C9\\u03BD\\u03AF\\u03B1"
151     },
152     /* display variant (Greek) */
153     {   "", "", "", "", "NY", "", "", "", ""    }, /* TODO: currently there is no translation for NY in Greek fix this test when we have it */
154     /* display name (Greek) */
155     {
156         "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac (\\u0397\\u03BD\\u03C9\\u03BC\\u03AD\\u03BD\\u03B5\\u03C2 \\u03A0\\u03BF\\u03BB\\u03B9\\u03C4\\u03B5\\u03AF\\u03B5\\u03C2)",
157         "\\u0393\\u03b1\\u03bb\\u03bb\\u03b9\\u03ba\\u03ac (\\u0393\\u03b1\\u03bb\\u03bb\\u03af\\u03b1)",
158         "\\u039a\\u03b1\\u03c4\\u03b1\\u03bb\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1)",
159         "\\u0395\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac (\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1)",
160         "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac (\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1, NY)",
161         "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC (\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03bf, \\u039A\\u03AF\\u03BD\\u03B1)",
162         "\\u0393\\u03b5\\u03c1\\u03bc\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u0393\\u03b5\\u03c1\\u03bc\\u03b1\\u03bd\\u03af\\u03b1, \\u03a3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2=\\u03a3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2 \\u03c4\\u03b7\\u03bb\\u03b5\\u03c6\\u03c9\\u03bd\\u03b9\\u03ba\\u03bf\\u03cd \\u03ba\\u03b1\\u03c4\\u03b1\\u03bb\\u03cc\\u03b3\\u03bf\\u03c5)",
163         "\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u03a3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2=\\u03a0\\u03b1\\u03c1\\u03b1\\u03b4\\u03bf\\u03c3\\u03b9\\u03b1\\u03ba\\u03ae \\u03c3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2)",
164         "\\u0399\\u03b1\\u03c0\\u03c9\\u03bd\\u03b9\\u03ba\\u03ac (\\u0399\\u03b1\\u03c0\\u03c9\\u03bd\\u03af\\u03b1, \\u0397\\u03bc\\u03b5\\u03c1\\u03bf\\u03bb\\u03cc\\u03b3\\u03b9\\u03bf=\\u0399\\u03b1\\u03c0\\u03c9\\u03bd\\u03b9\\u03ba\\u03cc \\u03b7\\u03bc\\u03b5\\u03c1\\u03bf\\u03bb\\u03cc\\u03b3\\u03b9\\u03bf)"
165     }
166 };
167 
168 static UChar*** dataTable=0;
169 enum {
170     ENGLISH = 0,
171     FRENCH = 1,
172     CATALAN = 2,
173     GREEK = 3,
174     NORWEGIAN = 4
175 };
176 
177 enum {
178     LANG = 0,
179     SCRIPT = 1,
180     CTRY = 2,
181     VAR = 3,
182     NAME = 4,
183     LANG3 = 5,
184     CTRY3 = 6,
185     LCID = 7,
186     DLANG_EN = 8,
187     DSCRIPT_EN = 9,
188     DCTRY_EN = 10,
189     DVAR_EN = 11,
190     DNAME_EN = 12,
191     DLANG_FR = 13,
192     DSCRIPT_FR = 14,
193     DCTRY_FR = 15,
194     DVAR_FR = 16,
195     DNAME_FR = 17,
196     DLANG_CA = 18,
197     DSCRIPT_CA = 19,
198     DCTRY_CA = 20,
199     DVAR_CA = 21,
200     DNAME_CA = 22,
201     DLANG_EL = 23,
202     DSCRIPT_EL = 24,
203     DCTRY_EL = 25,
204     DVAR_EL = 26,
205     DNAME_EL = 27
206 };
207 
208 #define TESTCASE(name) addTest(root, &name, "tsutil/cloctst/" #name)
209 
210 void addLocaleTest(TestNode** root);
211 
addLocaleTest(TestNode ** root)212 void addLocaleTest(TestNode** root)
213 {
214     TESTCASE(TestObsoleteNames); /* srl- move */
215     TESTCASE(TestBasicGetters);
216     TESTCASE(TestNullDefault);
217     TESTCASE(TestPrefixes);
218     TESTCASE(TestSimpleResourceInfo);
219     TESTCASE(TestDisplayNames);
220     TESTCASE(TestGetAvailableLocales);
221     TESTCASE(TestGetAvailableLocalesByType);
222     TESTCASE(TestDataDirectory);
223 #if !UCONFIG_NO_FILE_IO && !UCONFIG_NO_LEGACY_CONVERSION
224     TESTCASE(TestISOFunctions);
225 #endif
226     TESTCASE(TestISO3Fallback);
227     TESTCASE(TestUninstalledISO3Names);
228     TESTCASE(TestSimpleDisplayNames);
229     TESTCASE(TestVariantParsing);
230     TESTCASE(TestKeywordVariants);
231     TESTCASE(TestKeywordVariantParsing);
232     TESTCASE(TestCanonicalization);
233     TESTCASE(TestCanonicalizationBuffer);
234     TESTCASE(TestKeywordSet);
235     TESTCASE(TestKeywordSetError);
236     TESTCASE(TestDisplayKeywords);
237     TESTCASE(TestDisplayKeywordValues);
238     TESTCASE(TestGetBaseName);
239 #if !UCONFIG_NO_FILE_IO
240     TESTCASE(TestGetLocale);
241 #endif
242     TESTCASE(TestDisplayNameWarning);
243     TESTCASE(TestNonexistentLanguageExemplars);
244     TESTCASE(TestLocDataErrorCodeChaining);
245     TESTCASE(TestLocDataWithRgTag);
246     TESTCASE(TestLanguageExemplarsFallbacks);
247     TESTCASE(TestCalendar);
248     TESTCASE(TestDateFormat);
249     TESTCASE(TestCollation);
250     TESTCASE(TestULocale);
251     TESTCASE(TestUResourceBundle);
252     TESTCASE(TestDisplayName);
253     TESTCASE(TestAcceptLanguage);
254     TESTCASE(TestGetLocaleForLCID);
255     TESTCASE(TestOrientation);
256     TESTCASE(TestLikelySubtags);
257     TESTCASE(TestToLanguageTag);
258     TESTCASE(TestBug20132);
259     TESTCASE(TestBug20149);
260     TESTCASE(TestForLanguageTag);
261     TESTCASE(TestLangAndRegionCanonicalize);
262     TESTCASE(TestTrailingNull);
263     TESTCASE(TestUnicodeDefines);
264     TESTCASE(TestEnglishExemplarCharacters);
265     TESTCASE(TestDisplayNameBrackets);
266     TESTCASE(TestIsRightToLeft);
267     TESTCASE(TestToUnicodeLocaleKey);
268     TESTCASE(TestToLegacyKey);
269     TESTCASE(TestToUnicodeLocaleType);
270     TESTCASE(TestToLegacyType);
271     TESTCASE(TestBadLocaleIDs);
272     TESTCASE(TestBug20370);
273     TESTCASE(TestBug20321UnicodeLocaleKey);
274 }
275 
276 
277 /* testing uloc(), uloc_getName(), uloc_getLanguage(), uloc_getVariant(), uloc_getCountry() */
TestBasicGetters()278 static void TestBasicGetters() {
279     int32_t i;
280     int32_t cap;
281     UErrorCode status = U_ZERO_ERROR;
282     char *testLocale = 0;
283     char *temp = 0, *name = 0;
284     log_verbose("Testing Basic Getters\n");
285     for (i = 0; i < LOCALE_SIZE; i++) {
286         testLocale=(char*)malloc(sizeof(char) * (strlen(rawData2[NAME][i])+1));
287         strcpy(testLocale,rawData2[NAME][i]);
288 
289         log_verbose("Testing   %s  .....\n", testLocale);
290         cap=uloc_getLanguage(testLocale, NULL, 0, &status);
291         if(status==U_BUFFER_OVERFLOW_ERROR){
292             status=U_ZERO_ERROR;
293             temp=(char*)malloc(sizeof(char) * (cap+1));
294             uloc_getLanguage(testLocale, temp, cap+1, &status);
295         }
296         if(U_FAILURE(status)){
297             log_err("ERROR: in uloc_getLanguage  %s\n", myErrorName(status));
298         }
299         if (0 !=strcmp(temp,rawData2[LANG][i]))    {
300             log_err("  Language code mismatch: %s versus  %s\n", temp, rawData2[LANG][i]);
301         }
302 
303 
304         cap=uloc_getCountry(testLocale, temp, cap, &status);
305         if(status==U_BUFFER_OVERFLOW_ERROR){
306             status=U_ZERO_ERROR;
307             temp=(char*)realloc(temp, sizeof(char) * (cap+1));
308             uloc_getCountry(testLocale, temp, cap+1, &status);
309         }
310         if(U_FAILURE(status)){
311             log_err("ERROR: in uloc_getCountry  %s\n", myErrorName(status));
312         }
313         if (0 != strcmp(temp, rawData2[CTRY][i])) {
314             log_err(" Country code mismatch:  %s  versus   %s\n", temp, rawData2[CTRY][i]);
315 
316           }
317 
318         cap=uloc_getVariant(testLocale, temp, cap, &status);
319         if(status==U_BUFFER_OVERFLOW_ERROR){
320             status=U_ZERO_ERROR;
321             temp=(char*)realloc(temp, sizeof(char) * (cap+1));
322             uloc_getVariant(testLocale, temp, cap+1, &status);
323         }
324         if(U_FAILURE(status)){
325             log_err("ERROR: in uloc_getVariant  %s\n", myErrorName(status));
326         }
327         if (0 != strcmp(temp, rawData2[VAR][i])) {
328             log_err("Variant code mismatch:  %s  versus   %s\n", temp, rawData2[VAR][i]);
329         }
330 
331         cap=uloc_getName(testLocale, NULL, 0, &status);
332         if(status==U_BUFFER_OVERFLOW_ERROR){
333             status=U_ZERO_ERROR;
334             name=(char*)malloc(sizeof(char) * (cap+1));
335             uloc_getName(testLocale, name, cap+1, &status);
336         } else if(status==U_ZERO_ERROR) {
337           log_err("ERROR: in uloc_getName(%s,NULL,0,..), expected U_BUFFER_OVERFLOW_ERROR!\n", testLocale);
338         }
339         if(U_FAILURE(status)){
340             log_err("ERROR: in uloc_getName   %s\n", myErrorName(status));
341         }
342         if (0 != strcmp(name, rawData2[NAME][i])){
343             log_err(" Mismatch in getName:  %s  versus   %s\n", name, rawData2[NAME][i]);
344         }
345 
346         free(temp);
347         free(name);
348 
349         free(testLocale);
350     }
351 }
352 
TestNullDefault()353 static void TestNullDefault() {
354     UErrorCode status = U_ZERO_ERROR;
355     char original[ULOC_FULLNAME_CAPACITY];
356 
357     uprv_strcpy(original, uloc_getDefault());
358     uloc_setDefault("qq_BLA", &status);
359     if (uprv_strcmp(uloc_getDefault(), "qq_BLA") != 0) {
360         log_err(" Mismatch in uloc_setDefault:  qq_BLA  versus   %s\n", uloc_getDefault());
361     }
362     uloc_setDefault(NULL, &status);
363     if (uprv_strcmp(uloc_getDefault(), original) != 0) {
364         log_err(" uloc_setDefault(NULL, &status) didn't get the default locale back!\n");
365     }
366 
367     {
368     /* Test that set & get of default locale work, and that
369      * default locales are cached and reused, and not overwritten.
370      */
371         const char *n_en_US;
372         const char *n_fr_FR;
373         const char *n2_en_US;
374 
375         status = U_ZERO_ERROR;
376         uloc_setDefault("en_US", &status);
377         n_en_US = uloc_getDefault();
378         if (strcmp(n_en_US, "en_US") != 0) {
379             log_err("Wrong result from uloc_getDefault().  Expected \"en_US\", got \"%s\"\n", n_en_US);
380         }
381 
382         uloc_setDefault("fr_FR", &status);
383         n_fr_FR = uloc_getDefault();
384         if (strcmp(n_en_US, "en_US") != 0) {
385             log_err("uloc_setDefault altered previously default string."
386                 "Expected \"en_US\", got \"%s\"\n",  n_en_US);
387         }
388         if (strcmp(n_fr_FR, "fr_FR") != 0) {
389             log_err("Wrong result from uloc_getDefault().  Expected \"fr_FR\", got %s\n",  n_fr_FR);
390         }
391 
392         uloc_setDefault("en_US", &status);
393         n2_en_US = uloc_getDefault();
394         if (strcmp(n2_en_US, "en_US") != 0) {
395             log_err("Wrong result from uloc_getDefault().  Expected \"en_US\", got \"%s\"\n", n_en_US);
396         }
397         if (n2_en_US != n_en_US) {
398             log_err("Default locale cache failed to reuse en_US locale.\n");
399         }
400 
401         if (U_FAILURE(status)) {
402             log_err("Failure returned from uloc_setDefault - \"%s\"\n", u_errorName(status));
403         }
404 
405     }
406 
407 }
408 /* Test the i- and x- and @ and . functionality
409 */
410 
411 #define PREFIXBUFSIZ 128
412 
TestPrefixes()413 static void TestPrefixes() {
414     int row = 0;
415     int n;
416     const char *loc, *expected;
417 
418     static const char * const testData[][7] =
419     {
420         /* NULL canonicalize() column means "expect same as getName()" */
421         {"sv", "", "FI", "AL", "sv-fi-al", "sv_FI_AL", NULL},
422         {"en", "", "GB", "", "en-gb", "en_GB", NULL},
423         {"i-hakka", "", "MT", "XEMXIJA", "i-hakka_MT_XEMXIJA", "i-hakka_MT_XEMXIJA", NULL},
424         {"i-hakka", "", "CN", "", "i-hakka_CN", "i-hakka_CN", NULL},
425         {"i-hakka", "", "MX", "", "I-hakka_MX", "i-hakka_MX", NULL},
426         {"x-klingon", "", "US", "SANJOSE", "X-KLINGON_us_SANJOSE", "x-klingon_US_SANJOSE", NULL},
427         {"hy", "", "", "AREVMDA", "hy_AREVMDA", "hy__AREVMDA", "hyw"},
428         {"de", "", "", "1901", "de-1901", "de__1901", NULL},
429         {"mr", "", "", "", "mr.utf8", "mr.utf8", "mr"},
430         {"de", "", "TV", "", "de-tv.koi8r", "de_TV.koi8r", "de_TV"},
431         {"x-piglatin", "", "ML", "", "x-piglatin_ML.MBE", "x-piglatin_ML.MBE", "x-piglatin_ML"},  /* Multibyte English */
432         {"i-cherokee", "","US", "", "i-Cherokee_US.utf7", "i-cherokee_US.utf7", "i-cherokee_US"},
433         {"x-filfli", "", "MT", "FILFLA", "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA"},
434         {"no", "", "NO", "NY", "no-no-ny.utf32@B", "no_NO_NY.utf32@B", "no_NO_NY_B"},
435         {"no", "", "NO", "",  "no-no.utf32@B", "no_NO.utf32@B", "no_NO_B"},
436         {"no", "", "",   "NY", "no__ny", "no__NY", NULL},
437         {"no", "", "",   "", "no@ny", "no@ny", "no__NY"},
438         {"el", "Latn", "", "", "el-latn", "el_Latn", NULL},
439         {"en", "Cyrl", "RU", "", "en-cyrl-ru", "en_Cyrl_RU", NULL},
440         {"qq", "Qqqq", "QQ", "QQ", "qq_Qqqq_QQ_QQ", "qq_Qqqq_QQ_QQ", NULL},
441         {"qq", "Qqqq", "", "QQ", "qq_Qqqq__QQ", "qq_Qqqq__QQ", NULL},
442         {"ab", "Cdef", "GH", "IJ", "ab_cdef_gh_ij", "ab_Cdef_GH_IJ", NULL}, /* total garbage */
443 
444         // Before ICU 64, ICU locale canonicalization had some additional mappings.
445         // They were removed for ICU-20187 "drop support for long-obsolete locale ID variants".
446         // The following now use standard canonicalization.
447         {"zh", "Hans", "", "PINYIN", "zh-Hans-pinyin", "zh_Hans__PINYIN", "zh_Hans__PINYIN"},
448         {"zh", "Hant", "TW", "STROKE", "zh-hant_TW_STROKE", "zh_Hant_TW_STROKE", "zh_Hant_TW_STROKE"},
449 
450         {NULL,NULL,NULL,NULL,NULL,NULL,NULL}
451     };
452 
453     static const char * const testTitles[] = {
454         "uloc_getLanguage()",
455         "uloc_getScript()",
456         "uloc_getCountry()",
457         "uloc_getVariant()",
458         "name",
459         "uloc_getName()",
460         "uloc_canonicalize()"
461     };
462 
463     char buf[PREFIXBUFSIZ];
464     int32_t len;
465     UErrorCode err;
466 
467 
468     for(row=0;testData[row][0] != NULL;row++) {
469         loc = testData[row][NAME];
470         log_verbose("Test #%d: %s\n", row, loc);
471 
472         err = U_ZERO_ERROR;
473         len=0;
474         buf[0]=0;
475         for(n=0;n<=(NAME+2);n++) {
476             if(n==NAME) continue;
477 
478             for(len=0;len<PREFIXBUFSIZ;len++) {
479                 buf[len] = '%'; /* Set a tripwire.. */
480             }
481             len = 0;
482 
483             switch(n) {
484             case LANG:
485                 len = uloc_getLanguage(loc, buf, PREFIXBUFSIZ, &err);
486                 break;
487 
488             case SCRIPT:
489                 len = uloc_getScript(loc, buf, PREFIXBUFSIZ, &err);
490                 break;
491 
492             case CTRY:
493                 len = uloc_getCountry(loc, buf, PREFIXBUFSIZ, &err);
494                 break;
495 
496             case VAR:
497                 len = uloc_getVariant(loc, buf, PREFIXBUFSIZ, &err);
498                 break;
499 
500             case NAME+1:
501                 len = uloc_getName(loc, buf, PREFIXBUFSIZ, &err);
502                 break;
503 
504             case NAME+2:
505                 len = uloc_canonicalize(loc, buf, PREFIXBUFSIZ, &err);
506                 break;
507 
508             default:
509                 strcpy(buf, "**??");
510                 len=4;
511             }
512 
513             if(U_FAILURE(err)) {
514                 log_err("#%d: %s on %s: err %s\n",
515                     row, testTitles[n], loc, u_errorName(err));
516             } else {
517                 log_verbose("#%d: %s on %s: -> [%s] (length %d)\n",
518                     row, testTitles[n], loc, buf, len);
519 
520                 if(len != (int32_t)strlen(buf)) {
521                     log_err("#%d: %s on %s: -> [%s] (length returned %d, actual %d!)\n",
522                         row, testTitles[n], loc, buf, len, strlen(buf)+1);
523 
524                 }
525 
526                 /* see if they smashed something */
527                 if(buf[len+1] != '%') {
528                     log_err("#%d: %s on %s: -> [%s] - wrote [%X] out ofbounds!\n",
529                         row, testTitles[n], loc, buf, buf[len+1]);
530                 }
531 
532                 expected = testData[row][n];
533                 if (expected == NULL && n == (NAME+2)) {
534                     /* NULL expected canonicalize() means "expect same as getName()" */
535                     expected = testData[row][NAME+1];
536                 }
537                 if(strcmp(buf, expected)) {
538                     log_err("#%d: %s on %s: -> [%s] (expected '%s'!)\n",
539                         row, testTitles[n], loc, buf, expected);
540 
541                 }
542             }
543         }
544     }
545 }
546 
547 
548 /* testing uloc_getISO3Language(), uloc_getISO3Country(),  */
TestSimpleResourceInfo()549 static void TestSimpleResourceInfo() {
550     int32_t i;
551     char* testLocale = 0;
552     UChar* expected = 0;
553 
554     const char* temp;
555     char            temp2[20];
556     testLocale=(char*)malloc(sizeof(char) * 1);
557     expected=(UChar*)malloc(sizeof(UChar) * 1);
558 
559     setUpDataTable();
560     log_verbose("Testing getISO3Language and getISO3Country\n");
561     for (i = 0; i < LOCALE_SIZE; i++) {
562 
563         testLocale=(char*)realloc(testLocale, sizeof(char) * (u_strlen(dataTable[NAME][i])+1));
564         u_austrcpy(testLocale, dataTable[NAME][i]);
565 
566         log_verbose("Testing   %s ......\n", testLocale);
567 
568         temp=uloc_getISO3Language(testLocale);
569         expected=(UChar*)realloc(expected, sizeof(UChar) * (strlen(temp) + 1));
570         u_uastrcpy(expected,temp);
571         if (0 != u_strcmp(expected, dataTable[LANG3][i])) {
572             log_err("  ISO-3 language code mismatch:  %s versus  %s\n",  austrdup(expected),
573                 austrdup(dataTable[LANG3][i]));
574         }
575 
576         temp=uloc_getISO3Country(testLocale);
577         expected=(UChar*)realloc(expected, sizeof(UChar) * (strlen(temp) + 1));
578         u_uastrcpy(expected,temp);
579         if (0 != u_strcmp(expected, dataTable[CTRY3][i])) {
580             log_err("  ISO-3 Country code mismatch:  %s versus  %s\n",  austrdup(expected),
581                 austrdup(dataTable[CTRY3][i]));
582         }
583         sprintf(temp2, "%x", (int)uloc_getLCID(testLocale));
584         if (strcmp(temp2, rawData2[LCID][i]) != 0) {
585             log_err("LCID mismatch: %s versus %s\n", temp2 , rawData2[LCID][i]);
586         }
587     }
588 
589     free(expected);
590     free(testLocale);
591     cleanUpDataTable();
592 }
593 
594 /* if len < 0, we convert until we hit UChar 0x0000, which is not output. will add trailing null
595  * if there's room but won't be included in result.  result < 0 indicates an error.
596  * Returns the number of chars written (not those that would be written if there's enough room.*/
UCharsToEscapedAscii(const UChar * utext,int32_t len,char * resultChars,int32_t buflen)597 static int32_t UCharsToEscapedAscii(const UChar* utext, int32_t len, char* resultChars, int32_t buflen) {
598     static const struct {
599         char escapedChar;
600         UChar sourceVal;
601     } ESCAPE_MAP[] = {
602         /*a*/ {'a', 0x07},
603         /*b*/ {'b', 0x08},
604         /*e*/ {'e', 0x1b},
605         /*f*/ {'f', 0x0c},
606         /*n*/ {'n', 0x0a},
607         /*r*/ {'r', 0x0d},
608         /*t*/ {'t', 0x09},
609         /*v*/ {'v', 0x0b}
610     };
611     static const int32_t ESCAPE_MAP_LENGTH = UPRV_LENGTHOF(ESCAPE_MAP);
612     static const char HEX_DIGITS[] = {
613         '0', '1', '2', '3', '4', '5', '6', '7',
614         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
615     };
616     int32_t i, j;
617     int32_t resultLen = 0;
618     const int32_t limit = len<0 ? buflen : len; /* buflen is long enough to hit the buffer limit */
619     const int32_t escapeLimit1 = buflen-2;
620     const int32_t escapeLimit2 = buflen-6;
621     UChar uc;
622 
623     if(utext==NULL || resultChars==NULL || buflen<0) {
624         return -1;
625     }
626 
627     for(i=0;i<limit && resultLen<buflen;++i) {
628         uc=utext[i];
629         if(len<0 && uc==0) {
630             break;
631         }
632         if(uc<0x20) {
633             for(j=0;j<ESCAPE_MAP_LENGTH && uc!=ESCAPE_MAP[j].sourceVal;j++) {
634             }
635             if(j<ESCAPE_MAP_LENGTH) {
636                 if(resultLen>escapeLimit1) {
637                     break;
638                 }
639                 resultChars[resultLen++]='\\';
640                 resultChars[resultLen++]=ESCAPE_MAP[j].escapedChar;
641                 continue;
642             }
643         } else if(uc<0x7f) {
644             u_austrncpy(resultChars + resultLen, &uc, 1);
645             resultLen++;
646             continue;
647         }
648 
649         if(resultLen>escapeLimit2) {
650             break;
651         }
652 
653         /* have to escape the uchar */
654         resultChars[resultLen++]='\\';
655         resultChars[resultLen++]='u';
656         resultChars[resultLen++]=HEX_DIGITS[(uc>>12)&0xff];
657         resultChars[resultLen++]=HEX_DIGITS[(uc>>8)&0xff];
658         resultChars[resultLen++]=HEX_DIGITS[(uc>>4)&0xff];
659         resultChars[resultLen++]=HEX_DIGITS[uc&0xff];
660     }
661 
662     if(resultLen<buflen) {
663         resultChars[resultLen] = 0;
664     }
665 
666     return resultLen;
667 }
668 
669 /*
670  * Jitterbug 2439 -- markus 20030425
671  *
672  * The lookup of display names must not fall back through the default
673  * locale because that yields useless results.
674  */
TestDisplayNames()675 static void TestDisplayNames()
676 {
677     UChar buffer[100];
678     UErrorCode errorCode=U_ZERO_ERROR;
679     int32_t length;
680     log_verbose("Testing getDisplayName for different locales\n");
681 
682     log_verbose("  In locale = en_US...\n");
683     doTestDisplayNames("en_US", DLANG_EN);
684     log_verbose("  In locale = fr_FR....\n");
685     doTestDisplayNames("fr_FR", DLANG_FR);
686     log_verbose("  In locale = ca_ES...\n");
687     doTestDisplayNames("ca_ES", DLANG_CA);
688     log_verbose("  In locale = gr_EL..\n");
689     doTestDisplayNames("el_GR", DLANG_EL);
690 
691     /* test that the default locale has a display name for its own language */
692     errorCode=U_ZERO_ERROR;
693     length=uloc_getDisplayLanguage(NULL, NULL, buffer, UPRV_LENGTHOF(buffer), &errorCode);
694     if(U_FAILURE(errorCode) || (length<=3 && buffer[0]<=0x7f)) {
695         /* check <=3 to reject getting the language code as a display name */
696         log_data_err("unable to get a display string for the language of the default locale - %s (Are you missing data?)\n", u_errorName(errorCode));
697     }
698 
699     /* test that we get the language code itself for an unknown language, and a default warning */
700     errorCode=U_ZERO_ERROR;
701     length=uloc_getDisplayLanguage("qq", "rr", buffer, UPRV_LENGTHOF(buffer), &errorCode);
702     if(errorCode!=U_USING_DEFAULT_WARNING || length!=2 || buffer[0]!=0x71 || buffer[1]!=0x71) {
703         log_err("error getting the display string for an unknown language - %s\n", u_errorName(errorCode));
704     }
705 
706     /* test that we get a default warning for a display name where one component is unknown (4255) */
707     errorCode=U_ZERO_ERROR;
708     length=uloc_getDisplayName("qq_US_POSIX", "en_US", buffer, UPRV_LENGTHOF(buffer), &errorCode);
709     if(errorCode!=U_USING_DEFAULT_WARNING) {
710         log_err("error getting the display name for a locale with an unknown language - %s\n", u_errorName(errorCode));
711     }
712 
713     {
714         int32_t i;
715         static const char *aLocale = "es@collation=traditional;calendar=japanese";
716         static const char *testL[] = { "en_US",
717             "fr_FR",
718             "ca_ES",
719             "el_GR" };
720         static const char *expect[] = { "Spanish (Calendar=Japanese Calendar, Sort Order=Traditional Sort Order)", /* note sorted order of keywords */
721             "espagnol (calendrier=calendrier japonais, ordre de tri=ordre traditionnel)",
722             "espanyol (calendari=calendari japon\\u00e8s, ordenaci\\u00f3=ordre tradicional)",
723             "\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u0397\\u03bc\\u03b5\\u03c1\\u03bf\\u03bb\\u03cc\\u03b3\\u03b9\\u03bf=\\u0399\\u03b1\\u03c0\\u03c9\\u03bd\\u03b9\\u03ba\\u03cc \\u03b7\\u03bc\\u03b5\\u03c1\\u03bf\\u03bb\\u03cc\\u03b3\\u03b9\\u03bf, \\u03a3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2=\\u03a0\\u03b1\\u03c1\\u03b1\\u03b4\\u03bf\\u03c3\\u03b9\\u03b1\\u03ba\\u03ae \\u03c3\\u03b5\\u03b9\\u03c1\\u03ac \\u03c4\\u03b1\\u03be\\u03b9\\u03bd\\u03cc\\u03bc\\u03b7\\u03c3\\u03b7\\u03c2)" };
724         UChar *expectBuffer;
725 
726         for(i=0;i<UPRV_LENGTHOF(testL);i++) {
727             errorCode = U_ZERO_ERROR;
728             uloc_getDisplayName(aLocale, testL[i], buffer, UPRV_LENGTHOF(buffer), &errorCode);
729             if(U_FAILURE(errorCode)) {
730                 log_err("FAIL in uloc_getDisplayName(%s,%s,..) -> %s\n", aLocale, testL[i], u_errorName(errorCode));
731             } else {
732                 expectBuffer = CharsToUChars(expect[i]);
733                 if(u_strcmp(buffer,expectBuffer)) {
734                     log_data_err("FAIL in uloc_getDisplayName(%s,%s,..) expected '%s' got '%s' (Are you missing data?)\n", aLocale, testL[i], expect[i], austrdup(buffer));
735                 } else {
736                     log_verbose("pass in uloc_getDisplayName(%s,%s,..) got '%s'\n", aLocale, testL[i], expect[i]);
737                 }
738                 free(expectBuffer);
739             }
740         }
741     }
742 
743     /* test that we properly preflight and return data when there's a non-default pattern,
744        see ticket #8262. */
745     {
746         int32_t i;
747         static const char *locale="az_Cyrl";
748         static const char *displayLocale="ja";
749         static const char *expectedChars =
750                 "\\u30a2\\u30bc\\u30eb\\u30d0\\u30a4\\u30b8\\u30e3\\u30f3\\u8a9e "
751                 "(\\u30ad\\u30ea\\u30eb\\u6587\\u5b57)";
752         UErrorCode ec=U_ZERO_ERROR;
753         UChar result[256];
754         int32_t len;
755         int32_t preflightLen=uloc_getDisplayName(locale, displayLocale, NULL, 0, &ec);
756         /* inconvenient semantics when preflighting, this condition is expected... */
757         if(ec==U_BUFFER_OVERFLOW_ERROR) {
758             ec=U_ZERO_ERROR;
759         }
760         len=uloc_getDisplayName(locale, displayLocale, result, UPRV_LENGTHOF(result), &ec);
761         if(U_FAILURE(ec)) {
762             log_err("uloc_getDisplayName(%s, %s...) returned error: %s",
763                     locale, displayLocale, u_errorName(ec));
764         } else {
765             UChar *expected=CharsToUChars(expectedChars);
766             int32_t expectedLen=u_strlen(expected);
767 
768             if(len!=expectedLen) {
769                 log_data_err("uloc_getDisplayName(%s, %s...) returned string of length %d, expected length %d",
770                         locale, displayLocale, len, expectedLen);
771             } else if(preflightLen!=expectedLen) {
772                 log_err("uloc_getDisplayName(%s, %s...) returned preflight length %d, expected length %d",
773                         locale, displayLocale, preflightLen, expectedLen);
774             } else if(u_strncmp(result, expected, len)) {
775                 int32_t cap=len*6+1;  /* worst case + space for trailing null */
776                 char* resultChars=(char*)malloc(cap);
777                 int32_t resultCharsLen=UCharsToEscapedAscii(result, len, resultChars, cap);
778                 if(resultCharsLen<0 || resultCharsLen<cap-1) {
779                     log_err("uloc_getDisplayName(%s, %s...) mismatch", locale, displayLocale);
780                 } else {
781                     log_err("uloc_getDisplayName(%s, %s...) returned '%s' but expected '%s'",
782                             locale, displayLocale, resultChars, expectedChars);
783                 }
784                 free(resultChars);
785                 resultChars=NULL;
786             } else {
787                 /* test all buffer sizes */
788                 for(i=len+1;i>=0;--i) {
789                     len=uloc_getDisplayName(locale, displayLocale, result, i, &ec);
790                     if(ec==U_BUFFER_OVERFLOW_ERROR) {
791                         ec=U_ZERO_ERROR;
792                     }
793                     if(U_FAILURE(ec)) {
794                         log_err("using buffer of length %d returned error %s", i, u_errorName(ec));
795                         break;
796                     }
797                     if(len!=expectedLen) {
798                         log_err("with buffer of length %d, expected length %d but got %d", i, expectedLen, len);
799                         break;
800                     }
801                     /* There's no guarantee about what's in the buffer if we've overflowed, in particular,
802                      * we don't know that it's been filled, so no point in checking. */
803                 }
804             }
805 
806             free(expected);
807         }
808     }
809 }
810 
811 
812 /* test for uloc_getAvialable()  and uloc_countAvilable()*/
TestGetAvailableLocales()813 static void TestGetAvailableLocales()
814 {
815 
816     const char *locList;
817     int32_t locCount,i;
818 
819     log_verbose("Testing the no of avialable locales\n");
820     locCount=uloc_countAvailable();
821     if (locCount == 0)
822         log_data_err("countAvailable() returned an empty list!\n");
823 
824     /* use something sensible w/o hardcoding the count */
825     else if(locCount < 0){
826         log_data_err("countAvailable() returned a wrong value!= %d\n", locCount);
827     }
828     else{
829         log_info("Number of locales returned = %d\n", locCount);
830     }
831     for(i=0;i<locCount;i++){
832         locList=uloc_getAvailable(i);
833 
834         log_verbose(" %s\n", locList);
835     }
836 }
837 
TestGetAvailableLocalesByType()838 static void TestGetAvailableLocalesByType() {
839     UErrorCode status = U_ZERO_ERROR;
840 
841     UEnumeration* uenum = uloc_openAvailableByType(ULOC_AVAILABLE_DEFAULT, &status);
842     assertSuccess("Constructing the UEnumeration", &status);
843 
844     assertIntEquals("countAvailable() should be same in old and new methods",
845         uloc_countAvailable(),
846         uenum_count(uenum, &status));
847 
848     for (int32_t i = 0; i < uloc_countAvailable(); i++) {
849         const char* old = uloc_getAvailable(i);
850         int32_t len = 0;
851         const char* new = uenum_next(uenum, &len, &status);
852         assertEquals("Old and new strings should equal", old, new);
853         assertIntEquals("String length should be correct", uprv_strlen(old), len);
854     }
855     assertPtrEquals("Should get nullptr on the last string",
856         NULL, uenum_next(uenum, NULL, &status));
857 
858     uenum_close(uenum);
859 
860     uenum = uloc_openAvailableByType(ULOC_AVAILABLE_ONLY_LEGACY_ALIASES, &status);
861     UBool found_he = FALSE;
862     UBool found_iw = FALSE;
863     const char* loc;
864     while ((loc = uenum_next(uenum, NULL, &status))) {
865         if (uprv_strcmp("he", loc) == 0) {
866             found_he = TRUE;
867         }
868         if (uprv_strcmp("iw", loc) == 0) {
869             found_iw = TRUE;
870         }
871     }
872     assertTrue("Should NOT have found he amongst the legacy/alias locales", !found_he);
873     assertTrue("Should have found iw amongst the legacy/alias locales", found_iw);
874     uenum_close(uenum);
875 
876     uenum = uloc_openAvailableByType(ULOC_AVAILABLE_WITH_LEGACY_ALIASES, &status);
877     found_he = FALSE;
878     found_iw = FALSE;
879     const UChar* uloc; // test the UChar conversion
880     int32_t count = 0;
881     while ((uloc = uenum_unext(uenum, NULL, &status))) {
882         if (u_strcmp(u"iw", uloc) == 0) {
883             found_iw = TRUE;
884         }
885         if (u_strcmp(u"he", uloc) == 0) {
886             found_he = TRUE;
887         }
888         count++;
889     }
890     assertTrue("Should have found he amongst all locales", found_he);
891     assertTrue("Should have found iw amongst all locales", found_iw);
892     assertIntEquals("Should return as many strings as claimed",
893         count, uenum_count(uenum, &status));
894 
895     // Reset the enumeration and it should still work
896     uenum_reset(uenum, &status);
897     count = 0;
898     while ((loc = uenum_next(uenum, NULL, &status))) {
899         count++;
900     }
901     assertIntEquals("After reset, should return as many strings as claimed",
902         count, uenum_count(uenum, &status));
903 
904     uenum_close(uenum);
905 
906     assertSuccess("No errors should have occurred", &status);
907 }
908 
909 /* test for u_getDataDirectory, u_setDataDirectory, uloc_getISO3Language */
TestDataDirectory()910 static void TestDataDirectory()
911 {
912 
913     char            oldDirectory[512];
914     const char     *temp,*testValue1,*testValue2,*testValue3;
915     const char path[40] ="d:\\icu\\source\\test\\intltest" U_FILE_SEP_STRING; /*give the required path */
916 
917     log_verbose("Testing getDataDirectory()\n");
918     temp = u_getDataDirectory();
919     strcpy(oldDirectory, temp);
920 
921     testValue1=uloc_getISO3Language("en_US");
922     log_verbose("first fetch of language retrieved  %s\n", testValue1);
923 
924     if (0 != strcmp(testValue1,"eng")){
925         log_err("Initial check of ISO3 language failed: expected \"eng\", got  %s \n", testValue1);
926     }
927 
928     /*defining the path for DataDirectory */
929     log_verbose("Testing setDataDirectory\n");
930     u_setDataDirectory( path );
931     if(strcmp(path, u_getDataDirectory())==0)
932         log_verbose("setDataDirectory working fine\n");
933     else
934         log_err("Error in setDataDirectory. Directory not set correctly - came back as [%s], expected [%s]\n", u_getDataDirectory(), path);
935 
936     testValue2=uloc_getISO3Language("en_US");
937     log_verbose("second fetch of language retrieved  %s \n", testValue2);
938 
939     u_setDataDirectory(oldDirectory);
940     testValue3=uloc_getISO3Language("en_US");
941     log_verbose("third fetch of language retrieved  %s \n", testValue3);
942 
943     if (0 != strcmp(testValue3,"eng")) {
944        log_err("get/setDataDirectory() failed: expected \"eng\", got \" %s  \" \n", testValue3);
945     }
946 }
947 
948 
949 
950 /*=========================================================== */
951 
952 static UChar _NUL=0;
953 
doTestDisplayNames(const char * displayLocale,int32_t compareIndex)954 static void doTestDisplayNames(const char* displayLocale, int32_t compareIndex)
955 {
956     UErrorCode status = U_ZERO_ERROR;
957     int32_t i;
958     int32_t maxresultsize;
959 
960     const char *testLocale;
961 
962 
963     UChar  *testLang  = 0;
964     UChar  *testScript  = 0;
965     UChar  *testCtry = 0;
966     UChar  *testVar = 0;
967     UChar  *testName = 0;
968 
969 
970     UChar*  expectedLang = 0;
971     UChar*  expectedScript = 0;
972     UChar*  expectedCtry = 0;
973     UChar*  expectedVar = 0;
974     UChar*  expectedName = 0;
975 
976 setUpDataTable();
977 
978     for(i=0;i<LOCALE_SIZE; ++i)
979     {
980         testLocale=rawData2[NAME][i];
981 
982         log_verbose("Testing.....  %s\n", testLocale);
983 
984         maxresultsize=0;
985         maxresultsize=uloc_getDisplayLanguage(testLocale, displayLocale, NULL, maxresultsize, &status);
986         if(status==U_BUFFER_OVERFLOW_ERROR)
987         {
988             status=U_ZERO_ERROR;
989             testLang=(UChar*)malloc(sizeof(UChar) * (maxresultsize+1));
990             uloc_getDisplayLanguage(testLocale, displayLocale, testLang, maxresultsize + 1, &status);
991         }
992         else
993         {
994             testLang=&_NUL;
995         }
996         if(U_FAILURE(status)){
997             log_err("Error in getDisplayLanguage()  %s\n", myErrorName(status));
998         }
999 
1000         maxresultsize=0;
1001         maxresultsize=uloc_getDisplayScript(testLocale, displayLocale, NULL, maxresultsize, &status);
1002         if(status==U_BUFFER_OVERFLOW_ERROR)
1003         {
1004             status=U_ZERO_ERROR;
1005             testScript=(UChar*)malloc(sizeof(UChar) * (maxresultsize+1));
1006             uloc_getDisplayScript(testLocale, displayLocale, testScript, maxresultsize + 1, &status);
1007         }
1008         else
1009         {
1010             testScript=&_NUL;
1011         }
1012         if(U_FAILURE(status)){
1013             log_err("Error in getDisplayScript()  %s\n", myErrorName(status));
1014         }
1015 
1016         maxresultsize=0;
1017         maxresultsize=uloc_getDisplayCountry(testLocale, displayLocale, NULL, maxresultsize, &status);
1018         if(status==U_BUFFER_OVERFLOW_ERROR)
1019         {
1020             status=U_ZERO_ERROR;
1021             testCtry=(UChar*)malloc(sizeof(UChar) * (maxresultsize+1));
1022             uloc_getDisplayCountry(testLocale, displayLocale, testCtry, maxresultsize + 1, &status);
1023         }
1024         else
1025         {
1026             testCtry=&_NUL;
1027         }
1028         if(U_FAILURE(status)){
1029             log_err("Error in getDisplayCountry()  %s\n", myErrorName(status));
1030         }
1031 
1032         maxresultsize=0;
1033         maxresultsize=uloc_getDisplayVariant(testLocale, displayLocale, NULL, maxresultsize, &status);
1034         if(status==U_BUFFER_OVERFLOW_ERROR)
1035         {
1036             status=U_ZERO_ERROR;
1037             testVar=(UChar*)malloc(sizeof(UChar) * (maxresultsize+1));
1038             uloc_getDisplayVariant(testLocale, displayLocale, testVar, maxresultsize + 1, &status);
1039         }
1040         else
1041         {
1042             testVar=&_NUL;
1043         }
1044         if(U_FAILURE(status)){
1045                 log_err("Error in getDisplayVariant()  %s\n", myErrorName(status));
1046         }
1047 
1048         maxresultsize=0;
1049         maxresultsize=uloc_getDisplayName(testLocale, displayLocale, NULL, maxresultsize, &status);
1050         if(status==U_BUFFER_OVERFLOW_ERROR)
1051         {
1052             status=U_ZERO_ERROR;
1053             testName=(UChar*)malloc(sizeof(UChar) * (maxresultsize+1));
1054             uloc_getDisplayName(testLocale, displayLocale, testName, maxresultsize + 1, &status);
1055         }
1056         else
1057         {
1058             testName=&_NUL;
1059         }
1060         if(U_FAILURE(status)){
1061             log_err("Error in getDisplayName()  %s\n", myErrorName(status));
1062         }
1063 
1064         expectedLang=dataTable[compareIndex][i];
1065         if(u_strlen(expectedLang)== 0)
1066             expectedLang=dataTable[DLANG_EN][i];
1067 
1068         expectedScript=dataTable[compareIndex + 1][i];
1069         if(u_strlen(expectedScript)== 0)
1070             expectedScript=dataTable[DSCRIPT_EN][i];
1071 
1072         expectedCtry=dataTable[compareIndex + 2][i];
1073         if(u_strlen(expectedCtry)== 0)
1074             expectedCtry=dataTable[DCTRY_EN][i];
1075 
1076         expectedVar=dataTable[compareIndex + 3][i];
1077         if(u_strlen(expectedVar)== 0)
1078             expectedVar=dataTable[DVAR_EN][i];
1079 
1080         expectedName=dataTable[compareIndex + 4][i];
1081         if(u_strlen(expectedName) == 0)
1082             expectedName=dataTable[DNAME_EN][i];
1083 
1084         if (0 !=u_strcmp(testLang,expectedLang))  {
1085             log_data_err(" Display Language mismatch: got %s expected %s displayLocale=%s (Are you missing data?)\n", austrdup(testLang), austrdup(expectedLang), displayLocale);
1086         }
1087 
1088         if (0 != u_strcmp(testScript,expectedScript))   {
1089             log_data_err(" Display Script mismatch: got %s expected %s displayLocale=%s (Are you missing data?)\n", austrdup(testScript), austrdup(expectedScript), displayLocale);
1090         }
1091 
1092         if (0 != u_strcmp(testCtry,expectedCtry))   {
1093             log_data_err(" Display Country mismatch: got %s expected %s displayLocale=%s (Are you missing data?)\n", austrdup(testCtry), austrdup(expectedCtry), displayLocale);
1094         }
1095 
1096         if (0 != u_strcmp(testVar,expectedVar))    {
1097             log_data_err(" Display Variant mismatch: got %s expected %s displayLocale=%s (Are you missing data?)\n", austrdup(testVar), austrdup(expectedVar), displayLocale);
1098         }
1099 
1100         if(0 != u_strcmp(testName, expectedName))    {
1101             log_data_err(" Display Name mismatch: got %s expected %s displayLocale=%s (Are you missing data?)\n", austrdup(testName), austrdup(expectedName), displayLocale);
1102         }
1103 
1104         if(testName!=&_NUL) {
1105             free(testName);
1106         }
1107         if(testLang!=&_NUL) {
1108             free(testLang);
1109         }
1110         if(testScript!=&_NUL) {
1111             free(testScript);
1112         }
1113         if(testCtry!=&_NUL) {
1114             free(testCtry);
1115         }
1116         if(testVar!=&_NUL) {
1117             free(testVar);
1118         }
1119     }
1120 cleanUpDataTable();
1121 }
1122 
1123 /*------------------------------
1124  * TestDisplayNameBrackets
1125  */
1126 
1127 typedef struct {
1128     const char * displayLocale;
1129     const char * namedRegion;
1130     const char * namedLocale;
1131     const char * regionName;
1132     const char * localeName;
1133 } DisplayNameBracketsItem;
1134 
1135 static const DisplayNameBracketsItem displayNameBracketsItems[] = {
1136     { "en", "CC", "en_CC",      "Cocos (Keeling) Islands",  "English (Cocos [Keeling] Islands)"  },
1137     { "en", "MM", "my_MM",      "Myanmar (Burma)",          "Burmese (Myanmar [Burma])"          },
1138     { "en", "MM", "my_Mymr_MM", "Myanmar (Burma)",          "Burmese (Myanmar, Myanmar [Burma])" },
1139     { "zh", "CC", "en_CC",      "\\u79D1\\u79D1\\u65AF\\uFF08\\u57FA\\u6797\\uFF09\\u7FA4\\u5C9B", "\\u82F1\\u8BED\\uFF08\\u79D1\\u79D1\\u65AF\\uFF3B\\u57FA\\u6797\\uFF3D\\u7FA4\\u5C9B\\uFF09" },
1140     { "zh", "CG", "fr_CG",      "\\u521A\\u679C\\uFF08\\u5E03\\uFF09",                             "\\u6CD5\\u8BED\\uFF08\\u521A\\u679C\\uFF3B\\u5E03\\uFF3D\\uFF09" },
1141     { NULL, NULL, NULL,         NULL,                       NULL                                 }
1142 };
1143 
1144 enum { kDisplayNameBracketsMax = 128 };
1145 
TestDisplayNameBrackets()1146 static void TestDisplayNameBrackets()
1147 {
1148     const DisplayNameBracketsItem * itemPtr = displayNameBracketsItems;
1149     for (; itemPtr->displayLocale != NULL; itemPtr++) {
1150         ULocaleDisplayNames * uldn;
1151         UErrorCode status;
1152         UChar expectRegionName[kDisplayNameBracketsMax];
1153         UChar expectLocaleName[kDisplayNameBracketsMax];
1154         UChar getName[kDisplayNameBracketsMax];
1155         int32_t ulen;
1156 
1157         (void) u_unescape(itemPtr->regionName, expectRegionName, kDisplayNameBracketsMax);
1158         (void) u_unescape(itemPtr->localeName, expectLocaleName, kDisplayNameBracketsMax);
1159 
1160         status = U_ZERO_ERROR;
1161         ulen = uloc_getDisplayCountry(itemPtr->namedLocale, itemPtr->displayLocale, getName, kDisplayNameBracketsMax, &status);
1162         if ( U_FAILURE(status) || u_strcmp(getName, expectRegionName) != 0 ) {
1163             log_data_err("uloc_getDisplayCountry for displayLocale %s and namedLocale %s returns unexpected name or status %s\n", itemPtr->displayLocale, itemPtr->namedLocale, myErrorName(status));
1164         }
1165 
1166         status = U_ZERO_ERROR;
1167         ulen = uloc_getDisplayName(itemPtr->namedLocale, itemPtr->displayLocale, getName, kDisplayNameBracketsMax, &status);
1168         if ( U_FAILURE(status) || u_strcmp(getName, expectLocaleName) != 0 ) {
1169             log_data_err("uloc_getDisplayName for displayLocale %s and namedLocale %s returns unexpected name or status %s\n", itemPtr->displayLocale, itemPtr->namedLocale, myErrorName(status));
1170         }
1171 
1172 #if !UCONFIG_NO_FORMATTING
1173         status = U_ZERO_ERROR;
1174         uldn = uldn_open(itemPtr->displayLocale, ULDN_STANDARD_NAMES, &status);
1175         if (U_SUCCESS(status)) {
1176             status = U_ZERO_ERROR;
1177             ulen = uldn_regionDisplayName(uldn, itemPtr->namedRegion, getName, kDisplayNameBracketsMax, &status);
1178             if ( U_FAILURE(status) || u_strcmp(getName, expectRegionName) != 0 ) {
1179                 log_data_err("uldn_regionDisplayName for displayLocale %s and namedRegion %s returns unexpected name or status %s\n", itemPtr->displayLocale, itemPtr->namedRegion, myErrorName(status));
1180             }
1181 
1182             status = U_ZERO_ERROR;
1183             ulen = uldn_localeDisplayName(uldn, itemPtr->namedLocale, getName, kDisplayNameBracketsMax, &status);
1184             if ( U_FAILURE(status) || u_strcmp(getName, expectLocaleName) != 0 ) {
1185                 log_data_err("uldn_localeDisplayName for displayLocale %s and namedLocale %s returns unexpected name or status %s\n", itemPtr->displayLocale, itemPtr->namedLocale, myErrorName(status));
1186             }
1187 
1188             uldn_close(uldn);
1189         } else {
1190             log_data_err("uldn_open fails for displayLocale %s, status=%s\n", itemPtr->displayLocale, u_errorName(status));
1191         }
1192 #endif
1193     (void)ulen;   /* Suppress variable not used warning */
1194     }
1195 }
1196 
1197 /*------------------------------
1198  * TestISOFunctions
1199  */
1200 
1201 #if !UCONFIG_NO_FILE_IO && !UCONFIG_NO_LEGACY_CONVERSION
1202 /* test for uloc_getISOLanguages, uloc_getISOCountries */
TestISOFunctions()1203 static void TestISOFunctions()
1204 {
1205     const char* const* str=uloc_getISOLanguages();
1206     const char* const* str1=uloc_getISOCountries();
1207     const char* test;
1208     const char *key = NULL;
1209     int32_t count = 0, skipped = 0;
1210     int32_t expect;
1211     UResourceBundle *res;
1212     UResourceBundle *subRes;
1213     UErrorCode status = U_ZERO_ERROR;
1214 
1215     /*  test getISOLanguages*/
1216     /*str=uloc_getISOLanguages(); */
1217     log_verbose("Testing ISO Languages: \n");
1218 
1219     /* use structLocale - this data is no longer in root */
1220     res = ures_openDirect(loadTestData(&status), "structLocale", &status);
1221     subRes = ures_getByKey(res, "Languages", NULL, &status);
1222     if (U_FAILURE(status)) {
1223         log_data_err("There is an error in structLocale's ures_getByKey(\"Languages\"), status=%s\n", u_errorName(status));
1224         return;
1225     }
1226 
1227     expect = ures_getSize(subRes);
1228     for(count = 0; *(str+count) != 0; count++)
1229     {
1230         key = NULL;
1231         test = *(str+count);
1232         status = U_ZERO_ERROR;
1233 
1234         do {
1235             /* Skip over language tags. This API only returns language codes. */
1236             skipped += (key != NULL);
1237             ures_getNextString(subRes, NULL, &key, &status);
1238         }
1239         while (key != NULL && strchr(key, '_'));
1240 
1241         if(key == NULL)
1242             break;
1243         /* TODO: Consider removing sh, which is deprecated */
1244         if(strcmp(key,"root") == 0 || strcmp(key,"Fallback") == 0 || strcmp(key,"sh") == 0) {
1245             ures_getNextString(subRes, NULL, &key, &status);
1246             skipped++;
1247         }
1248 #if U_CHARSET_FAMILY==U_ASCII_FAMILY
1249         /* This code only works on ASCII machines where the keys are stored in ASCII order */
1250         if(strcmp(test,key)) {
1251             /* The first difference usually implies the place where things get out of sync */
1252             log_err("FAIL Language diff at offset %d, \"%s\" != \"%s\"\n", count, test, key);
1253         }
1254 #endif
1255 
1256         if(!strcmp(test,"in"))
1257             log_err("FAIL getISOLanguages() has obsolete language code %s\n", test);
1258         if(!strcmp(test,"iw"))
1259             log_err("FAIL getISOLanguages() has obsolete language code %s\n", test);
1260         if(!strcmp(test,"ji"))
1261             log_err("FAIL getISOLanguages() has obsolete language code %s\n", test);
1262         if(!strcmp(test,"jw"))
1263             log_err("FAIL getISOLanguages() has obsolete language code %s\n", test);
1264         if(!strcmp(test,"sh"))
1265             log_err("FAIL getISOLanguages() has obsolete language code %s\n", test);
1266     }
1267 
1268     expect -= skipped; /* Ignore the skipped resources from structLocale */
1269 
1270     if(count!=expect) {
1271         log_err("There is an error in getISOLanguages, got %d, expected %d (as per structLocale)\n", count, expect);
1272     }
1273 
1274     subRes = ures_getByKey(res, "Countries", subRes, &status);
1275     log_verbose("Testing ISO Countries");
1276     skipped = 0;
1277     expect = ures_getSize(subRes) - 1; /* Skip ZZ */
1278     for(count = 0; *(str1+count) != 0; count++)
1279     {
1280         key = NULL;
1281         test = *(str1+count);
1282         do {
1283             /* Skip over numeric UN tags. This API only returns ISO-3166 codes. */
1284             skipped += (key != NULL);
1285             ures_getNextString(subRes, NULL, &key, &status);
1286         }
1287         while (key != NULL && strlen(key) != 2);
1288 
1289         if(key == NULL)
1290             break;
1291         /* TODO: Consider removing CS, which is deprecated */
1292         while(strcmp(key,"QO") == 0 || strcmp(key,"QU") == 0 || strcmp(key,"CS") == 0) {
1293             ures_getNextString(subRes, NULL, &key, &status);
1294             skipped++;
1295         }
1296 #if U_CHARSET_FAMILY==U_ASCII_FAMILY
1297         /* This code only works on ASCII machines where the keys are stored in ASCII order */
1298         if(strcmp(test,key)) {
1299             /* The first difference usually implies the place where things get out of sync */
1300             log_err("FAIL Country diff at offset %d, \"%s\" != \"%s\"\n", count, test, key);
1301         }
1302 #endif
1303         if(!strcmp(test,"FX"))
1304             log_err("FAIL getISOCountries() has obsolete country code %s\n", test);
1305         if(!strcmp(test,"YU"))
1306             log_err("FAIL getISOCountries() has obsolete country code %s\n", test);
1307         if(!strcmp(test,"ZR"))
1308             log_err("FAIL getISOCountries() has obsolete country code %s\n", test);
1309     }
1310 
1311     ures_getNextString(subRes, NULL, &key, &status);
1312     if (strcmp(key, "ZZ") != 0) {
1313         log_err("ZZ was expected to be the last entry in structLocale, but got %s\n", key);
1314     }
1315 #if U_CHARSET_FAMILY==U_EBCDIC_FAMILY
1316     /* On EBCDIC machines, the numbers are sorted last. Account for those in the skipped value too. */
1317     key = NULL;
1318     do {
1319         /* Skip over numeric UN tags. uloc_getISOCountries only returns ISO-3166 codes. */
1320         skipped += (key != NULL);
1321         ures_getNextString(subRes, NULL, &key, &status);
1322     }
1323     while (U_SUCCESS(status) && key != NULL && strlen(key) != 2);
1324 #endif
1325     expect -= skipped; /* Ignore the skipped resources from structLocale */
1326     if(count!=expect)
1327     {
1328         log_err("There is an error in getISOCountries, got %d, expected %d \n", count, expect);
1329     }
1330     ures_close(subRes);
1331     ures_close(res);
1332 }
1333 #endif
1334 
setUpDataTable()1335 static void setUpDataTable()
1336 {
1337     int32_t i,j;
1338     dataTable = (UChar***)(calloc(sizeof(UChar**),LOCALE_INFO_SIZE));
1339 
1340     for (i = 0; i < LOCALE_INFO_SIZE; i++) {
1341         dataTable[i] = (UChar**)(calloc(sizeof(UChar*),LOCALE_SIZE));
1342         for (j = 0; j < LOCALE_SIZE; j++){
1343             dataTable[i][j] = CharsToUChars(rawData2[i][j]);
1344         }
1345     }
1346 }
1347 
cleanUpDataTable()1348 static void cleanUpDataTable()
1349 {
1350     int32_t i,j;
1351     if(dataTable != NULL) {
1352         for (i=0; i<LOCALE_INFO_SIZE; i++) {
1353             for(j = 0; j < LOCALE_SIZE; j++) {
1354                 free(dataTable[i][j]);
1355             }
1356             free(dataTable[i]);
1357         }
1358         free(dataTable);
1359     }
1360     dataTable = NULL;
1361 }
1362 
1363 /**
1364  * @bug 4011756 4011380
1365  */
TestISO3Fallback()1366 static void TestISO3Fallback()
1367 {
1368     const char* test="xx_YY";
1369 
1370     const char * result;
1371 
1372     result = uloc_getISO3Language(test);
1373 
1374     /* Conform to C API usage  */
1375 
1376     if (!result || (result[0] != 0))
1377        log_err("getISO3Language() on xx_YY returned %s instead of \"\"");
1378 
1379     result = uloc_getISO3Country(test);
1380 
1381     if (!result || (result[0] != 0))
1382         log_err("getISO3Country() on xx_YY returned %s instead of \"\"");
1383 }
1384 
1385 /**
1386  * @bug 4118587
1387  */
TestSimpleDisplayNames()1388 static void TestSimpleDisplayNames()
1389 {
1390   /*
1391      This test is different from TestDisplayNames because TestDisplayNames checks
1392      fallback behavior, combination of language and country names to form locale
1393      names, and other stuff like that.  This test just checks specific language
1394      and country codes to make sure we have the correct names for them.
1395   */
1396     char languageCodes[] [4] = { "he", "id", "iu", "ug", "yi", "za", "419" };
1397     const char* languageNames [] = { "Hebrew", "Indonesian", "Inuktitut", "Uyghur", "Yiddish",
1398                                "Zhuang", "419" };
1399     const char* inLocale [] = { "en_US", "zh_Hant"};
1400     UErrorCode status=U_ZERO_ERROR;
1401 
1402     int32_t i;
1403     int32_t localeIndex = 0;
1404     for (i = 0; i < 7; i++) {
1405         UChar *testLang=0;
1406         UChar *expectedLang=0;
1407         int size=0;
1408 
1409         if (i == 6) {
1410             localeIndex = 1; /* Use the second locale for the rest of the test. */
1411         }
1412 
1413         size=uloc_getDisplayLanguage(languageCodes[i], inLocale[localeIndex], NULL, size, &status);
1414         if(status==U_BUFFER_OVERFLOW_ERROR) {
1415             status=U_ZERO_ERROR;
1416             testLang=(UChar*)malloc(sizeof(UChar) * (size + 1));
1417             uloc_getDisplayLanguage(languageCodes[i], inLocale[localeIndex], testLang, size + 1, &status);
1418         }
1419         expectedLang=(UChar*)malloc(sizeof(UChar) * (strlen(languageNames[i])+1));
1420         u_uastrcpy(expectedLang, languageNames[i]);
1421         if (u_strcmp(testLang, expectedLang) != 0)
1422             log_data_err("Got wrong display name for %s : Expected \"%s\", got \"%s\".\n",
1423                     languageCodes[i], languageNames[i], austrdup(testLang));
1424         free(testLang);
1425         free(expectedLang);
1426     }
1427 
1428 }
1429 
1430 /**
1431  * @bug 4118595
1432  */
TestUninstalledISO3Names()1433 static void TestUninstalledISO3Names()
1434 {
1435   /* This test checks to make sure getISO3Language and getISO3Country work right
1436      even for locales that are not installed. */
1437     static const char iso2Languages [][4] = {     "am", "ba", "fy", "mr", "rn",
1438                                         "ss", "tw", "zu" };
1439     static const char iso3Languages [][5] = {     "amh", "bak", "fry", "mar", "run",
1440                                         "ssw", "twi", "zul" };
1441     static const char iso2Countries [][6] = {     "am_AF", "ba_BW", "fy_KZ", "mr_MO", "rn_MN",
1442                                         "ss_SB", "tw_TC", "zu_ZW" };
1443     static const char iso3Countries [][4] = {     "AFG", "BWA", "KAZ", "MAC", "MNG",
1444                                         "SLB", "TCA", "ZWE" };
1445     int32_t i;
1446 
1447     for (i = 0; i < 8; i++) {
1448       UErrorCode err = U_ZERO_ERROR;
1449       const char *test;
1450       test = uloc_getISO3Language(iso2Languages[i]);
1451       if(strcmp(test, iso3Languages[i]) !=0 || U_FAILURE(err))
1452          log_err("Got wrong ISO3 code for %s : Expected \"%s\", got \"%s\". %s\n",
1453                      iso2Languages[i], iso3Languages[i], test, myErrorName(err));
1454     }
1455     for (i = 0; i < 8; i++) {
1456       UErrorCode err = U_ZERO_ERROR;
1457       const char *test;
1458       test = uloc_getISO3Country(iso2Countries[i]);
1459       if(strcmp(test, iso3Countries[i]) !=0 || U_FAILURE(err))
1460          log_err("Got wrong ISO3 code for %s : Expected \"%s\", got \"%s\". %s\n",
1461                      iso2Countries[i], iso3Countries[i], test, myErrorName(err));
1462     }
1463 }
1464 
1465 
TestVariantParsing()1466 static void TestVariantParsing()
1467 {
1468     static const char* en_US_custom="en_US_De Anza_Cupertino_California_United States_Earth";
1469     static const char* dispName="English (United States, DE ANZA_CUPERTINO_CALIFORNIA_UNITED STATES_EARTH)";
1470     static const char* dispVar="DE ANZA_CUPERTINO_CALIFORNIA_UNITED STATES_EARTH";
1471     static const char* shortVariant="fr_FR_foo";
1472     static const char* bogusVariant="fr_FR__foo";
1473     static const char* bogusVariant2="fr_FR_foo_";
1474     static const char* bogusVariant3="fr_FR__foo_";
1475 
1476 
1477     UChar displayVar[100];
1478     UChar displayName[100];
1479     UErrorCode status=U_ZERO_ERROR;
1480     UChar* got=0;
1481     int32_t size=0;
1482     size=uloc_getDisplayVariant(en_US_custom, "en_US", NULL, size, &status);
1483     if(status==U_BUFFER_OVERFLOW_ERROR) {
1484         status=U_ZERO_ERROR;
1485         got=(UChar*)realloc(got, sizeof(UChar) * (size+1));
1486         uloc_getDisplayVariant(en_US_custom, "en_US", got, size + 1, &status);
1487     }
1488     else {
1489         log_err("FAIL: Didn't get U_BUFFER_OVERFLOW_ERROR\n");
1490     }
1491     u_uastrcpy(displayVar, dispVar);
1492     if(u_strcmp(got,displayVar)!=0) {
1493         log_err("FAIL: getDisplayVariant() Wanted %s, got %s\n", dispVar, austrdup(got));
1494     }
1495     size=0;
1496     size=uloc_getDisplayName(en_US_custom, "en_US", NULL, size, &status);
1497     if(status==U_BUFFER_OVERFLOW_ERROR) {
1498         status=U_ZERO_ERROR;
1499         got=(UChar*)realloc(got, sizeof(UChar) * (size+1));
1500         uloc_getDisplayName(en_US_custom, "en_US", got, size + 1, &status);
1501     }
1502     else {
1503         log_err("FAIL: Didn't get U_BUFFER_OVERFLOW_ERROR\n");
1504     }
1505     u_uastrcpy(displayName, dispName);
1506     if(u_strcmp(got,displayName)!=0) {
1507         if (status == U_USING_DEFAULT_WARNING) {
1508             log_data_err("FAIL: getDisplayName() got %s. Perhaps you are missing data?\n", u_errorName(status));
1509         } else {
1510             log_err("FAIL: getDisplayName() Wanted %s, got %s\n", dispName, austrdup(got));
1511         }
1512     }
1513 
1514     size=0;
1515     status=U_ZERO_ERROR;
1516     size=uloc_getDisplayVariant(shortVariant, NULL, NULL, size, &status);
1517     if(status==U_BUFFER_OVERFLOW_ERROR) {
1518         status=U_ZERO_ERROR;
1519         got=(UChar*)realloc(got, sizeof(UChar) * (size+1));
1520         uloc_getDisplayVariant(shortVariant, NULL, got, size + 1, &status);
1521     }
1522     else {
1523         log_err("FAIL: Didn't get U_BUFFER_OVERFLOW_ERROR\n");
1524     }
1525     if(strcmp(austrdup(got),"FOO")!=0) {
1526         log_err("FAIL: getDisplayVariant()  Wanted: foo  Got: %s\n", austrdup(got));
1527     }
1528     size=0;
1529     status=U_ZERO_ERROR;
1530     size=uloc_getDisplayVariant(bogusVariant, NULL, NULL, size, &status);
1531     if(status==U_BUFFER_OVERFLOW_ERROR) {
1532         status=U_ZERO_ERROR;
1533         got=(UChar*)realloc(got, sizeof(UChar) * (size+1));
1534         uloc_getDisplayVariant(bogusVariant, NULL, got, size + 1, &status);
1535     }
1536     else {
1537         log_err("FAIL: Didn't get U_BUFFER_OVERFLOW_ERROR\n");
1538     }
1539     if(strcmp(austrdup(got),"_FOO")!=0) {
1540         log_err("FAIL: getDisplayVariant()  Wanted: _FOO  Got: %s\n", austrdup(got));
1541     }
1542     size=0;
1543     status=U_ZERO_ERROR;
1544     size=uloc_getDisplayVariant(bogusVariant2, NULL, NULL, size, &status);
1545     if(status==U_BUFFER_OVERFLOW_ERROR) {
1546         status=U_ZERO_ERROR;
1547         got=(UChar*)realloc(got, sizeof(UChar) * (size+1));
1548         uloc_getDisplayVariant(bogusVariant2, NULL, got, size + 1, &status);
1549     }
1550     else {
1551         log_err("FAIL: Didn't get U_BUFFER_OVERFLOW_ERROR\n");
1552     }
1553     if(strcmp(austrdup(got),"FOO_")!=0) {
1554         log_err("FAIL: getDisplayVariant()  Wanted: FOO_  Got: %s\n", austrdup(got));
1555     }
1556     size=0;
1557     status=U_ZERO_ERROR;
1558     size=uloc_getDisplayVariant(bogusVariant3, NULL, NULL, size, &status);
1559     if(status==U_BUFFER_OVERFLOW_ERROR) {
1560         status=U_ZERO_ERROR;
1561         got=(UChar*)realloc(got, sizeof(UChar) * (size+1));
1562         uloc_getDisplayVariant(bogusVariant3, NULL, got, size + 1, &status);
1563     }
1564     else {
1565         log_err("FAIL: Didn't get U_BUFFER_OVERFLOW_ERROR\n");
1566     }
1567     if(strcmp(austrdup(got),"_FOO_")!=0) {
1568         log_err("FAIL: getDisplayVariant()  Wanted: _FOO_  Got: %s\n", austrdup(got));
1569     }
1570     free(got);
1571 }
1572 
1573 
TestObsoleteNames(void)1574 static void TestObsoleteNames(void)
1575 {
1576     int32_t i;
1577     UErrorCode status = U_ZERO_ERROR;
1578     char buff[256];
1579 
1580     static const struct
1581     {
1582         char locale[9];
1583         char lang3[4];
1584         char lang[4];
1585         char ctry3[4];
1586         char ctry[4];
1587     } tests[] =
1588     {
1589         { "eng_USA", "eng", "en", "USA", "US" },
1590         { "kok",  "kok", "kok", "", "" },
1591         { "in",  "ind", "in", "", "" },
1592         { "id",  "ind", "id", "", "" }, /* NO aliasing */
1593         { "sh",  "srp", "sh", "", "" },
1594         { "zz_CS",  "", "zz", "SCG", "CS" },
1595         { "zz_FX",  "", "zz", "FXX", "FX" },
1596         { "zz_RO",  "", "zz", "ROU", "RO" },
1597         { "zz_TP",  "", "zz", "TMP", "TP" },
1598         { "zz_TL",  "", "zz", "TLS", "TL" },
1599         { "zz_ZR",  "", "zz", "ZAR", "ZR" },
1600         { "zz_FXX",  "", "zz", "FXX", "FX" }, /* no aliasing. Doesn't go to PS(PSE). */
1601         { "zz_ROM",  "", "zz", "ROU", "RO" },
1602         { "zz_ROU",  "", "zz", "ROU", "RO" },
1603         { "zz_ZAR",  "", "zz", "ZAR", "ZR" },
1604         { "zz_TMP",  "", "zz", "TMP", "TP" },
1605         { "zz_TLS",  "", "zz", "TLS", "TL" },
1606         { "zz_YUG",  "", "zz", "YUG", "YU" },
1607         { "mlt_PSE", "mlt", "mt", "PSE", "PS" },
1608         { "iw", "heb", "iw", "", "" },
1609         { "ji", "yid", "ji", "", "" },
1610         { "jw", "jaw", "jw", "", "" },
1611         { "sh", "srp", "sh", "", "" },
1612         { "", "", "", "", "" }
1613     };
1614 
1615     for(i=0;tests[i].locale[0];i++)
1616     {
1617         const char *locale;
1618 
1619         locale = tests[i].locale;
1620         log_verbose("** %s:\n", locale);
1621 
1622         status = U_ZERO_ERROR;
1623         if(strcmp(tests[i].lang3,uloc_getISO3Language(locale)))
1624         {
1625             log_err("FAIL: uloc_getISO3Language(%s)==\t\"%s\",\t expected \"%s\"\n",
1626                 locale,  uloc_getISO3Language(locale), tests[i].lang3);
1627         }
1628         else
1629         {
1630             log_verbose("   uloc_getISO3Language()==\t\"%s\"\n",
1631                 uloc_getISO3Language(locale) );
1632         }
1633 
1634         status = U_ZERO_ERROR;
1635         uloc_getLanguage(locale, buff, 256, &status);
1636         if(U_FAILURE(status))
1637         {
1638             log_err("FAIL: error getting language from %s\n", locale);
1639         }
1640         else
1641         {
1642             if(strcmp(buff,tests[i].lang))
1643             {
1644                 log_err("FAIL: uloc_getLanguage(%s)==\t\"%s\"\t expected \"%s\"\n",
1645                     locale, buff, tests[i].lang);
1646             }
1647             else
1648             {
1649                 log_verbose("  uloc_getLanguage(%s)==\t%s\n", locale, buff);
1650             }
1651         }
1652         if(strcmp(tests[i].lang3,uloc_getISO3Language(locale)))
1653         {
1654             log_err("FAIL: uloc_getISO3Language(%s)==\t\"%s\",\t expected \"%s\"\n",
1655                 locale,  uloc_getISO3Language(locale), tests[i].lang3);
1656         }
1657         else
1658         {
1659             log_verbose("   uloc_getISO3Language()==\t\"%s\"\n",
1660                 uloc_getISO3Language(locale) );
1661         }
1662 
1663         if(strcmp(tests[i].ctry3,uloc_getISO3Country(locale)))
1664         {
1665             log_err("FAIL: uloc_getISO3Country(%s)==\t\"%s\",\t expected \"%s\"\n",
1666                 locale,  uloc_getISO3Country(locale), tests[i].ctry3);
1667         }
1668         else
1669         {
1670             log_verbose("   uloc_getISO3Country()==\t\"%s\"\n",
1671                 uloc_getISO3Country(locale) );
1672         }
1673 
1674         status = U_ZERO_ERROR;
1675         uloc_getCountry(locale, buff, 256, &status);
1676         if(U_FAILURE(status))
1677         {
1678             log_err("FAIL: error getting country from %s\n", locale);
1679         }
1680         else
1681         {
1682             if(strcmp(buff,tests[i].ctry))
1683             {
1684                 log_err("FAIL: uloc_getCountry(%s)==\t\"%s\"\t expected \"%s\"\n",
1685                     locale, buff, tests[i].ctry);
1686             }
1687             else
1688             {
1689                 log_verbose("  uloc_getCountry(%s)==\t%s\n", locale, buff);
1690             }
1691         }
1692     }
1693 
1694     if (uloc_getLCID("iw_IL") != uloc_getLCID("he_IL")) {
1695         log_err("he,iw LCID mismatch: %X versus %X\n", uloc_getLCID("iw_IL"), uloc_getLCID("he_IL"));
1696     }
1697 
1698     if (uloc_getLCID("iw") != uloc_getLCID("he")) {
1699         log_err("he,iw LCID mismatch: %X versus %X\n", uloc_getLCID("iw"), uloc_getLCID("he"));
1700     }
1701 
1702 #if 0
1703 
1704     i = uloc_getLanguage("kok",NULL,0,&icu_err);
1705     if(U_FAILURE(icu_err))
1706     {
1707         log_err("FAIL: Got %s trying to do uloc_getLanguage(kok)\n", u_errorName(icu_err));
1708     }
1709 
1710     icu_err = U_ZERO_ERROR;
1711     uloc_getLanguage("kok",r1_buff,12,&icu_err);
1712     if(U_FAILURE(icu_err))
1713     {
1714         log_err("FAIL: Got %s trying to do uloc_getLanguage(kok, buff)\n", u_errorName(icu_err));
1715     }
1716 
1717     r1_addr = (char *)uloc_getISO3Language("kok");
1718 
1719     icu_err = U_ZERO_ERROR;
1720     if (strcmp(r1_buff,"kok") != 0)
1721     {
1722         log_err("FAIL: uloc_getLanguage(kok)==%s not kok\n",r1_buff);
1723         line--;
1724     }
1725     r1_addr = (char *)uloc_getISO3Language("in");
1726     i = uloc_getLanguage(r1_addr,r1_buff,12,&icu_err);
1727     if (strcmp(r1_buff,"id") != 0)
1728     {
1729         printf("uloc_getLanguage error (%s)\n",r1_buff);
1730         line--;
1731     }
1732     r1_addr = (char *)uloc_getISO3Language("sh");
1733     i = uloc_getLanguage(r1_addr,r1_buff,12,&icu_err);
1734     if (strcmp(r1_buff,"sr") != 0)
1735     {
1736         printf("uloc_getLanguage error (%s)\n",r1_buff);
1737         line--;
1738     }
1739 
1740     r1_addr = (char *)uloc_getISO3Country("zz_ZR");
1741     strcpy(p1_buff,"zz_");
1742     strcat(p1_buff,r1_addr);
1743     i = uloc_getCountry(p1_buff,r1_buff,12,&icu_err);
1744     if (strcmp(r1_buff,"ZR") != 0)
1745     {
1746         printf("uloc_getCountry error (%s)\n",r1_buff);
1747         line--;
1748     }
1749     r1_addr = (char *)uloc_getISO3Country("zz_FX");
1750     strcpy(p1_buff,"zz_");
1751     strcat(p1_buff,r1_addr);
1752     i = uloc_getCountry(p1_buff,r1_buff,12,&icu_err);
1753     if (strcmp(r1_buff,"FX") != 0)
1754     {
1755         printf("uloc_getCountry error (%s)\n",r1_buff);
1756         line--;
1757     }
1758 
1759 #endif
1760 
1761 }
1762 
TestKeywordVariants(void)1763 static void TestKeywordVariants(void)
1764 {
1765     static const struct {
1766         const char *localeID;
1767         const char *expectedLocaleID;           /* uloc_getName */
1768         const char *expectedLocaleIDNoKeywords; /* uloc_getBaseName */
1769         const char *expectedCanonicalID;        /* uloc_canonicalize */
1770         const char *expectedKeywords[10];
1771         int32_t numKeywords;
1772         UErrorCode expectedStatus; /* from uloc_openKeywords */
1773     } testCases[] = {
1774         {
1775             "de_DE@  currency = euro; C o ll A t i o n   = Phonebook   ; C alen dar = buddhist   ",
1776             "de_DE@calendar=buddhist;collation=Phonebook;currency=euro",
1777             "de_DE",
1778             "de_DE@calendar=buddhist;collation=Phonebook;currency=euro",
1779             {"calendar", "collation", "currency"},
1780             3,
1781             U_ZERO_ERROR
1782         },
1783         {
1784             "de_DE@euro",
1785             "de_DE@euro",
1786             "de_DE@euro",   /* we probably should strip off the POSIX style variant @euro see #11690 */
1787             "de_DE_EURO",
1788             {"","","","","","",""},
1789             0,
1790             U_INVALID_FORMAT_ERROR /* must have '=' after '@' */
1791         },
1792         {
1793             "de_DE@euro;collation=phonebook",   /* The POSIX style variant @euro cannot be combined with key=value? */
1794             "de_DE", /* getName returns de_DE - should be INVALID_FORMAT_ERROR? */
1795             "de_DE", /* getBaseName returns de_DE - should be INVALID_FORMAT_ERROR? see #11690 */
1796             "de_DE", /* canonicalize returns de_DE - should be INVALID_FORMAT_ERROR? */
1797             {"","","","","","",""},
1798             0,
1799             U_INVALID_FORMAT_ERROR
1800         },
1801         {
1802             "de_DE@collation=",
1803             0, /* expected getName to fail */
1804             "de_DE", /* getBaseName returns de_DE - should be INVALID_FORMAT_ERROR? see #11690 */
1805             0, /* expected canonicalize to fail */
1806             {"","","","","","",""},
1807             0,
1808             U_INVALID_FORMAT_ERROR /* must have '=' after '@' */
1809         }
1810     };
1811     UErrorCode status = U_ZERO_ERROR;
1812 
1813     int32_t i = 0, j = 0;
1814     int32_t resultLen = 0;
1815     char buffer[256];
1816     UEnumeration *keywords;
1817     int32_t keyCount = 0;
1818     const char *keyword = NULL;
1819     int32_t keywordLen = 0;
1820 
1821     for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
1822         status = U_ZERO_ERROR;
1823         *buffer = 0;
1824         keywords = uloc_openKeywords(testCases[i].localeID, &status);
1825 
1826         if(status != testCases[i].expectedStatus) {
1827             log_err("Expected to uloc_openKeywords(\"%s\") => status %s. Got %s instead\n",
1828                     testCases[i].localeID,
1829                     u_errorName(testCases[i].expectedStatus), u_errorName(status));
1830         }
1831         status = U_ZERO_ERROR;
1832         if(keywords) {
1833             if((keyCount = uenum_count(keywords, &status)) != testCases[i].numKeywords) {
1834                 log_err("Expected to get %i keywords, got %i\n", testCases[i].numKeywords, keyCount);
1835             }
1836             if(keyCount) {
1837                 j = 0;
1838                 while((keyword = uenum_next(keywords, &keywordLen, &status))) {
1839                     if(strcmp(keyword, testCases[i].expectedKeywords[j]) != 0) {
1840                         log_err("Expected to get keyword value %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
1841                     }
1842                     j++;
1843                 }
1844                 j = 0;
1845                 uenum_reset(keywords, &status);
1846                 while((keyword = uenum_next(keywords, &keywordLen, &status))) {
1847                     if(strcmp(keyword, testCases[i].expectedKeywords[j]) != 0) {
1848                         log_err("Expected to get keyword value %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
1849                     }
1850                     j++;
1851                 }
1852             }
1853             uenum_close(keywords);
1854         }
1855 
1856         status = U_ZERO_ERROR;
1857         resultLen = uloc_getName(testCases[i].localeID, buffer, 256, &status);
1858         (void)resultLen;
1859         U_ASSERT(resultLen < 256);
1860         if (U_SUCCESS(status)) {
1861             if (testCases[i].expectedLocaleID == 0) {
1862                 log_err("Expected uloc_getName(\"%s\") to fail; got \"%s\"\n",
1863                         testCases[i].localeID, buffer);
1864             } else if (uprv_strcmp(testCases[i].expectedLocaleID, buffer) != 0) {
1865                 log_err("Expected uloc_getName(\"%s\") => \"%s\"; got \"%s\"\n",
1866                         testCases[i].localeID, testCases[i].expectedLocaleID, buffer);
1867             }
1868         } else {
1869             if (testCases[i].expectedLocaleID != 0) {
1870                 log_err("Expected uloc_getName(\"%s\") => \"%s\"; but returned error: %s\n",
1871                         testCases[i].localeID, testCases[i].expectedLocaleID, buffer, u_errorName(status));
1872             }
1873         }
1874 
1875         status = U_ZERO_ERROR;
1876         resultLen = uloc_getBaseName(testCases[i].localeID, buffer, 256, &status);
1877         U_ASSERT(resultLen < 256);
1878         if (U_SUCCESS(status)) {
1879             if (testCases[i].expectedLocaleIDNoKeywords == 0) {
1880                 log_err("Expected uloc_getBaseName(\"%s\") to fail; got \"%s\"\n",
1881                         testCases[i].localeID, buffer);
1882             } else if (uprv_strcmp(testCases[i].expectedLocaleIDNoKeywords, buffer) != 0) {
1883                 log_err("Expected uloc_getBaseName(\"%s\") => \"%s\"; got \"%s\"\n",
1884                         testCases[i].localeID, testCases[i].expectedLocaleIDNoKeywords, buffer);
1885             }
1886         } else {
1887             if (testCases[i].expectedLocaleIDNoKeywords != 0) {
1888                 log_err("Expected uloc_getBaseName(\"%s\") => \"%s\"; but returned error: %s\n",
1889                         testCases[i].localeID, testCases[i].expectedLocaleIDNoKeywords, buffer, u_errorName(status));
1890             }
1891         }
1892 
1893         status = U_ZERO_ERROR;
1894         resultLen = uloc_canonicalize(testCases[i].localeID, buffer, 256, &status);
1895         U_ASSERT(resultLen < 256);
1896         if (U_SUCCESS(status)) {
1897             if (testCases[i].expectedCanonicalID == 0) {
1898                 log_err("Expected uloc_canonicalize(\"%s\") to fail; got \"%s\"\n",
1899                         testCases[i].localeID, buffer);
1900             } else if (uprv_strcmp(testCases[i].expectedCanonicalID, buffer) != 0) {
1901                 log_err("Expected uloc_canonicalize(\"%s\") => \"%s\"; got \"%s\"\n",
1902                         testCases[i].localeID, testCases[i].expectedCanonicalID, buffer);
1903             }
1904         } else {
1905             if (testCases[i].expectedCanonicalID != 0) {
1906                 log_err("Expected uloc_canonicalize(\"%s\") => \"%s\"; but returned error: %s\n",
1907                         testCases[i].localeID, testCases[i].expectedCanonicalID, buffer, u_errorName(status));
1908             }
1909         }
1910     }
1911 }
1912 
TestKeywordVariantParsing(void)1913 static void TestKeywordVariantParsing(void)
1914 {
1915     static const struct {
1916         const char *localeID;
1917         const char *keyword;
1918         const char *expectedValue; /* NULL if failure is expected */
1919     } testCases[] = {
1920         { "de_DE@  C o ll A t i o n   = Phonebook   ", "c o ll a t i o n", NULL }, /* malformed key name */
1921         { "de_DE", "collation", ""},
1922         { "de_DE@collation=PHONEBOOK", "collation", "PHONEBOOK" },
1923         { "de_DE@currency = euro; CoLLaTion   = PHONEBOOk", "collatiON", "PHONEBOOk" },
1924     };
1925 
1926     UErrorCode status;
1927     int32_t i = 0;
1928     int32_t resultLen = 0;
1929     char buffer[256];
1930 
1931     for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
1932         *buffer = 0;
1933         status = U_ZERO_ERROR;
1934         resultLen = uloc_getKeywordValue(testCases[i].localeID, testCases[i].keyword, buffer, 256, &status);
1935         (void)resultLen;    /* Suppress set but not used warning. */
1936         if (testCases[i].expectedValue) {
1937             /* expect success */
1938             if (U_FAILURE(status)) {
1939                 log_err("Expected to extract \"%s\" from \"%s\" for keyword \"%s\". Instead got status %s\n",
1940                     testCases[i].expectedValue, testCases[i].localeID, testCases[i].keyword, u_errorName(status));
1941             } else if (uprv_strcmp(testCases[i].expectedValue, buffer) != 0) {
1942                 log_err("Expected to extract \"%s\" from \"%s\" for keyword \"%s\". Instead got \"%s\"\n",
1943                     testCases[i].expectedValue, testCases[i].localeID, testCases[i].keyword, buffer);
1944             }
1945         } else if (U_SUCCESS(status)) {
1946             /* expect failure */
1947             log_err("Expected failure but got success from \"%s\" for keyword \"%s\". Got \"%s\"\n",
1948                 testCases[i].localeID, testCases[i].keyword, buffer);
1949 
1950         }
1951     }
1952 }
1953 
1954 static const struct {
1955   const char *l; /* locale */
1956   const char *k; /* kw */
1957   const char *v; /* value */
1958   const char *x; /* expected */
1959 } kwSetTestCases[] = {
1960 #if 1
1961   { "en_US", "calendar", "japanese", "en_US@calendar=japanese" },
1962   { "en_US@", "calendar", "japanese", "en_US@calendar=japanese" },
1963   { "en_US@calendar=islamic", "calendar", "japanese", "en_US@calendar=japanese" },
1964   { "en_US@calendar=slovakian", "calendar", "gregorian", "en_US@calendar=gregorian" }, /* don't know what this means, but it has the same # of chars as gregorian */
1965   { "en_US@calendar=gregorian", "calendar", "japanese", "en_US@calendar=japanese" },
1966   { "de", "Currency", "CHF", "de@currency=CHF" },
1967   { "de", "Currency", "CHF", "de@currency=CHF" },
1968 
1969   { "en_US@collation=phonebook", "calendar", "japanese", "en_US@calendar=japanese;collation=phonebook" },
1970   { "en_US@calendar=japanese", "collation", "phonebook", "en_US@calendar=japanese;collation=phonebook" },
1971   { "de@collation=phonebook", "Currency", "CHF", "de@collation=phonebook;currency=CHF" },
1972   { "en_US@calendar=gregorian;collation=phonebook", "calendar", "japanese", "en_US@calendar=japanese;collation=phonebook" },
1973   { "en_US@calendar=slovakian;collation=phonebook", "calendar", "gregorian", "en_US@calendar=gregorian;collation=phonebook" }, /* don't know what this means, but it has the same # of chars as gregorian */
1974   { "en_US@calendar=slovakian;collation=videobook", "collation", "phonebook", "en_US@calendar=slovakian;collation=phonebook" }, /* don't know what this means, but it has the same # of chars as gregorian */
1975   { "en_US@calendar=islamic;collation=phonebook", "calendar", "japanese", "en_US@calendar=japanese;collation=phonebook" },
1976   { "de@collation=phonebook", "Currency", "CHF", "de@collation=phonebook;currency=CHF" },
1977 #endif
1978 #if 1
1979   { "mt@a=0;b=1;c=2;d=3", "c","j", "mt@a=0;b=1;c=j;d=3" },
1980   { "mt@a=0;b=1;c=2;d=3", "x","j", "mt@a=0;b=1;c=2;d=3;x=j" },
1981   { "mt@a=0;b=1;c=2;d=3", "a","f", "mt@a=f;b=1;c=2;d=3" },
1982   { "mt@a=0;aa=1;aaa=3", "a","x", "mt@a=x;aa=1;aaa=3" },
1983   { "mt@a=0;aa=1;aaa=3", "aa","x", "mt@a=0;aa=x;aaa=3" },
1984   { "mt@a=0;aa=1;aaa=3", "aaa","x", "mt@a=0;aa=1;aaa=x" },
1985   { "mt@a=0;aa=1;aaa=3", "a","yy", "mt@a=yy;aa=1;aaa=3" },
1986   { "mt@a=0;aa=1;aaa=3", "aa","yy", "mt@a=0;aa=yy;aaa=3" },
1987   { "mt@a=0;aa=1;aaa=3", "aaa","yy", "mt@a=0;aa=1;aaa=yy" },
1988 #endif
1989 #if 1
1990   /* removal tests */
1991   /* 1. removal of item at end */
1992   { "de@collation=phonebook;currency=CHF", "currency",   "", "de@collation=phonebook" },
1993   { "de@collation=phonebook;currency=CHF", "currency", NULL, "de@collation=phonebook" },
1994   /* 2. removal of item at beginning */
1995   { "de@collation=phonebook;currency=CHF", "collation", "", "de@currency=CHF" },
1996   { "de@collation=phonebook;currency=CHF", "collation", NULL, "de@currency=CHF" },
1997   /* 3. removal of an item not there */
1998   { "de@collation=phonebook;currency=CHF", "calendar", NULL, "de@collation=phonebook;currency=CHF" },
1999   /* 4. removal of only item */
2000   { "de@collation=phonebook", "collation", NULL, "de" },
2001 #endif
2002   { "de@collation=phonebook", "Currency", "CHF", "de@collation=phonebook;currency=CHF" },
2003   /* cases with legal extra spacing */
2004   /*31*/{ "en_US@ calendar = islamic", "calendar", "japanese", "en_US@calendar=japanese" },
2005   /*32*/{ "en_US@ calendar = gregorian ; collation = phonebook", "calendar", "japanese", "en_US@calendar=japanese;collation=phonebook" },
2006   /*33*/{ "en_US@ calendar = islamic", "currency", "CHF", "en_US@calendar=islamic;currency=CHF" },
2007   /*34*/{ "en_US@ currency = CHF", "calendar", "japanese", "en_US@calendar=japanese;currency=CHF" },
2008   /* cases in which setKeywordValue expected to fail (implied by NULL for expected); locale need not be canonical */
2009   /*35*/{ "en_US@calendar=gregorian;", "calendar", "japanese", NULL },
2010   /*36*/{ "en_US@calendar=gregorian;=", "calendar", "japanese", NULL },
2011   /*37*/{ "en_US@calendar=gregorian;currency=", "calendar", "japanese", NULL },
2012   /*38*/{ "en_US@=", "calendar", "japanese", NULL },
2013   /*39*/{ "en_US@=;", "calendar", "japanese", NULL },
2014   /*40*/{ "en_US@= ", "calendar", "japanese", NULL },
2015   /*41*/{ "en_US@ =", "calendar", "japanese", NULL },
2016   /*42*/{ "en_US@ = ", "calendar", "japanese", NULL },
2017   /*43*/{ "en_US@=;calendar=gregorian", "calendar", "japanese", NULL },
2018   /*44*/{ "en_US@= calen dar = gregorian", "calendar", "japanese", NULL },
2019   /*45*/{ "en_US@= calendar = greg orian", "calendar", "japanese", NULL },
2020   /*46*/{ "en_US@=;cal...endar=gregorian", "calendar", "japanese", NULL },
2021   /*47*/{ "en_US@=;calendar=greg...orian", "calendar", "japanese", NULL },
2022   /*48*/{ "en_US@calendar=gregorian", "cale ndar", "japanese", NULL },
2023   /*49*/{ "en_US@calendar=gregorian", "calendar", "japa..nese", NULL },
2024   /* cases in which getKeywordValue and setKeyword expected to fail (implied by NULL for value and expected) */
2025   /*50*/{ "en_US@=", "calendar", NULL, NULL },
2026   /*51*/{ "en_US@=;", "calendar", NULL, NULL },
2027   /*52*/{ "en_US@= ", "calendar", NULL, NULL },
2028   /*53*/{ "en_US@ =", "calendar", NULL, NULL },
2029   /*54*/{ "en_US@ = ", "calendar", NULL, NULL },
2030   /*55*/{ "en_US@=;calendar=gregorian", "calendar", NULL, NULL },
2031   /*56*/{ "en_US@= calen dar = gregorian", "calendar", NULL, NULL },
2032   /*57*/{ "en_US@= calendar = greg orian", "calendar", NULL, NULL },
2033   /*58*/{ "en_US@=;cal...endar=gregorian", "calendar", NULL, NULL },
2034   /*59*/{ "en_US@=;calendar=greg...orian", "calendar", NULL, NULL },
2035   /*60*/{ "en_US@calendar=gregorian", "cale ndar", NULL, NULL },
2036 };
2037 
2038 
TestKeywordSet(void)2039 static void TestKeywordSet(void)
2040 {
2041     int32_t i = 0;
2042     int32_t resultLen = 0;
2043     char buffer[1024];
2044 
2045     char cbuffer[1024];
2046 
2047     for(i = 0; i < UPRV_LENGTHOF(kwSetTestCases); i++) {
2048       UErrorCode status = U_ZERO_ERROR;
2049       memset(buffer,'%',1023);
2050       strcpy(buffer, kwSetTestCases[i].l);
2051 
2052       if (kwSetTestCases[i].x != NULL) {
2053         uloc_canonicalize(kwSetTestCases[i].l, cbuffer, 1023, &status);
2054         if(strcmp(buffer,cbuffer)) {
2055           log_verbose("note: [%d] wasn't canonical, should be: '%s' not '%s'. Won't check for canonicity in output.\n", i, cbuffer, buffer);
2056         }
2057         /* sanity check test case results for canonicity */
2058         uloc_canonicalize(kwSetTestCases[i].x, cbuffer, 1023, &status);
2059         if(strcmp(kwSetTestCases[i].x,cbuffer)) {
2060           log_err("%s:%d: ERROR: kwSetTestCases[%d].x = '%s', should be %s (must be canonical)\n", __FILE__, __LINE__, i, kwSetTestCases[i].x, cbuffer);
2061         }
2062 
2063         status = U_ZERO_ERROR;
2064         resultLen = uloc_setKeywordValue(kwSetTestCases[i].k, kwSetTestCases[i].v, buffer, 1023, &status);
2065         if(U_FAILURE(status)) {
2066           log_err("Err on test case %d for setKeywordValue: got error %s\n", i, u_errorName(status));
2067         } else if(strcmp(buffer,kwSetTestCases[i].x) || ((int32_t)strlen(buffer)!=resultLen)) {
2068           log_err("FAIL: #%d setKeywordValue: %s + [%s=%s] -> %s (%d) expected %s (%d)\n", i, kwSetTestCases[i].l, kwSetTestCases[i].k,
2069                   kwSetTestCases[i].v, buffer, resultLen, kwSetTestCases[i].x, strlen(buffer));
2070         } else {
2071           log_verbose("pass: #%d: %s + [%s=%s] -> %s\n", i, kwSetTestCases[i].l, kwSetTestCases[i].k, kwSetTestCases[i].v,buffer);
2072         }
2073 
2074         if (kwSetTestCases[i].v != NULL && kwSetTestCases[i].v[0] != 0) {
2075           status = U_ZERO_ERROR;
2076           resultLen = uloc_getKeywordValue(kwSetTestCases[i].x, kwSetTestCases[i].k, buffer, 1023, &status);
2077           if(U_FAILURE(status)) {
2078             log_err("Err on test case %d for getKeywordValue: got error %s\n", i, u_errorName(status));
2079           } else if (resultLen != (int32_t)uprv_strlen(kwSetTestCases[i].v) || uprv_strcmp(buffer, kwSetTestCases[i].v) != 0) {
2080             log_err("FAIL: #%d getKeywordValue: got %s (%d) expected %s (%d)\n", i, buffer, resultLen,
2081                     kwSetTestCases[i].v, uprv_strlen(kwSetTestCases[i].v));
2082           }
2083         }
2084       } else {
2085         /* test cases expected to result in error */
2086         status = U_ZERO_ERROR;
2087         resultLen = uloc_setKeywordValue(kwSetTestCases[i].k, kwSetTestCases[i].v, buffer, 1023, &status);
2088         if(U_SUCCESS(status)) {
2089           log_err("Err on test case %d for setKeywordValue: expected to fail but succeeded, got %s (%d)\n", i, buffer, resultLen);
2090         }
2091 
2092         if (kwSetTestCases[i].v == NULL) {
2093           status = U_ZERO_ERROR;
2094           strcpy(cbuffer, kwSetTestCases[i].l);
2095           resultLen = uloc_getKeywordValue(cbuffer, kwSetTestCases[i].k, buffer, 1023, &status);
2096           if(U_SUCCESS(status)) {
2097             log_err("Err on test case %d for getKeywordValue: expected to fail but succeeded\n", i);
2098           }
2099         }
2100       }
2101     }
2102 }
2103 
TestKeywordSetError(void)2104 static void TestKeywordSetError(void)
2105 {
2106     char buffer[1024];
2107     UErrorCode status;
2108     int32_t res;
2109     int32_t i;
2110     int32_t blen;
2111 
2112     /* 0-test whether an error condition modifies the buffer at all */
2113     blen=0;
2114     i=0;
2115     memset(buffer,'%',1023);
2116     status = U_ZERO_ERROR;
2117     res = uloc_setKeywordValue(kwSetTestCases[i].k, kwSetTestCases[i].v, buffer, blen, &status);
2118     if(status != U_ILLEGAL_ARGUMENT_ERROR) {
2119         log_err("expected illegal err got %s\n", u_errorName(status));
2120         return;
2121     }
2122     /*  if(res!=strlen(kwSetTestCases[i].x)) {
2123     log_err("expected result %d got %d\n", strlen(kwSetTestCases[i].x), res);
2124     return;
2125     } */
2126     if(buffer[blen]!='%') {
2127         log_err("Buffer byte %d was modified: now %c\n", blen, buffer[blen]);
2128         return;
2129     }
2130     log_verbose("0-buffer modify OK\n");
2131 
2132     for(i=0;i<=2;i++) {
2133         /* 1- test a short buffer with growing text */
2134         blen=(int32_t)strlen(kwSetTestCases[i].l)+1;
2135         memset(buffer,'%',1023);
2136         strcpy(buffer,kwSetTestCases[i].l);
2137         status = U_ZERO_ERROR;
2138         res = uloc_setKeywordValue(kwSetTestCases[i].k, kwSetTestCases[i].v, buffer, blen, &status);
2139         if(status != U_BUFFER_OVERFLOW_ERROR) {
2140             log_err("expected buffer overflow on buffer %d got %s, len %d (%s + [%s=%s])\n", blen, u_errorName(status), res, kwSetTestCases[i].l, kwSetTestCases[i].k, kwSetTestCases[i].v);
2141             return;
2142         }
2143         if(res!=(int32_t)strlen(kwSetTestCases[i].x)) {
2144             log_err("expected result %d got %d\n", strlen(kwSetTestCases[i].x), res);
2145             return;
2146         }
2147         if(buffer[blen]!='%') {
2148             log_err("Buffer byte %d was modified: now %c\n", blen, buffer[blen]);
2149             return;
2150         }
2151         log_verbose("1/%d-buffer modify OK\n",i);
2152     }
2153 
2154     for(i=3;i<=4;i++) {
2155         /* 2- test a short buffer - text the same size or shrinking   */
2156         blen=(int32_t)strlen(kwSetTestCases[i].l)+1;
2157         memset(buffer,'%',1023);
2158         strcpy(buffer,kwSetTestCases[i].l);
2159         status = U_ZERO_ERROR;
2160         res = uloc_setKeywordValue(kwSetTestCases[i].k, kwSetTestCases[i].v, buffer, blen, &status);
2161         if(status != U_ZERO_ERROR) {
2162             log_err("expected zero error got %s\n", u_errorName(status));
2163             return;
2164         }
2165         if(buffer[blen+1]!='%') {
2166             log_err("Buffer byte %d was modified: now %c\n", blen+1, buffer[blen+1]);
2167             return;
2168         }
2169         if(res!=(int32_t)strlen(kwSetTestCases[i].x)) {
2170             log_err("expected result %d got %d\n", strlen(kwSetTestCases[i].x), res);
2171             return;
2172         }
2173         if(strcmp(buffer,kwSetTestCases[i].x) || ((int32_t)strlen(buffer)!=res)) {
2174             log_err("FAIL: #%d: %s + [%s=%s] -> %s (%d) expected %s (%d)\n", i, kwSetTestCases[i].l, kwSetTestCases[i].k,
2175                 kwSetTestCases[i].v, buffer, res, kwSetTestCases[i].x, strlen(buffer));
2176         } else {
2177             log_verbose("pass: #%d: %s + [%s=%s] -> %s\n", i, kwSetTestCases[i].l, kwSetTestCases[i].k, kwSetTestCases[i].v,
2178                 buffer);
2179         }
2180         log_verbose("2/%d-buffer modify OK\n",i);
2181     }
2182 }
2183 
_canonicalize(int32_t selector,const char * localeID,char * result,int32_t resultCapacity,UErrorCode * ec)2184 static int32_t _canonicalize(int32_t selector, /* 0==getName, 1==canonicalize */
2185                              const char* localeID,
2186                              char* result,
2187                              int32_t resultCapacity,
2188                              UErrorCode* ec) {
2189     /* YOU can change this to use function pointers if you like */
2190     switch (selector) {
2191     case 0:
2192         return uloc_getName(localeID, result, resultCapacity, ec);
2193     case 1:
2194         return uloc_canonicalize(localeID, result, resultCapacity, ec);
2195     default:
2196         return -1;
2197     }
2198 }
2199 
TestCanonicalization(void)2200 static void TestCanonicalization(void)
2201 {
2202     static const struct {
2203         const char *localeID;    /* input */
2204         const char *getNameID;   /* expected getName() result */
2205         const char *canonicalID; /* expected canonicalize() result */
2206     } testCases[] = {
2207         { "ca_ES-with-extra-stuff-that really doesn't make any sense-unless-you're trying to increase code coverage",
2208           "ca_ES_WITH_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_YOU'RE TRYING TO INCREASE CODE COVERAGE",
2209           "ca_ES_WITH_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_YOU'RE TRYING TO INCREASE CODE COVERAGE"},
2210         { "zh@collation=pinyin", "zh@collation=pinyin", "zh@collation=pinyin" },
2211         { "zh_CN@collation=pinyin", "zh_CN@collation=pinyin", "zh_CN@collation=pinyin" },
2212         { "zh_CN_CA@collation=pinyin", "zh_CN_CA@collation=pinyin", "zh_CN_CA@collation=pinyin" },
2213         { "en_US_POSIX", "en_US_POSIX", "en_US_POSIX" },
2214         { "hy_AM_REVISED", "hy_AM_REVISED", "hy_AM_REVISED" },
2215         { "no_NO_NY", "no_NO_NY", "no_NO_NY" /* not: "nn_NO" [alan ICU3.0] */ },
2216         { "no@ny", "no@ny", "no__NY" /* not: "nn" [alan ICU3.0] */ }, /* POSIX ID */
2217         { "no-no.utf32@B", "no_NO.utf32@B", "no_NO_B" /* not: "nb_NO_B" [alan ICU3.0] */ }, /* POSIX ID */
2218         { "qz-qz@Euro", "qz_QZ@Euro", "qz_QZ_EURO" }, /* qz-qz uses private use iso codes */
2219         { "en-BOONT", "en__BOONT", "en__BOONT" }, /* registered name */
2220         { "de-1901", "de__1901", "de__1901" }, /* registered name */
2221         { "de-1906", "de__1906", "de__1906" }, /* registered name */
2222 
2223         /* posix behavior that used to be performed by getName */
2224         { "mr.utf8", "mr.utf8", "mr" },
2225         { "de-tv.koi8r", "de_TV.koi8r", "de_TV" },
2226         { "x-piglatin_ML.MBE", "x-piglatin_ML.MBE", "x-piglatin_ML" },
2227         { "i-cherokee_US.utf7", "i-cherokee_US.utf7", "i-cherokee_US" },
2228         { "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA" },
2229         { "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 */
2230 
2231         /* fleshing out canonicalization */
2232         /* trim space and sort keywords, ';' is separator so not present at end in canonical form */
2233         { "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" },
2234         /* already-canonical ids are not changed */
2235         { "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" },
2236         /* norwegian is just too weird, if we handle things in their full generality */
2237         { "no-Hant-GB_NY@currency=$$$", "no_Hant_GB_NY@currency=$$$", "no_Hant_GB_NY@currency=$$$" /* not: "nn_Hant_GB@currency=$$$" [alan ICU3.0] */ },
2238 
2239         /* test cases reflecting internal resource bundle usage */
2240         { "root@kw=foo", "root@kw=foo", "root@kw=foo" },
2241         { "@calendar=gregorian", "@calendar=gregorian", "@calendar=gregorian" },
2242         { "ja_JP@calendar=Japanese", "ja_JP@calendar=Japanese", "ja_JP@calendar=Japanese" },
2243         { "ja_JP", "ja_JP", "ja_JP" },
2244 
2245         /* test case for "i-default" */
2246         { "i-default", "en@x=i-default", "en@x=i-default" },
2247 
2248         // Before ICU 64, ICU locale canonicalization had some additional mappings.
2249         // They were removed for ICU-20187 "drop support for long-obsolete locale ID variants".
2250         // The following now use standard canonicalization.
2251         { "ca_ES_PREEURO", "ca_ES_PREEURO", "ca_ES_PREEURO" },
2252         { "de_AT_PREEURO", "de_AT_PREEURO", "de_AT_PREEURO" },
2253         { "de_DE_PREEURO", "de_DE_PREEURO", "de_DE_PREEURO" },
2254         { "de_LU_PREEURO", "de_LU_PREEURO", "de_LU_PREEURO" },
2255         { "el_GR_PREEURO", "el_GR_PREEURO", "el_GR_PREEURO" },
2256         { "en_BE_PREEURO", "en_BE_PREEURO", "en_BE_PREEURO" },
2257         { "en_IE_PREEURO", "en_IE_PREEURO", "en_IE_PREEURO" },
2258         { "es_ES_PREEURO", "es_ES_PREEURO", "es_ES_PREEURO" },
2259         { "eu_ES_PREEURO", "eu_ES_PREEURO", "eu_ES_PREEURO" },
2260         { "fi_FI_PREEURO", "fi_FI_PREEURO", "fi_FI_PREEURO" },
2261         { "fr_BE_PREEURO", "fr_BE_PREEURO", "fr_BE_PREEURO" },
2262         { "fr_FR_PREEURO", "fr_FR_PREEURO", "fr_FR_PREEURO" },
2263         { "fr_LU_PREEURO", "fr_LU_PREEURO", "fr_LU_PREEURO" },
2264         { "ga_IE_PREEURO", "ga_IE_PREEURO", "ga_IE_PREEURO" },
2265         { "gl_ES_PREEURO", "gl_ES_PREEURO", "gl_ES_PREEURO" },
2266         { "it_IT_PREEURO", "it_IT_PREEURO", "it_IT_PREEURO" },
2267         { "nl_BE_PREEURO", "nl_BE_PREEURO", "nl_BE_PREEURO" },
2268         { "nl_NL_PREEURO", "nl_NL_PREEURO", "nl_NL_PREEURO" },
2269         { "pt_PT_PREEURO", "pt_PT_PREEURO", "pt_PT_PREEURO" },
2270         { "de__PHONEBOOK", "de__PHONEBOOK", "de__PHONEBOOK" },
2271         { "en_GB_EURO", "en_GB_EURO", "en_GB_EURO" },
2272         { "en_GB@EURO", "en_GB@EURO", "en_GB_EURO" }, /* POSIX ID */
2273         { "es__TRADITIONAL", "es__TRADITIONAL", "es__TRADITIONAL" },
2274         { "hi__DIRECT", "hi__DIRECT", "hi__DIRECT" },
2275         { "ja_JP_TRADITIONAL", "ja_JP_TRADITIONAL", "ja_JP_TRADITIONAL" },
2276         { "th_TH_TRADITIONAL", "th_TH_TRADITIONAL", "th_TH_TRADITIONAL" },
2277         { "zh_TW_STROKE", "zh_TW_STROKE", "zh_TW_STROKE" },
2278         { "zh__PINYIN", "zh__PINYIN", "zh__PINYIN" },
2279         { "zh_CN_STROKE", "zh_CN_STROKE", "zh_CN_STROKE" },
2280         { "sr-SP-Cyrl", "sr_SP_CYRL", "sr_SP_CYRL" }, /* .NET name */
2281         { "sr-SP-Latn", "sr_SP_LATN", "sr_SP_LATN" }, /* .NET name */
2282         { "sr_YU_CYRILLIC", "sr_YU_CYRILLIC", "sr_YU_CYRILLIC" }, /* Linux name */
2283         { "uz-UZ-Cyrl", "uz_UZ_CYRL", "uz_UZ_CYRL" }, /* .NET name */
2284         { "uz-UZ-Latn", "uz_UZ_LATN", "uz_UZ_LATN" }, /* .NET name */
2285         { "zh-CHS", "zh_CHS", "zh_CHS" }, /* .NET name */
2286         { "zh-CHT", "zh_CHT", "zh_CHT" }, /* .NET name This may change back to zh_Hant */
2287         /* PRE_EURO and EURO conversions don't affect other keywords */
2288         { "es_ES_PREEURO@CALendar=Japanese", "es_ES_PREEURO@calendar=Japanese", "es_ES_PREEURO@calendar=Japanese" },
2289         { "es_ES_EURO@SHOUT=zipeedeedoodah", "es_ES_EURO@shout=zipeedeedoodah", "es_ES_EURO@shout=zipeedeedoodah" },
2290         /* currency keyword overrides PRE_EURO and EURO currency */
2291         { "es_ES_PREEURO@currency=EUR", "es_ES_PREEURO@currency=EUR", "es_ES_PREEURO@currency=EUR" },
2292         { "es_ES_EURO@currency=ESP", "es_ES_EURO@currency=ESP", "es_ES_EURO@currency=ESP" },
2293     };
2294 
2295     static const char* label[] = { "getName", "canonicalize" };
2296 
2297     UErrorCode status = U_ZERO_ERROR;
2298     int32_t i, j, resultLen = 0, origResultLen;
2299     char buffer[256];
2300 
2301     for (i=0; i < UPRV_LENGTHOF(testCases); i++) {
2302         for (j=0; j<2; ++j) {
2303             const char* expected = (j==0) ? testCases[i].getNameID : testCases[i].canonicalID;
2304             *buffer = 0;
2305             status = U_ZERO_ERROR;
2306 
2307             if (expected == NULL) {
2308                 expected = uloc_getDefault();
2309             }
2310 
2311             /* log_verbose("testing %s -> %s\n", testCases[i], testCases[i].canonicalID); */
2312             origResultLen = _canonicalize(j, testCases[i].localeID, NULL, 0, &status);
2313             if (status != U_BUFFER_OVERFLOW_ERROR) {
2314                 log_err("FAIL: uloc_%s(%s) => %s, expected U_BUFFER_OVERFLOW_ERROR\n",
2315                         label[j], testCases[i].localeID, u_errorName(status));
2316                 continue;
2317             }
2318             status = U_ZERO_ERROR;
2319             resultLen = _canonicalize(j, testCases[i].localeID, buffer, sizeof(buffer), &status);
2320             if (U_FAILURE(status)) {
2321                 log_err("FAIL: uloc_%s(%s) => %s, expected U_ZERO_ERROR\n",
2322                         label[j], testCases[i].localeID, u_errorName(status));
2323                 continue;
2324             }
2325             if(uprv_strcmp(expected, buffer) != 0) {
2326                 log_err("FAIL: uloc_%s(%s) => \"%s\", expected \"%s\"\n",
2327                         label[j], testCases[i].localeID, buffer, expected);
2328             } else {
2329                 log_verbose("Ok: uloc_%s(%s) => \"%s\"\n",
2330                             label[j], testCases[i].localeID, buffer);
2331             }
2332             if (resultLen != (int32_t)strlen(buffer)) {
2333                 log_err("FAIL: uloc_%s(%s) => len %d, expected len %d\n",
2334                         label[j], testCases[i].localeID, resultLen, strlen(buffer));
2335             }
2336             if (origResultLen != resultLen) {
2337                 log_err("FAIL: uloc_%s(%s) => preflight len %d != actual len %d\n",
2338                         label[j], testCases[i].localeID, origResultLen, resultLen);
2339             }
2340         }
2341     }
2342 }
2343 
TestCanonicalizationBuffer(void)2344 static void TestCanonicalizationBuffer(void)
2345 {
2346     UErrorCode status = U_ZERO_ERROR;
2347     char buffer[256];
2348 
2349     // ULOC_FULLNAME_CAPACITY == 157 (uloc.h)
2350     static const char name[] =
2351         "zh@x"
2352         "=foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
2353         "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
2354         "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
2355         "-foo-barz"
2356     ;
2357     static const size_t len = sizeof(name) - 1;  // Without NUL terminator.
2358 
2359     int32_t reslen = uloc_canonicalize(name, buffer, (int32_t)len, &status);
2360 
2361     if (U_FAILURE(status)) {
2362         log_err("FAIL: uloc_canonicalize(%s) => %s, expected !U_FAILURE()\n",
2363                 name, u_errorName(status));
2364         return;
2365     }
2366 
2367     if (reslen != len) {
2368         log_err("FAIL: uloc_canonicalize(%s) => \"%i\", expected \"%u\"\n",
2369                 name, reslen, len);
2370         return;
2371     }
2372 
2373     if (uprv_strncmp(name, buffer, len) != 0) {
2374         log_err("FAIL: uloc_canonicalize(%s) => \"%.*s\", expected \"%s\"\n",
2375                 name, reslen, buffer, name);
2376         return;
2377     }
2378 }
2379 
TestDisplayKeywords(void)2380 static void TestDisplayKeywords(void)
2381 {
2382     int32_t i;
2383 
2384     static const struct {
2385         const char *localeID;
2386         const char *displayLocale;
2387         UChar displayKeyword[200];
2388     } testCases[] = {
2389         {   "ca_ES@currency=ESP",         "de_AT",
2390             {0x0057, 0x00e4, 0x0068, 0x0072, 0x0075, 0x006e, 0x0067, 0x0000},
2391         },
2392         {   "ja_JP@calendar=japanese",         "de",
2393             { 0x004b, 0x0061, 0x006c, 0x0065, 0x006e, 0x0064, 0x0065, 0x0072, 0x0000}
2394         },
2395         {   "de_DE@collation=traditional",       "de_DE",
2396             {0x0053, 0x006f, 0x0072, 0x0074, 0x0069, 0x0065, 0x0072, 0x0075, 0x006e, 0x0067, 0x0000}
2397         },
2398     };
2399     for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
2400         UErrorCode status = U_ZERO_ERROR;
2401         const char* keyword =NULL;
2402         int32_t keywordLen = 0;
2403         int32_t keywordCount = 0;
2404         UChar *displayKeyword=NULL;
2405         int32_t displayKeywordLen = 0;
2406         UEnumeration* keywordEnum = uloc_openKeywords(testCases[i].localeID, &status);
2407         for(keywordCount = uenum_count(keywordEnum, &status); keywordCount > 0 ; keywordCount--){
2408               if(U_FAILURE(status)){
2409                   log_err("uloc_getKeywords failed for locale id: %s with error : %s \n", testCases[i].localeID, u_errorName(status));
2410                   break;
2411               }
2412               /* the uenum_next returns NUL terminated string */
2413               keyword = uenum_next(keywordEnum, &keywordLen, &status);
2414               /* fetch the displayKeyword */
2415               displayKeywordLen = uloc_getDisplayKeyword(keyword, testCases[i].displayLocale, displayKeyword, displayKeywordLen, &status);
2416               if(status==U_BUFFER_OVERFLOW_ERROR){
2417                   status = U_ZERO_ERROR;
2418                   displayKeywordLen++; /* for null termination */
2419                   displayKeyword = (UChar*) malloc(displayKeywordLen * U_SIZEOF_UCHAR);
2420                   displayKeywordLen = uloc_getDisplayKeyword(keyword, testCases[i].displayLocale, displayKeyword, displayKeywordLen, &status);
2421                   if(U_FAILURE(status)){
2422                       log_err("uloc_getDisplayKeyword filed for keyword : %s in locale id: %s for display locale: %s \n", testCases[i].localeID, keyword, testCases[i].displayLocale, u_errorName(status));
2423                       free(displayKeyword);
2424                       break;
2425                   }
2426                   if(u_strncmp(displayKeyword, testCases[i].displayKeyword, displayKeywordLen)!=0){
2427                       if (status == U_USING_DEFAULT_WARNING) {
2428                           log_data_err("uloc_getDisplayKeyword did not get the expected value for keyword : %s in locale id: %s for display locale: %s . Got error: %s. Perhaps you are missing data?\n", testCases[i].localeID, keyword, testCases[i].displayLocale, u_errorName(status));
2429                       } else {
2430                           log_err("uloc_getDisplayKeyword did not get the expected value for keyword : %s in locale id: %s for display locale: %s \n", testCases[i].localeID, keyword, testCases[i].displayLocale);
2431                       }
2432                       free(displayKeyword);
2433                       break;
2434                   }
2435               }else{
2436                   log_err("uloc_getDisplayKeyword did not return the expected error. Error: %s\n", u_errorName(status));
2437               }
2438 
2439               free(displayKeyword);
2440 
2441         }
2442         uenum_close(keywordEnum);
2443     }
2444 }
2445 
TestDisplayKeywordValues(void)2446 static void TestDisplayKeywordValues(void){
2447     int32_t i;
2448 
2449     static const struct {
2450         const char *localeID;
2451         const char *displayLocale;
2452         UChar displayKeywordValue[500];
2453     } testCases[] = {
2454         {   "ca_ES@currency=ESP",         "de_AT",
2455             {0x0053, 0x0070, 0x0061, 0x006e, 0x0069, 0x0073, 0x0063, 0x0068, 0x0065, 0x0020, 0x0050, 0x0065, 0x0073, 0x0065, 0x0074, 0x0061, 0x0000}
2456         },
2457         {   "de_AT@currency=ATS",         "fr_FR",
2458             {0x0073, 0x0063, 0x0068, 0x0069, 0x006c, 0x006c, 0x0069, 0x006e, 0x0067, 0x0020, 0x0061, 0x0075, 0x0074, 0x0072, 0x0069, 0x0063, 0x0068, 0x0069, 0x0065, 0x006e, 0x0000}
2459         },
2460         {   "de_DE@currency=DEM",         "it",
2461             {0x006d, 0x0061, 0x0072, 0x0063, 0x006f, 0x0020, 0x0074, 0x0065, 0x0064, 0x0065, 0x0073, 0x0063, 0x006f, 0x0000}
2462         },
2463         {   "el_GR@currency=GRD",         "en",
2464             {0x0047, 0x0072, 0x0065, 0x0065, 0x006b, 0x0020, 0x0044, 0x0072, 0x0061, 0x0063, 0x0068, 0x006d, 0x0061, 0x0000}
2465         },
2466         {   "eu_ES@currency=ESP",         "it_IT",
2467             {0x0070, 0x0065, 0x0073, 0x0065, 0x0074, 0x0061, 0x0020, 0x0073, 0x0070, 0x0061, 0x0067, 0x006e, 0x006f, 0x006c, 0x0061, 0x0000}
2468         },
2469         {   "de@collation=phonebook",     "es",
2470             {0x006F, 0x0072, 0x0064, 0x0065, 0x006E, 0x0020, 0x0064, 0x0065, 0x0020, 0x006C, 0x0069, 0x0073, 0x0074, 0x00ED, 0x006E, 0x0020, 0x0074, 0x0065, 0x006C, 0x0065, 0x0066, 0x00F3, 0x006E, 0x0069, 0x0063, 0x006F, 0x0000}
2471         },
2472 
2473         { "de_DE@collation=phonebook",  "es",
2474           {0x006F, 0x0072, 0x0064, 0x0065, 0x006E, 0x0020, 0x0064, 0x0065, 0x0020, 0x006C, 0x0069, 0x0073, 0x0074, 0x00ED, 0x006E, 0x0020, 0x0074, 0x0065, 0x006C, 0x0065, 0x0066, 0x00F3, 0x006E, 0x0069, 0x0063, 0x006F, 0x0000}
2475         },
2476         { "es_ES@collation=traditional","de",
2477           {0x0054, 0x0072, 0x0061, 0x0064, 0x0069, 0x0074, 0x0069, 0x006f, 0x006e, 0x0065, 0x006c, 0x006c, 0x0065, 0x0020, 0x0053, 0x006f, 0x0072, 0x0074, 0x0069, 0x0065, 0x0072, 0x0072, 0x0065, 0x0067, 0x0065, 0x006c, 0x006e, 0x0000}
2478         },
2479         { "ja_JP@calendar=japanese",    "de",
2480            {0x004a, 0x0061, 0x0070, 0x0061, 0x006e, 0x0069, 0x0073, 0x0063, 0x0068, 0x0065, 0x0072, 0x0020, 0x004b, 0x0061, 0x006c, 0x0065, 0x006e, 0x0064, 0x0065, 0x0072, 0x0000}
2481         },
2482     };
2483     for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
2484         UErrorCode status = U_ZERO_ERROR;
2485         const char* keyword =NULL;
2486         int32_t keywordLen = 0;
2487         int32_t keywordCount = 0;
2488         UChar *displayKeywordValue = NULL;
2489         int32_t displayKeywordValueLen = 0;
2490         UEnumeration* keywordEnum = uloc_openKeywords(testCases[i].localeID, &status);
2491         for(keywordCount = uenum_count(keywordEnum, &status); keywordCount > 0 ; keywordCount--){
2492               if(U_FAILURE(status)){
2493                   log_err("uloc_getKeywords failed for locale id: %s in display locale: % with error : %s \n", testCases[i].localeID, testCases[i].displayLocale, u_errorName(status));
2494                   break;
2495               }
2496               /* the uenum_next returns NUL terminated string */
2497               keyword = uenum_next(keywordEnum, &keywordLen, &status);
2498 
2499               /* fetch the displayKeywordValue */
2500               displayKeywordValueLen = uloc_getDisplayKeywordValue(testCases[i].localeID, keyword, testCases[i].displayLocale, displayKeywordValue, displayKeywordValueLen, &status);
2501               if(status==U_BUFFER_OVERFLOW_ERROR){
2502                   status = U_ZERO_ERROR;
2503                   displayKeywordValueLen++; /* for null termination */
2504                   displayKeywordValue = (UChar*)malloc(displayKeywordValueLen * U_SIZEOF_UCHAR);
2505                   displayKeywordValueLen = uloc_getDisplayKeywordValue(testCases[i].localeID, keyword, testCases[i].displayLocale, displayKeywordValue, displayKeywordValueLen, &status);
2506                   if(U_FAILURE(status)){
2507                       log_err("uloc_getDisplayKeywordValue failed for keyword : %s in locale id: %s for display locale: %s with error : %s \n", testCases[i].localeID, keyword, testCases[i].displayLocale, u_errorName(status));
2508                       free(displayKeywordValue);
2509                       break;
2510                   }
2511                   if(u_strncmp(displayKeywordValue, testCases[i].displayKeywordValue, displayKeywordValueLen)!=0){
2512                       if (status == U_USING_DEFAULT_WARNING) {
2513                           log_data_err("uloc_getDisplayKeywordValue did not return the expected value keyword : %s in locale id: %s for display locale: %s with error : %s Perhaps you are missing data\n", testCases[i].localeID, keyword, testCases[i].displayLocale, u_errorName(status));
2514                       } else {
2515                           log_err("uloc_getDisplayKeywordValue did not return the expected value keyword : %s in locale id: %s for display locale: %s with error : %s \n", testCases[i].localeID, keyword, testCases[i].displayLocale, u_errorName(status));
2516                       }
2517                       free(displayKeywordValue);
2518                       break;
2519                   }
2520               }else{
2521                   log_err("uloc_getDisplayKeywordValue did not return the expected error. Error: %s\n", u_errorName(status));
2522               }
2523               free(displayKeywordValue);
2524         }
2525         uenum_close(keywordEnum);
2526     }
2527     {
2528         /* test a multiple keywords */
2529         UErrorCode status = U_ZERO_ERROR;
2530         const char* keyword =NULL;
2531         int32_t keywordLen = 0;
2532         int32_t keywordCount = 0;
2533         const char* localeID = "es@collation=phonebook;calendar=buddhist;currency=DEM";
2534         const char* displayLocale = "de";
2535         static const UChar expected[][50] = {
2536             {0x0042, 0x0075, 0x0064, 0x0064, 0x0068, 0x0069, 0x0073, 0x0074, 0x0069, 0x0073, 0x0063, 0x0068, 0x0065, 0x0072, 0x0020, 0x004b, 0x0061, 0x006c, 0x0065, 0x006e, 0x0064, 0x0065, 0x0072, 0x0000},
2537 
2538             {0x0054, 0x0065, 0x006c, 0x0065, 0x0066, 0x006f, 0x006e, 0x0062, 0x0075, 0x0063, 0x0068, 0x002d, 0x0053, 0x006f, 0x0072, 0x0074, 0x0069, 0x0065, 0x0072, 0x0075, 0x006e, 0x0067, 0x0000},
2539             {0x0044, 0x0065, 0x0075, 0x0074, 0x0073, 0x0063, 0x0068, 0x0065, 0x0020, 0x004d, 0x0061, 0x0072, 0x006b, 0x0000},
2540         };
2541 
2542         UEnumeration* keywordEnum = uloc_openKeywords(localeID, &status);
2543 
2544         for(keywordCount = 0; keywordCount < uenum_count(keywordEnum, &status) ; keywordCount++){
2545               UChar *displayKeywordValue = NULL;
2546               int32_t displayKeywordValueLen = 0;
2547               if(U_FAILURE(status)){
2548                   log_err("uloc_getKeywords failed for locale id: %s in display locale: % with error : %s \n", localeID, displayLocale, u_errorName(status));
2549                   break;
2550               }
2551               /* the uenum_next returns NUL terminated string */
2552               keyword = uenum_next(keywordEnum, &keywordLen, &status);
2553 
2554               /* fetch the displayKeywordValue */
2555               displayKeywordValueLen = uloc_getDisplayKeywordValue(localeID, keyword, displayLocale, displayKeywordValue, displayKeywordValueLen, &status);
2556               if(status==U_BUFFER_OVERFLOW_ERROR){
2557                   status = U_ZERO_ERROR;
2558                   displayKeywordValueLen++; /* for null termination */
2559                   displayKeywordValue = (UChar*)malloc(displayKeywordValueLen * U_SIZEOF_UCHAR);
2560                   displayKeywordValueLen = uloc_getDisplayKeywordValue(localeID, keyword, displayLocale, displayKeywordValue, displayKeywordValueLen, &status);
2561                   if(U_FAILURE(status)){
2562                       log_err("uloc_getDisplayKeywordValue failed for keyword : %s in locale id: %s for display locale: %s with error : %s \n", localeID, keyword, displayLocale, u_errorName(status));
2563                       free(displayKeywordValue);
2564                       break;
2565                   }
2566                   if(u_strncmp(displayKeywordValue, expected[keywordCount], displayKeywordValueLen)!=0){
2567                       if (status == U_USING_DEFAULT_WARNING) {
2568                           log_data_err("uloc_getDisplayKeywordValue did not return the expected value keyword : %s in locale id: %s for display locale: %s  got error: %s. Perhaps you are missing data?\n", localeID, keyword, displayLocale, u_errorName(status));
2569                       } else {
2570                           log_err("uloc_getDisplayKeywordValue did not return the expected value keyword : %s in locale id: %s for display locale: %s \n", localeID, keyword, displayLocale);
2571                       }
2572                       free(displayKeywordValue);
2573                       break;
2574                   }
2575               }else{
2576                   log_err("uloc_getDisplayKeywordValue did not return the expected error. Error: %s\n", u_errorName(status));
2577               }
2578               free(displayKeywordValue);
2579         }
2580         uenum_close(keywordEnum);
2581 
2582     }
2583     {
2584         /* Test non existent keywords */
2585         UErrorCode status = U_ZERO_ERROR;
2586         const char* localeID = "es";
2587         const char* displayLocale = "de";
2588         UChar *displayKeywordValue = NULL;
2589         int32_t displayKeywordValueLen = 0;
2590 
2591         /* fetch the displayKeywordValue */
2592         displayKeywordValueLen = uloc_getDisplayKeywordValue(localeID, "calendar", displayLocale, displayKeywordValue, displayKeywordValueLen, &status);
2593         if(U_FAILURE(status)) {
2594           log_err("uloc_getDisplaykeywordValue returned error status %s\n", u_errorName(status));
2595         } else if(displayKeywordValueLen != 0) {
2596           log_err("uloc_getDisplaykeywordValue returned %d should be 0 \n", displayKeywordValueLen);
2597         }
2598     }
2599 }
2600 
2601 
TestGetBaseName(void)2602 static void TestGetBaseName(void) {
2603     static const struct {
2604         const char *localeID;
2605         const char *baseName;
2606     } testCases[] = {
2607         { "de_DE@  C o ll A t i o n   = Phonebook   ", "de_DE" },
2608         { "de@currency = euro; CoLLaTion   = PHONEBOOk", "de" },
2609         { "ja@calendar = buddhist", "ja" }
2610     };
2611 
2612     int32_t i = 0, baseNameLen = 0;
2613     char baseName[256];
2614     UErrorCode status = U_ZERO_ERROR;
2615 
2616     for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
2617         baseNameLen = uloc_getBaseName(testCases[i].localeID, baseName, 256, &status);
2618         (void)baseNameLen;    /* Suppress set but not used warning. */
2619         if(strcmp(testCases[i].baseName, baseName)) {
2620             log_err("For locale \"%s\" expected baseName \"%s\", but got \"%s\"\n",
2621                 testCases[i].localeID, testCases[i].baseName, baseName);
2622             return;
2623         }
2624     }
2625 }
2626 
TestTrailingNull(void)2627 static void TestTrailingNull(void) {
2628   const char* localeId = "zh_Hans";
2629   UChar buffer[128]; /* sufficient for this test */
2630   int32_t len;
2631   UErrorCode status = U_ZERO_ERROR;
2632   int i;
2633 
2634   len = uloc_getDisplayName(localeId, localeId, buffer, 128, &status);
2635   if (len > 128) {
2636     log_err("buffer too small");
2637     return;
2638   }
2639 
2640   for (i = 0; i < len; ++i) {
2641     if (buffer[i] == 0) {
2642       log_err("name contained null");
2643       return;
2644     }
2645   }
2646 }
2647 
2648 /* Jitterbug 4115 */
TestDisplayNameWarning(void)2649 static void TestDisplayNameWarning(void) {
2650     UChar name[256];
2651     int32_t size;
2652     UErrorCode status = U_ZERO_ERROR;
2653 
2654     size = uloc_getDisplayLanguage("qqq", "kl", name, UPRV_LENGTHOF(name), &status);
2655     (void)size;    /* Suppress set but not used warning. */
2656     if (status != U_USING_DEFAULT_WARNING) {
2657         log_err("For language \"qqq\" in locale \"kl\", expecting U_USING_DEFAULT_WARNING, but got %s\n",
2658             u_errorName(status));
2659     }
2660 }
2661 
2662 
2663 /**
2664  * Compare two locale IDs.  If they are equal, return 0.  If `string'
2665  * starts with `prefix' plus an additional element, that is, string ==
2666  * prefix + '_' + x, then return 1.  Otherwise return a value < 0.
2667  */
_loccmp(const char * string,const char * prefix)2668 static UBool _loccmp(const char* string, const char* prefix) {
2669     int32_t slen = (int32_t)uprv_strlen(string),
2670             plen = (int32_t)uprv_strlen(prefix);
2671     int32_t c = uprv_strncmp(string, prefix, plen);
2672     /* 'root' is less than everything */
2673     if (uprv_strcmp(prefix, "root") == 0) {
2674         return (uprv_strcmp(string, "root") == 0) ? 0 : 1;
2675     }
2676     if (c) return -1; /* mismatch */
2677     if (slen == plen) return 0;
2678     if (string[plen] == '_') return 1;
2679     return -2; /* false match, e.g. "en_USX" cmp "en_US" */
2680 }
2681 
_checklocs(const char * label,const char * req,const char * valid,const char * actual)2682 static void _checklocs(const char* label,
2683                        const char* req,
2684                        const char* valid,
2685                        const char* actual) {
2686     /* We want the valid to be strictly > the bogus requested locale,
2687        and the valid to be >= the actual. */
2688     if (_loccmp(req, valid) > 0 &&
2689         _loccmp(valid, actual) >= 0) {
2690         log_verbose("%s; req=%s, valid=%s, actual=%s\n",
2691                     label, req, valid, actual);
2692     } else {
2693         log_err("FAIL: %s; req=%s, valid=%s, actual=%s\n",
2694                 label, req, valid, actual);
2695     }
2696 }
2697 
TestGetLocale(void)2698 static void TestGetLocale(void) {
2699     UErrorCode ec = U_ZERO_ERROR;
2700     UParseError pe;
2701     UChar EMPTY[1] = {0};
2702 
2703     /* === udat === */
2704 #if !UCONFIG_NO_FORMATTING
2705     {
2706         UDateFormat *obj;
2707         const char *req = "en_US_REDWOODSHORES", *valid, *actual;
2708         obj = udat_open(UDAT_DEFAULT, UDAT_DEFAULT,
2709                         req,
2710                         NULL, 0,
2711                         NULL, 0, &ec);
2712         if (U_FAILURE(ec)) {
2713             log_data_err("udat_open failed.Error %s\n", u_errorName(ec));
2714             return;
2715         }
2716         valid = udat_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec);
2717         actual = udat_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec);
2718         if (U_FAILURE(ec)) {
2719             log_err("udat_getLocaleByType() failed\n");
2720             return;
2721         }
2722         _checklocs("udat", req, valid, actual);
2723         udat_close(obj);
2724     }
2725 #endif
2726 
2727     /* === ucal === */
2728 #if !UCONFIG_NO_FORMATTING
2729     {
2730         UCalendar *obj;
2731         const char *req = "fr_FR_PROVENCAL", *valid, *actual;
2732         obj = ucal_open(NULL, 0,
2733                         req,
2734                         UCAL_GREGORIAN,
2735                         &ec);
2736         if (U_FAILURE(ec)) {
2737             log_err("ucal_open failed with error: %s\n", u_errorName(ec));
2738             return;
2739         }
2740         valid = ucal_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec);
2741         actual = ucal_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec);
2742         if (U_FAILURE(ec)) {
2743             log_err("ucal_getLocaleByType() failed\n");
2744             return;
2745         }
2746         _checklocs("ucal", req, valid, actual);
2747         ucal_close(obj);
2748     }
2749 #endif
2750 
2751     /* === unum === */
2752 #if !UCONFIG_NO_FORMATTING
2753     {
2754         UNumberFormat *obj;
2755         const char *req = "zh_Hant_TW_TAINAN", *valid, *actual;
2756         obj = unum_open(UNUM_DECIMAL,
2757                         NULL, 0,
2758                         req,
2759                         &pe, &ec);
2760         if (U_FAILURE(ec)) {
2761             log_err("unum_open failed\n");
2762             return;
2763         }
2764         valid = unum_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec);
2765         actual = unum_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec);
2766         if (U_FAILURE(ec)) {
2767             log_err("unum_getLocaleByType() failed\n");
2768             return;
2769         }
2770         _checklocs("unum", req, valid, actual);
2771         unum_close(obj);
2772     }
2773 #endif
2774 
2775     /* === umsg === */
2776 #if 0
2777     /* commented out by weiv 01/12/2005. umsg_getLocaleByType is to be removed */
2778 #if !UCONFIG_NO_FORMATTING
2779     {
2780         UMessageFormat *obj;
2781         const char *req = "ja_JP_TAKAYAMA", *valid, *actual;
2782         UBool test;
2783         obj = umsg_open(EMPTY, 0,
2784                         req,
2785                         &pe, &ec);
2786         if (U_FAILURE(ec)) {
2787             log_err("umsg_open failed\n");
2788             return;
2789         }
2790         valid = umsg_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec);
2791         actual = umsg_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec);
2792         if (U_FAILURE(ec)) {
2793             log_err("umsg_getLocaleByType() failed\n");
2794             return;
2795         }
2796         /* We want the valid to be strictly > the bogus requested locale,
2797            and the valid to be >= the actual. */
2798         /* TODO MessageFormat is currently just storing the locale it is given.
2799            As a result, it will return whatever it was given, even if the
2800            locale is invalid. */
2801         test = (_cmpversion("3.2") <= 0) ?
2802             /* Here is the weakened test for 3.0: */
2803             (_loccmp(req, valid) >= 0) :
2804             /* Here is what the test line SHOULD be: */
2805             (_loccmp(req, valid) > 0);
2806 
2807         if (test &&
2808             _loccmp(valid, actual) >= 0) {
2809             log_verbose("umsg; req=%s, valid=%s, actual=%s\n", req, valid, actual);
2810         } else {
2811             log_err("FAIL: umsg; req=%s, valid=%s, actual=%s\n", req, valid, actual);
2812         }
2813         umsg_close(obj);
2814     }
2815 #endif
2816 #endif
2817 
2818     /* === ubrk === */
2819 #if !UCONFIG_NO_BREAK_ITERATION
2820     {
2821         UBreakIterator *obj;
2822         const char *req = "ar_KW_ABDALI", *valid, *actual;
2823         obj = ubrk_open(UBRK_WORD,
2824                         req,
2825                         EMPTY,
2826                         0,
2827                         &ec);
2828         if (U_FAILURE(ec)) {
2829             log_err("ubrk_open failed. Error: %s \n", u_errorName(ec));
2830             return;
2831         }
2832         valid = ubrk_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec);
2833         actual = ubrk_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec);
2834         if (U_FAILURE(ec)) {
2835             log_err("ubrk_getLocaleByType() failed\n");
2836             return;
2837         }
2838         _checklocs("ubrk", req, valid, actual);
2839         ubrk_close(obj);
2840     }
2841 #endif
2842 
2843     /* === ucol === */
2844 #if !UCONFIG_NO_COLLATION
2845     {
2846         UCollator *obj;
2847         const char *req = "es_AR_BUENOSAIRES", *valid, *actual;
2848         obj = ucol_open(req, &ec);
2849         if (U_FAILURE(ec)) {
2850             log_err("ucol_open failed - %s\n", u_errorName(ec));
2851             return;
2852         }
2853         valid = ucol_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec);
2854         actual = ucol_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec);
2855         if (U_FAILURE(ec)) {
2856             log_err("ucol_getLocaleByType() failed\n");
2857             return;
2858         }
2859         _checklocs("ucol", req, valid, actual);
2860         ucol_close(obj);
2861     }
2862 #endif
2863 }
TestEnglishExemplarCharacters(void)2864 static void TestEnglishExemplarCharacters(void) {
2865     UErrorCode status = U_ZERO_ERROR;
2866     int i;
2867     USet *exSet = NULL;
2868     UChar testChars[] = {
2869         0x61,   /* standard */
2870         0xE1,   /* auxiliary */
2871         0x41,   /* index */
2872         0x2D    /* punctuation */
2873     };
2874     ULocaleData *uld = ulocdata_open("en", &status);
2875     if (U_FAILURE(status)) {
2876         log_data_err("ulocdata_open() failed : %s - (Are you missing data?)\n", u_errorName(status));
2877         return;
2878     }
2879 
2880     for (i = 0; i < ULOCDATA_ES_COUNT; i++) {
2881         exSet = ulocdata_getExemplarSet(uld, exSet, 0, (ULocaleDataExemplarSetType)i, &status);
2882         if (U_FAILURE(status)) {
2883             log_err_status(status, "ulocdata_getExemplarSet() for type %d failed\n", i);
2884             status = U_ZERO_ERROR;
2885             continue;
2886         }
2887         if (!uset_contains(exSet, (UChar32)testChars[i])) {
2888             log_err("Character U+%04X is not included in exemplar type %d\n", testChars[i], i);
2889         }
2890     }
2891 
2892     uset_close(exSet);
2893     ulocdata_close(uld);
2894 }
2895 
TestNonexistentLanguageExemplars(void)2896 static void TestNonexistentLanguageExemplars(void) {
2897     /* JB 4068 - Nonexistent language */
2898     UErrorCode ec = U_ZERO_ERROR;
2899     ULocaleData *uld = ulocdata_open("qqq",&ec);
2900     if (ec != U_USING_DEFAULT_WARNING) {
2901         log_err_status(ec, "Exemplar set for \"qqq\", expecting U_USING_DEFAULT_WARNING, but got %s\n",
2902             u_errorName(ec));
2903     }
2904     uset_close(ulocdata_getExemplarSet(uld, NULL, 0, ULOCDATA_ES_STANDARD, &ec));
2905     ulocdata_close(uld);
2906 }
2907 
TestLocDataErrorCodeChaining(void)2908 static void TestLocDataErrorCodeChaining(void) {
2909     UErrorCode ec = U_USELESS_COLLATOR_ERROR;
2910     ulocdata_open(NULL, &ec);
2911     ulocdata_getExemplarSet(NULL, NULL, 0, ULOCDATA_ES_STANDARD, &ec);
2912     ulocdata_getDelimiter(NULL, ULOCDATA_DELIMITER_COUNT, NULL, -1, &ec);
2913     ulocdata_getMeasurementSystem(NULL, &ec);
2914     ulocdata_getPaperSize(NULL, NULL, NULL, &ec);
2915     if (ec != U_USELESS_COLLATOR_ERROR) {
2916         log_err("ulocdata API changed the error code to %s\n", u_errorName(ec));
2917     }
2918 }
2919 
2920 typedef struct {
2921     const char*        locale;
2922     UMeasurementSystem measureSys;
2923 } LocToMeasureSys;
2924 
2925 static const LocToMeasureSys locToMeasures[] = {
2926     { "fr_FR",            UMS_SI },
2927     { "en",               UMS_US },
2928     { "en_GB",            UMS_UK },
2929     { "fr_FR@rg=GBZZZZ",  UMS_UK },
2930     { "en@rg=frzzzz",     UMS_SI },
2931     { "en_GB@rg=USZZZZ",  UMS_US },
2932     { NULL, (UMeasurementSystem)0 } /* terminator */
2933 };
2934 
TestLocDataWithRgTag(void)2935 static void TestLocDataWithRgTag(void) {
2936     const  LocToMeasureSys* locToMeasurePtr = locToMeasures;
2937     for (; locToMeasurePtr->locale != NULL; locToMeasurePtr++) {
2938         UErrorCode status = U_ZERO_ERROR;
2939         UMeasurementSystem measureSys = ulocdata_getMeasurementSystem(locToMeasurePtr->locale, &status);
2940         if (U_FAILURE(status)) {
2941             log_data_err("ulocdata_getMeasurementSystem(\"%s\", ...) failed: %s - Are you missing data?\n",
2942                         locToMeasurePtr->locale, u_errorName(status));
2943         } else if (measureSys != locToMeasurePtr->measureSys) {
2944             log_err("ulocdata_getMeasurementSystem(\"%s\", ...), expected %d, got %d\n",
2945                         locToMeasurePtr->locale, (int) locToMeasurePtr->measureSys, (int)measureSys);
2946         }
2947     }
2948 }
2949 
TestLanguageExemplarsFallbacks(void)2950 static void TestLanguageExemplarsFallbacks(void) {
2951     /* Test that en_US fallsback, but en doesn't fallback. */
2952     UErrorCode ec = U_ZERO_ERROR;
2953     ULocaleData *uld = ulocdata_open("en_US",&ec);
2954     uset_close(ulocdata_getExemplarSet(uld, NULL, 0, ULOCDATA_ES_STANDARD, &ec));
2955     if (ec != U_USING_FALLBACK_WARNING) {
2956         log_err_status(ec, "Exemplar set for \"en_US\", expecting U_USING_FALLBACK_WARNING, but got %s\n",
2957             u_errorName(ec));
2958     }
2959     ulocdata_close(uld);
2960     ec = U_ZERO_ERROR;
2961     uld = ulocdata_open("en",&ec);
2962     uset_close(ulocdata_getExemplarSet(uld, NULL, 0, ULOCDATA_ES_STANDARD, &ec));
2963     if (ec != U_ZERO_ERROR) {
2964         log_err_status(ec, "Exemplar set for \"en\", expecting U_ZERO_ERROR, but got %s\n",
2965             u_errorName(ec));
2966     }
2967     ulocdata_close(uld);
2968 }
2969 
acceptResult(UAcceptResult uar)2970 static const char *acceptResult(UAcceptResult uar) {
2971     return  udbg_enumName(UDBG_UAcceptResult, uar);
2972 }
2973 
TestAcceptLanguage(void)2974 static void TestAcceptLanguage(void) {
2975     UErrorCode status = U_ZERO_ERROR;
2976     UAcceptResult outResult;
2977     UEnumeration *available;
2978     char tmp[200];
2979     int i;
2980     int32_t rc = 0;
2981 
2982     struct {
2983         int32_t httpSet;       /**< Which of http[] should be used? */
2984         const char *icuSet;    /**< ? */
2985         const char *expect;    /**< The expected locale result */
2986         UAcceptResult res;     /**< The expected error code */
2987         UErrorCode expectStatus; /**< expected status */
2988     } tests[] = {
2989         /*0*/{ 0, NULL, "mt_MT", ULOC_ACCEPT_VALID, U_ZERO_ERROR},
2990         /*1*/{ 1, NULL, "en", ULOC_ACCEPT_VALID, U_ZERO_ERROR},
2991         /*2*/{ 2, NULL, "en", ULOC_ACCEPT_FALLBACK, U_ZERO_ERROR},
2992         /*3*/{ 3, NULL, "", ULOC_ACCEPT_FAILED, U_ZERO_ERROR},
2993         /*4*/{ 4, NULL, "es", ULOC_ACCEPT_VALID, U_ZERO_ERROR},
2994         /*5*/{ 5, NULL, "en", ULOC_ACCEPT_VALID, U_ZERO_ERROR},  /* XF */
2995         /*6*/{ 6, NULL, "ja", ULOC_ACCEPT_FALLBACK, U_ZERO_ERROR},  /* XF */
2996         /*7*/{ 7, NULL, "zh", ULOC_ACCEPT_FALLBACK, U_ZERO_ERROR},  /* XF */
2997         /*8*/{ 8, NULL, "", ULOC_ACCEPT_FAILED, U_ZERO_ERROR },  /*  */
2998         /*9*/{ 9, NULL, "", ULOC_ACCEPT_FAILED, U_ZERO_ERROR },  /*  */
2999        /*10*/{10, NULL, "", ULOC_ACCEPT_FAILED, U_BUFFER_OVERFLOW_ERROR },  /*  */
3000        /*11*/{11, NULL, "", ULOC_ACCEPT_FAILED, U_BUFFER_OVERFLOW_ERROR },  /*  */
3001     };
3002     const int32_t numTests = UPRV_LENGTHOF(tests);
3003     static const char *http[] = {
3004         /*0*/ "mt-mt, ja;q=0.76, en-us;q=0.95, en;q=0.92, en-gb;q=0.89, fr;q=0.87, iu-ca;q=0.84, iu;q=0.82, ja-jp;q=0.79, mt;q=0.97, de-de;q=0.74, de;q=0.71, es;q=0.68, it-it;q=0.66, it;q=0.63, vi-vn;q=0.61, vi;q=0.58, nl-nl;q=0.55, nl;q=0.53, th-th-traditional;q=.01",
3005         /*1*/ "ja;q=0.5, en;q=0.8, tlh",
3006         /*2*/ "en-wf, de-lx;q=0.8",
3007         /*3*/ "mga-ie;q=0.9, tlh",
3008         /*4*/ "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
3009               "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
3010               "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
3011               "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
3012               "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
3013               "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
3014               "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xx-yy;q=.1, "
3015               "es",
3016         /*5*/ "zh-xx;q=0.9, en;q=0.6",
3017         /*6*/ "ja-JA",
3018         /*7*/ "zh-xx;q=0.9",
3019        /*08*/ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3020               "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3021               "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3022               "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", // 156
3023        /*09*/ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3024               "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3025               "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3026               "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB", // 157 (this hits U_STRING_NOT_TERMINATED_WARNING )
3027        /*10*/ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3028               "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3029               "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3030               "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABC", // 158
3031        /*11*/ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3032               "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3033               "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3034               "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", // 163 bytes
3035     };
3036 
3037     for(i=0;i<numTests;i++) {
3038         outResult = -3;
3039         status=U_ZERO_ERROR;
3040         log_verbose("test #%d: http[%s], ICU[%s], expect %s, %s\n",
3041             i, http[tests[i].httpSet], tests[i].icuSet, tests[i].expect, acceptResult(tests[i].res));
3042 
3043         available = ures_openAvailableLocales(tests[i].icuSet, &status);
3044         tmp[0]=0;
3045         rc = uloc_acceptLanguageFromHTTP(tmp, 199, &outResult, http[tests[i].httpSet], available, &status);
3046         (void)rc;    /* Suppress set but not used warning. */
3047         uenum_close(available);
3048         log_verbose(" got %s, %s [%s]\n", tmp[0]?tmp:"(EMPTY)", acceptResult(outResult), u_errorName(status));
3049         if(status != tests[i].expectStatus) {
3050           log_err_status(status, "FAIL: expected status %s but got %s\n", u_errorName(tests[i].expectStatus), u_errorName(status));
3051         } else if(U_SUCCESS(tests[i].expectStatus)) {
3052             /* don't check content if expected failure */
3053             if(outResult != tests[i].res) {
3054             log_err_status(status, "FAIL: #%d: expected outResult of %s but got %s\n", i,
3055                 acceptResult( tests[i].res),
3056                 acceptResult( outResult));
3057             log_info("test #%d: http[%s], ICU[%s], expect %s, %s\n",
3058                 i, http[tests[i].httpSet], tests[i].icuSet, tests[i].expect,acceptResult(tests[i].res));
3059             }
3060             if((outResult>0)&&uprv_strcmp(tmp, tests[i].expect)) {
3061               log_err_status(status, "FAIL: #%d: expected %s but got %s\n", i, tests[i].expect, tmp);
3062               log_info("test #%d: http[%s], ICU[%s], expect %s, %s\n",
3063                        i, http[tests[i].httpSet], tests[i].icuSet, tests[i].expect, acceptResult(tests[i].res));
3064             }
3065         }
3066     }
3067 }
3068 
3069 static const char* LOCALE_ALIAS[][2] = {
3070     {"in", "id"},
3071     {"in_ID", "id_ID"},
3072     {"iw", "he"},
3073     {"iw_IL", "he_IL"},
3074     {"ji", "yi"},
3075     {"en_BU", "en_MM"},
3076     {"en_DY", "en_BJ"},
3077     {"en_HV", "en_BF"},
3078     {"en_NH", "en_VU"},
3079     {"en_RH", "en_ZW"},
3080     {"en_TP", "en_TL"},
3081     {"en_ZR", "en_CD"}
3082 };
isLocaleAvailable(UResourceBundle * resIndex,const char * loc)3083 static UBool isLocaleAvailable(UResourceBundle* resIndex, const char* loc){
3084     UErrorCode status = U_ZERO_ERROR;
3085     int32_t len = 0;
3086     ures_getStringByKey(resIndex, loc,&len, &status);
3087     if(U_FAILURE(status)){
3088         return FALSE;
3089     }
3090     return TRUE;
3091 }
3092 
TestCalendar()3093 static void TestCalendar() {
3094 #if !UCONFIG_NO_FORMATTING
3095     int i;
3096     UErrorCode status = U_ZERO_ERROR;
3097     UResourceBundle *resIndex = ures_open(NULL,"res_index", &status);
3098     if(U_FAILURE(status)){
3099         log_err_status(status, "Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
3100         return;
3101     }
3102     for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
3103         const char* oldLoc = LOCALE_ALIAS[i][0];
3104         const char* newLoc = LOCALE_ALIAS[i][1];
3105         UCalendar* c1 = NULL;
3106         UCalendar* c2 = NULL;
3107 
3108         /*Test function "getLocale(ULocale.VALID_LOCALE)"*/
3109         const char* l1 = ucal_getLocaleByType(c1, ULOC_VALID_LOCALE, &status);
3110         const char* l2 = ucal_getLocaleByType(c2, ULOC_VALID_LOCALE, &status);
3111 
3112         if(!isLocaleAvailable(resIndex, newLoc)){
3113             continue;
3114         }
3115         c1 = ucal_open(NULL, -1, oldLoc, UCAL_GREGORIAN, &status);
3116         c2 = ucal_open(NULL, -1, newLoc, UCAL_GREGORIAN, &status);
3117 
3118         if (strcmp(newLoc,l1)!=0 || strcmp(l1,l2)!=0 || status!=U_ZERO_ERROR) {
3119             log_err("The locales are not equal!.Old: %s, New: %s \n", oldLoc, newLoc);
3120         }
3121         log_verbose("ucal_getLocaleByType old:%s   new:%s\n", l1, l2);
3122         ucal_close(c1);
3123         ucal_close(c2);
3124     }
3125     ures_close(resIndex);
3126 #endif
3127 }
3128 
TestDateFormat()3129 static void TestDateFormat() {
3130 #if !UCONFIG_NO_FORMATTING
3131     int i;
3132     UErrorCode status = U_ZERO_ERROR;
3133     UResourceBundle *resIndex = ures_open(NULL,"res_index", &status);
3134     if(U_FAILURE(status)){
3135         log_err_status(status, "Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
3136         return;
3137     }
3138     for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
3139         const char* oldLoc = LOCALE_ALIAS[i][0];
3140         const char* newLoc = LOCALE_ALIAS[i][1];
3141         UDateFormat* df1 = NULL;
3142         UDateFormat* df2 = NULL;
3143         const char* l1 = NULL;
3144         const char* l2 = NULL;
3145 
3146         if(!isLocaleAvailable(resIndex, newLoc)){
3147             continue;
3148         }
3149         df1 = udat_open(UDAT_FULL, UDAT_FULL,oldLoc, NULL, 0, NULL, -1, &status);
3150         df2 = udat_open(UDAT_FULL, UDAT_FULL,newLoc, NULL, 0, NULL, -1, &status);
3151         if(U_FAILURE(status)){
3152             log_err("Creation of date format failed  %s\n", u_errorName(status));
3153             return;
3154         }
3155         /*Test function "getLocale"*/
3156         l1 = udat_getLocaleByType(df1, ULOC_VALID_LOCALE, &status);
3157         l2 = udat_getLocaleByType(df2, ULOC_VALID_LOCALE, &status);
3158         if(U_FAILURE(status)){
3159             log_err("Fetching the locale by type failed.  %s\n", u_errorName(status));
3160         }
3161         if (strcmp(newLoc,l1)!=0 || strcmp(l1,l2)!=0) {
3162             log_err("The locales are not equal!.Old: %s, New: %s \n", oldLoc, newLoc);
3163         }
3164         log_verbose("udat_getLocaleByType old:%s   new:%s\n", l1, l2);
3165         udat_close(df1);
3166         udat_close(df2);
3167     }
3168     ures_close(resIndex);
3169 #endif
3170 }
3171 
TestCollation()3172 static void TestCollation() {
3173 #if !UCONFIG_NO_COLLATION
3174     int i;
3175     UErrorCode status = U_ZERO_ERROR;
3176     UResourceBundle *resIndex = ures_open(NULL,"res_index", &status);
3177     if(U_FAILURE(status)){
3178         log_err_status(status, "Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
3179         return;
3180     }
3181     for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
3182         const char* oldLoc = LOCALE_ALIAS[i][0];
3183         const char* newLoc = LOCALE_ALIAS[i][1];
3184         UCollator* c1 = NULL;
3185         UCollator* c2 = NULL;
3186         const char* l1 = NULL;
3187         const char* l2 = NULL;
3188 
3189         status = U_ZERO_ERROR;
3190         if(!isLocaleAvailable(resIndex, newLoc)){
3191             continue;
3192         }
3193         if(U_FAILURE(status)){
3194             log_err("Creation of collators failed  %s\n", u_errorName(status));
3195             return;
3196         }
3197         c1 = ucol_open(oldLoc, &status);
3198         c2 = ucol_open(newLoc, &status);
3199         l1 = ucol_getLocaleByType(c1, ULOC_VALID_LOCALE, &status);
3200         l2 = ucol_getLocaleByType(c2, ULOC_VALID_LOCALE, &status);
3201         if(U_FAILURE(status)){
3202             log_err("Fetching the locale names failed failed  %s\n", u_errorName(status));
3203         }
3204         if (strcmp(newLoc,l1)!=0 || strcmp(l1,l2)!=0) {
3205             log_err("The locales are not equal!.Old: %s, New: %s \n", oldLoc, newLoc);
3206         }
3207         log_verbose("ucol_getLocaleByType old:%s   new:%s\n", l1, l2);
3208         ucol_close(c1);
3209         ucol_close(c2);
3210     }
3211     ures_close(resIndex);
3212 #endif
3213 }
3214 
3215 typedef struct OrientationStructTag {
3216     const char* localeId;
3217     ULayoutType character;
3218     ULayoutType line;
3219 } OrientationStruct;
3220 
ULayoutTypeToString(ULayoutType type)3221 static const char* ULayoutTypeToString(ULayoutType type)
3222 {
3223     switch(type)
3224     {
3225     case ULOC_LAYOUT_LTR:
3226         return "ULOC_LAYOUT_LTR";
3227         break;
3228     case ULOC_LAYOUT_RTL:
3229         return "ULOC_LAYOUT_RTL";
3230         break;
3231     case ULOC_LAYOUT_TTB:
3232         return "ULOC_LAYOUT_TTB";
3233         break;
3234     case ULOC_LAYOUT_BTT:
3235         return "ULOC_LAYOUT_BTT";
3236         break;
3237     case ULOC_LAYOUT_UNKNOWN:
3238         break;
3239     }
3240 
3241     return "Unknown enum value for ULayoutType!";
3242 }
3243 
TestOrientation()3244 static void  TestOrientation()
3245 {
3246     static const OrientationStruct toTest [] = {
3247         { "ar", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3248         { "aR", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3249         { "ar_Arab", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3250         { "fa", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3251         { "Fa", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3252         { "he", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3253         { "ps", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3254         { "ur", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3255         { "UR", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3256         { "en", ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB }
3257     };
3258 
3259     size_t i = 0;
3260     for (; i < UPRV_LENGTHOF(toTest); ++i) {
3261         UErrorCode statusCO = U_ZERO_ERROR;
3262         UErrorCode statusLO = U_ZERO_ERROR;
3263         const char* const localeId = toTest[i].localeId;
3264         const ULayoutType co = uloc_getCharacterOrientation(localeId, &statusCO);
3265         const ULayoutType expectedCO = toTest[i].character;
3266         const ULayoutType lo = uloc_getLineOrientation(localeId, &statusLO);
3267         const ULayoutType expectedLO = toTest[i].line;
3268         if (U_FAILURE(statusCO)) {
3269             log_err_status(statusCO,
3270                 "  unexpected failure for uloc_getCharacterOrientation(), with localId \"%s\" and status %s\n",
3271                 localeId,
3272                 u_errorName(statusCO));
3273         }
3274         else if (co != expectedCO) {
3275             log_err(
3276                 "  unexpected result for uloc_getCharacterOrientation(), with localeId \"%s\". Expected %s but got result %s\n",
3277                 localeId,
3278                 ULayoutTypeToString(expectedCO),
3279                 ULayoutTypeToString(co));
3280         }
3281         if (U_FAILURE(statusLO)) {
3282             log_err_status(statusLO,
3283                 "  unexpected failure for uloc_getLineOrientation(), with localId \"%s\" and status %s\n",
3284                 localeId,
3285                 u_errorName(statusLO));
3286         }
3287         else if (lo != expectedLO) {
3288             log_err(
3289                 "  unexpected result for uloc_getLineOrientation(), with localeId \"%s\". Expected %s but got result %s\n",
3290                 localeId,
3291                 ULayoutTypeToString(expectedLO),
3292                 ULayoutTypeToString(lo));
3293         }
3294     }
3295 }
3296 
TestULocale()3297 static void  TestULocale() {
3298     int i;
3299     UErrorCode status = U_ZERO_ERROR;
3300     UResourceBundle *resIndex = ures_open(NULL,"res_index", &status);
3301     if(U_FAILURE(status)){
3302         log_err_status(status, "Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
3303         return;
3304     }
3305     for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
3306         const char* oldLoc = LOCALE_ALIAS[i][0];
3307         const char* newLoc = LOCALE_ALIAS[i][1];
3308         UChar name1[256], name2[256];
3309         char names1[256], names2[256];
3310         int32_t capacity = 256;
3311 
3312         status = U_ZERO_ERROR;
3313         if(!isLocaleAvailable(resIndex, newLoc)){
3314             continue;
3315         }
3316         uloc_getDisplayName(oldLoc, ULOC_US, name1, capacity, &status);
3317         if(U_FAILURE(status)){
3318             log_err("uloc_getDisplayName(%s) failed %s\n", oldLoc, u_errorName(status));
3319         }
3320 
3321         uloc_getDisplayName(newLoc, ULOC_US, name2, capacity, &status);
3322         if(U_FAILURE(status)){
3323             log_err("uloc_getDisplayName(%s) failed %s\n", newLoc, u_errorName(status));
3324         }
3325 
3326         if (u_strcmp(name1, name2)!=0) {
3327             log_err("The locales are not equal!.Old: %s, New: %s \n", oldLoc, newLoc);
3328         }
3329         u_austrcpy(names1, name1);
3330         u_austrcpy(names2, name2);
3331         log_verbose("uloc_getDisplayName old:%s   new:%s\n", names1, names2);
3332     }
3333     ures_close(resIndex);
3334 
3335 }
3336 
TestUResourceBundle()3337 static void TestUResourceBundle() {
3338     const char* us1;
3339     const char* us2;
3340 
3341     UResourceBundle* rb1 = NULL;
3342     UResourceBundle* rb2 = NULL;
3343     UErrorCode status = U_ZERO_ERROR;
3344     int i;
3345     UResourceBundle *resIndex = NULL;
3346     if(U_FAILURE(status)){
3347         log_err("Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
3348         return;
3349     }
3350     resIndex = ures_open(NULL,"res_index", &status);
3351     for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
3352 
3353         const char* oldLoc = LOCALE_ALIAS[i][0];
3354         const char* newLoc = LOCALE_ALIAS[i][1];
3355         if(!isLocaleAvailable(resIndex, newLoc)){
3356             continue;
3357         }
3358         rb1 = ures_open(NULL, oldLoc, &status);
3359         if (U_FAILURE(status)) {
3360             log_err("ures_open(%s) failed %s\n", oldLoc, u_errorName(status));
3361         }
3362 
3363         us1 = ures_getLocaleByType(rb1, ULOC_ACTUAL_LOCALE, &status);
3364 
3365         status = U_ZERO_ERROR;
3366         rb2 = ures_open(NULL, newLoc, &status);
3367         if (U_FAILURE(status)) {
3368             log_err("ures_open(%s) failed %s\n", oldLoc, u_errorName(status));
3369         }
3370         us2 = ures_getLocaleByType(rb2, ULOC_ACTUAL_LOCALE, &status);
3371 
3372         if (strcmp(us1,newLoc)!=0 || strcmp(us1,us2)!=0 ) {
3373             log_err("The locales are not equal!.Old: %s, New: %s \n", oldLoc, newLoc);
3374         }
3375 
3376         log_verbose("ures_getStringByKey old:%s   new:%s\n", us1, us2);
3377         ures_close(rb1);
3378         rb1 = NULL;
3379         ures_close(rb2);
3380         rb2 = NULL;
3381     }
3382     ures_close(resIndex);
3383 }
3384 
TestDisplayName()3385 static void TestDisplayName() {
3386 
3387     UChar oldCountry[256] = {'\0'};
3388     UChar newCountry[256] = {'\0'};
3389     UChar oldLang[256] = {'\0'};
3390     UChar newLang[256] = {'\0'};
3391     char country[256] ={'\0'};
3392     char language[256] ={'\0'};
3393     int32_t capacity = 256;
3394     int i =0;
3395     int j=0;
3396     for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
3397         const char* oldLoc = LOCALE_ALIAS[i][0];
3398         const char* newLoc = LOCALE_ALIAS[i][1];
3399         UErrorCode status = U_ZERO_ERROR;
3400         int32_t available = uloc_countAvailable();
3401 
3402         for(j=0; j<available; j++){
3403 
3404             const char* dispLoc = uloc_getAvailable(j);
3405             int32_t oldCountryLen = uloc_getDisplayCountry(oldLoc,dispLoc, oldCountry, capacity, &status);
3406             int32_t newCountryLen = uloc_getDisplayCountry(newLoc, dispLoc, newCountry, capacity, &status);
3407             int32_t oldLangLen = uloc_getDisplayLanguage(oldLoc, dispLoc, oldLang, capacity, &status);
3408             int32_t newLangLen = uloc_getDisplayLanguage(newLoc, dispLoc, newLang, capacity, &status );
3409 
3410             int32_t countryLen = uloc_getCountry(newLoc, country, capacity, &status);
3411             int32_t langLen  = uloc_getLanguage(newLoc, language, capacity, &status);
3412             /* there is a display name for the current country ID */
3413             if(countryLen != newCountryLen ){
3414                 if(u_strncmp(oldCountry,newCountry,oldCountryLen)!=0){
3415                     log_err("uloc_getDisplayCountry() failed for %s in display locale %s \n", oldLoc, dispLoc);
3416                 }
3417             }
3418             /* there is a display name for the current lang ID */
3419             if(langLen!=newLangLen){
3420                 if(u_strncmp(oldLang,newLang,oldLangLen)){
3421                     log_err("uloc_getDisplayLanguage() failed for %s in display locale %s \n", oldLoc, dispLoc);                }
3422             }
3423         }
3424     }
3425 }
3426 
TestGetLocaleForLCID()3427 static void TestGetLocaleForLCID() {
3428     int32_t i, length, lengthPre;
3429     const char* testLocale = 0;
3430     UErrorCode status = U_ZERO_ERROR;
3431     char            temp2[40], temp3[40];
3432     uint32_t lcid;
3433 
3434     lcid = uloc_getLCID("en_US");
3435     if (lcid != 0x0409) {
3436         log_err("  uloc_getLCID(\"en_US\") = %d, expected 0x0409\n", lcid);
3437     }
3438 
3439     lengthPre = uloc_getLocaleForLCID(lcid, temp2, 4, &status);
3440     if (status != U_BUFFER_OVERFLOW_ERROR) {
3441         log_err("  unexpected result from uloc_getLocaleForLCID with small buffer: %s\n", u_errorName(status));
3442     }
3443     else {
3444         status = U_ZERO_ERROR;
3445     }
3446 
3447     length = uloc_getLocaleForLCID(lcid, temp2, UPRV_LENGTHOF(temp2), &status);
3448     if (U_FAILURE(status)) {
3449         log_err("  unexpected result from uloc_getLocaleForLCID(0x0409): %s\n", u_errorName(status));
3450         status = U_ZERO_ERROR;
3451     }
3452 
3453     if (length != lengthPre) {
3454         log_err("  uloc_getLocaleForLCID(0x0409): returned length %d does not match preflight length %d\n", length, lengthPre);
3455     }
3456 
3457     length = uloc_getLocaleForLCID(0x12345, temp2, UPRV_LENGTHOF(temp2), &status);
3458     if (U_SUCCESS(status)) {
3459         log_err("  unexpected result from uloc_getLocaleForLCID(0x12345): %s, status %s\n", temp2, u_errorName(status));
3460     }
3461     status = U_ZERO_ERROR;
3462 
3463     log_verbose("Testing getLocaleForLCID vs. locale data\n");
3464     for (i = 0; i < LOCALE_SIZE; i++) {
3465 
3466         testLocale=rawData2[NAME][i];
3467 
3468         log_verbose("Testing   %s ......\n", testLocale);
3469 
3470         sscanf(rawData2[LCID][i], "%x", &lcid);
3471         length = uloc_getLocaleForLCID(lcid, temp2, UPRV_LENGTHOF(temp2), &status);
3472         if (U_FAILURE(status)) {
3473             log_err("  unexpected failure of uloc_getLocaleForLCID(%#04x), status %s\n", lcid, u_errorName(status));
3474             status = U_ZERO_ERROR;
3475             continue;
3476         }
3477 
3478         if (length != (int32_t)uprv_strlen(temp2)) {
3479             log_err("  returned length %d not correct for uloc_getLocaleForLCID(%#04x), expected %d\n", length, lcid, uprv_strlen(temp2));
3480         }
3481 
3482         /* Compare language, country, script */
3483         length = uloc_getLanguage(temp2, temp3, UPRV_LENGTHOF(temp3), &status);
3484         if (U_FAILURE(status)) {
3485             log_err("  couldn't get language in uloc_getLocaleForLCID(%#04x) = %s, status %s\n", lcid, temp2, u_errorName(status));
3486             status = U_ZERO_ERROR;
3487         }
3488         else if (uprv_strcmp(temp3, rawData2[LANG][i]) && !(uprv_strcmp(temp3, "nn") == 0 && uprv_strcmp(rawData2[VAR][i], "NY") == 0)) {
3489             log_err("  language doesn't match expected %s in in uloc_getLocaleForLCID(%#04x) = %s\n", rawData2[LANG][i], lcid, temp2);
3490         }
3491 
3492         length = uloc_getScript(temp2, temp3, UPRV_LENGTHOF(temp3), &status);
3493         if (U_FAILURE(status)) {
3494             log_err("  couldn't get script in uloc_getLocaleForLCID(%#04x) = %s, status %s\n", lcid, temp2, u_errorName(status));
3495             status = U_ZERO_ERROR;
3496         }
3497         else if (uprv_strcmp(temp3, rawData2[SCRIPT][i])) {
3498             log_err("  script doesn't match expected %s in in uloc_getLocaleForLCID(%#04x) = %s\n", rawData2[SCRIPT][i], lcid, temp2);
3499         }
3500 
3501         length = uloc_getCountry(temp2, temp3, UPRV_LENGTHOF(temp3), &status);
3502         if (U_FAILURE(status)) {
3503             log_err("  couldn't get country in uloc_getLocaleForLCID(%#04x) = %s, status %s\n", lcid, temp2, u_errorName(status));
3504             status = U_ZERO_ERROR;
3505         }
3506         else if (uprv_strlen(rawData2[CTRY][i]) && uprv_strcmp(temp3, rawData2[CTRY][i])) {
3507             log_err("  country doesn't match expected %s in in uloc_getLocaleForLCID(%#04x) = %s\n", rawData2[CTRY][i], lcid, temp2);
3508         }
3509     }
3510 
3511 }
3512 
3513 const char* const basic_maximize_data[][2] = {
3514   {
3515     "zu_Zzzz_Zz",
3516     "zu_Latn_ZA",
3517   }, {
3518     "ZU_Zz",
3519     "zu_Latn_ZA"
3520   }, {
3521     "zu_LATN",
3522     "zu_Latn_ZA"
3523   }, {
3524     "en_Zz",
3525     "en_Latn_US"
3526   }, {
3527     "en_us",
3528     "en_Latn_US"
3529   }, {
3530     "en_Kore",
3531     "en_Kore_US"
3532   }, {
3533     "en_Kore_Zz",
3534     "en_Kore_US"
3535   }, {
3536     "en_Kore_ZA",
3537     "en_Kore_ZA"
3538   }, {
3539     "en_Kore_ZA_POSIX",
3540     "en_Kore_ZA_POSIX"
3541   }, {
3542     "en_Gujr",
3543     "en_Gujr_US"
3544   }, {
3545     "en_ZA",
3546     "en_Latn_ZA"
3547   }, {
3548     "en_Gujr_Zz",
3549     "en_Gujr_US"
3550   }, {
3551     "en_Gujr_ZA",
3552     "en_Gujr_ZA"
3553   }, {
3554     "en_Gujr_ZA_POSIX",
3555     "en_Gujr_ZA_POSIX"
3556   }, {
3557     "en_US_POSIX_1901",
3558     "en_Latn_US_POSIX_1901"
3559   }, {
3560     "en_Latn__POSIX_1901",
3561     "en_Latn_US_POSIX_1901"
3562   }, {
3563     "en__POSIX_1901",
3564     "en_Latn_US_POSIX_1901"
3565   }, {
3566     "de__POSIX_1901",
3567     "de_Latn_DE_POSIX_1901"
3568   }, {
3569     "en_US_BOSTON",
3570     "en_Latn_US_BOSTON"
3571   }, {
3572     "th@calendar=buddhist",
3573     "th_Thai_TH@calendar=buddhist"
3574   }, {
3575     "ar_ZZ",
3576     "ar_Arab_EG"
3577   }, {
3578     "zh",
3579     "zh_Hans_CN"
3580   }, {
3581     "zh_TW",
3582     "zh_Hant_TW"
3583   }, {
3584     "zh_HK",
3585     "zh_Hant_HK"
3586   }, {
3587     "zh_Hant",
3588     "zh_Hant_TW"
3589   }, {
3590     "zh_Zzzz_CN",
3591     "zh_Hans_CN"
3592   }, {
3593     "und_US",
3594     "en_Latn_US"
3595   }, {
3596     "und_HK",
3597     "zh_Hant_HK"
3598   }, {
3599     "zzz",
3600     ""
3601   }, {
3602      "de_u_co_phonebk",
3603      "de_Latn_DE_U_CO_PHONEBK"
3604   }, {
3605      "de_Latn_u_co_phonebk",
3606      "de_Latn_DE_U_CO_PHONEBK"
3607   }, {
3608      "de_Latn_DE_u_co_phonebk",
3609      "de_Latn_DE_U_CO_PHONEBK"
3610   }, {
3611     "_Arab@em=emoji",
3612     "ar_Arab_EG@em=emoji"
3613   }, {
3614     "_Latn@em=emoji",
3615     "en_Latn_US@em=emoji"
3616   }, {
3617     "_Latn_DE@em=emoji",
3618     "de_Latn_DE@em=emoji"
3619   }, {
3620     "_Zzzz_DE@em=emoji",
3621     "de_Latn_DE@em=emoji"
3622   }, {
3623     "_DE@em=emoji",
3624     "de_Latn_DE@em=emoji"
3625   }
3626 };
3627 
3628 const char* const basic_minimize_data[][2] = {
3629   {
3630     "en_Latn_US",
3631     "en"
3632   }, {
3633     "en_Latn_US_POSIX_1901",
3634     "en__POSIX_1901"
3635   }, {
3636     "EN_Latn_US_POSIX_1901",
3637     "en__POSIX_1901"
3638   }, {
3639     "en_Zzzz_US_POSIX_1901",
3640     "en__POSIX_1901"
3641   }, {
3642     "de_Latn_DE_POSIX_1901",
3643     "de__POSIX_1901"
3644   }, {
3645     "",
3646     ""
3647   }, {
3648     "en_Latn_US@calendar=gregorian",
3649     "en@calendar=gregorian"
3650   }
3651 };
3652 
3653 const char* const full_data[][3] = {
3654   {
3655     /*   "FROM", */
3656     /*   "ADD-LIKELY", */
3657     /*   "REMOVE-LIKELY" */
3658     /* }, { */
3659     "aa",
3660     "aa_Latn_ET",
3661     "aa"
3662   }, {
3663     "af",
3664     "af_Latn_ZA",
3665     "af"
3666   }, {
3667     "ak",
3668     "ak_Latn_GH",
3669     "ak"
3670   }, {
3671     "am",
3672     "am_Ethi_ET",
3673     "am"
3674   }, {
3675     "ar",
3676     "ar_Arab_EG",
3677     "ar"
3678   }, {
3679     "as",
3680     "as_Beng_IN",
3681     "as"
3682   }, {
3683     "az",
3684     "az_Latn_AZ",
3685     "az"
3686   }, {
3687     "be",
3688     "be_Cyrl_BY",
3689     "be"
3690   }, {
3691     "bg",
3692     "bg_Cyrl_BG",
3693     "bg"
3694   }, {
3695     "bn",
3696     "bn_Beng_BD",
3697     "bn"
3698   }, {
3699     "bo",
3700     "bo_Tibt_CN",
3701     "bo"
3702   }, {
3703     "bs",
3704     "bs_Latn_BA",
3705     "bs"
3706   }, {
3707     "ca",
3708     "ca_Latn_ES",
3709     "ca"
3710   }, {
3711     "ch",
3712     "ch_Latn_GU",
3713     "ch"
3714   }, {
3715     "chk",
3716     "chk_Latn_FM",
3717     "chk"
3718   }, {
3719     "cs",
3720     "cs_Latn_CZ",
3721     "cs"
3722   }, {
3723     "cy",
3724     "cy_Latn_GB",
3725     "cy"
3726   }, {
3727     "da",
3728     "da_Latn_DK",
3729     "da"
3730   }, {
3731     "de",
3732     "de_Latn_DE",
3733     "de"
3734   }, {
3735     "dv",
3736     "dv_Thaa_MV",
3737     "dv"
3738   }, {
3739     "dz",
3740     "dz_Tibt_BT",
3741     "dz"
3742   }, {
3743     "ee",
3744     "ee_Latn_GH",
3745     "ee"
3746   }, {
3747     "el",
3748     "el_Grek_GR",
3749     "el"
3750   }, {
3751     "en",
3752     "en_Latn_US",
3753     "en"
3754   }, {
3755     "es",
3756     "es_Latn_ES",
3757     "es"
3758   }, {
3759     "et",
3760     "et_Latn_EE",
3761     "et"
3762   }, {
3763     "eu",
3764     "eu_Latn_ES",
3765     "eu"
3766   }, {
3767     "fa",
3768     "fa_Arab_IR",
3769     "fa"
3770   }, {
3771     "fi",
3772     "fi_Latn_FI",
3773     "fi"
3774   }, {
3775     "fil",
3776     "fil_Latn_PH",
3777     "fil"
3778   }, {
3779     "fo",
3780     "fo_Latn_FO",
3781     "fo"
3782   }, {
3783     "fr",
3784     "fr_Latn_FR",
3785     "fr"
3786   }, {
3787     "fur",
3788     "fur_Latn_IT",
3789     "fur"
3790   }, {
3791     "ga",
3792     "ga_Latn_IE",
3793     "ga"
3794   }, {
3795     "gaa",
3796     "gaa_Latn_GH",
3797     "gaa"
3798   }, {
3799     "gl",
3800     "gl_Latn_ES",
3801     "gl"
3802   }, {
3803     "gn",
3804     "gn_Latn_PY",
3805     "gn"
3806   }, {
3807     "gu",
3808     "gu_Gujr_IN",
3809     "gu"
3810   }, {
3811     "ha",
3812     "ha_Latn_NG",
3813     "ha"
3814   }, {
3815     "haw",
3816     "haw_Latn_US",
3817     "haw"
3818   }, {
3819     "he",
3820     "he_Hebr_IL",
3821     "he"
3822   }, {
3823     "hi",
3824     "hi_Deva_IN",
3825     "hi"
3826   }, {
3827     "hr",
3828     "hr_Latn_HR",
3829     "hr"
3830   }, {
3831     "ht",
3832     "ht_Latn_HT",
3833     "ht"
3834   }, {
3835     "hu",
3836     "hu_Latn_HU",
3837     "hu"
3838   }, {
3839     "hy",
3840     "hy_Armn_AM",
3841     "hy"
3842   }, {
3843     "id",
3844     "id_Latn_ID",
3845     "id"
3846   }, {
3847     "ig",
3848     "ig_Latn_NG",
3849     "ig"
3850   }, {
3851     "ii",
3852     "ii_Yiii_CN",
3853     "ii"
3854   }, {
3855     "is",
3856     "is_Latn_IS",
3857     "is"
3858   }, {
3859     "it",
3860     "it_Latn_IT",
3861     "it"
3862   }, {
3863     "ja",
3864     "ja_Jpan_JP",
3865     "ja"
3866   }, {
3867     "ka",
3868     "ka_Geor_GE",
3869     "ka"
3870   }, {
3871     "kaj",
3872     "kaj_Latn_NG",
3873     "kaj"
3874   }, {
3875     "kam",
3876     "kam_Latn_KE",
3877     "kam"
3878   }, {
3879     "kk",
3880     "kk_Cyrl_KZ",
3881     "kk"
3882   }, {
3883     "kl",
3884     "kl_Latn_GL",
3885     "kl"
3886   }, {
3887     "km",
3888     "km_Khmr_KH",
3889     "km"
3890   }, {
3891     "kn",
3892     "kn_Knda_IN",
3893     "kn"
3894   }, {
3895     "ko",
3896     "ko_Kore_KR",
3897     "ko"
3898   }, {
3899     "kok",
3900     "kok_Deva_IN",
3901     "kok"
3902   }, {
3903     "kpe",
3904     "kpe_Latn_LR",
3905     "kpe"
3906   }, {
3907     "ku",
3908     "ku_Latn_TR",
3909     "ku"
3910   }, {
3911     "ky",
3912     "ky_Cyrl_KG",
3913     "ky"
3914   }, {
3915     "la",
3916     "la_Latn_VA",
3917     "la"
3918   }, {
3919     "ln",
3920     "ln_Latn_CD",
3921     "ln"
3922   }, {
3923     "lo",
3924     "lo_Laoo_LA",
3925     "lo"
3926   }, {
3927     "lt",
3928     "lt_Latn_LT",
3929     "lt"
3930   }, {
3931     "lv",
3932     "lv_Latn_LV",
3933     "lv"
3934   }, {
3935     "mg",
3936     "mg_Latn_MG",
3937     "mg"
3938   }, {
3939     "mh",
3940     "mh_Latn_MH",
3941     "mh"
3942   }, {
3943     "mk",
3944     "mk_Cyrl_MK",
3945     "mk"
3946   }, {
3947     "ml",
3948     "ml_Mlym_IN",
3949     "ml"
3950   }, {
3951     "mn",
3952     "mn_Cyrl_MN",
3953     "mn"
3954   }, {
3955     "mr",
3956     "mr_Deva_IN",
3957     "mr"
3958   }, {
3959     "ms",
3960     "ms_Latn_MY",
3961     "ms"
3962   }, {
3963     "mt",
3964     "mt_Latn_MT",
3965     "mt"
3966   }, {
3967     "my",
3968     "my_Mymr_MM",
3969     "my"
3970   }, {
3971     "na",
3972     "na_Latn_NR",
3973     "na"
3974   }, {
3975     "ne",
3976     "ne_Deva_NP",
3977     "ne"
3978   }, {
3979     "niu",
3980     "niu_Latn_NU",
3981     "niu"
3982   }, {
3983     "nl",
3984     "nl_Latn_NL",
3985     "nl"
3986   }, {
3987     "nn",
3988     "nn_Latn_NO",
3989     "nn"
3990   }, {
3991     "nr",
3992     "nr_Latn_ZA",
3993     "nr"
3994   }, {
3995     "nso",
3996     "nso_Latn_ZA",
3997     "nso"
3998   }, {
3999     "ny",
4000     "ny_Latn_MW",
4001     "ny"
4002   }, {
4003     "om",
4004     "om_Latn_ET",
4005     "om"
4006   }, {
4007     "or",
4008     "or_Orya_IN",
4009     "or"
4010   }, {
4011     "pa",
4012     "pa_Guru_IN",
4013     "pa"
4014   }, {
4015     "pa_Arab",
4016     "pa_Arab_PK",
4017     "pa_PK"
4018   }, {
4019     "pa_PK",
4020     "pa_Arab_PK",
4021     "pa_PK"
4022   }, {
4023     "pap",
4024     "pap_Latn_AW",
4025     "pap"
4026   }, {
4027     "pau",
4028     "pau_Latn_PW",
4029     "pau"
4030   }, {
4031     "pl",
4032     "pl_Latn_PL",
4033     "pl"
4034   }, {
4035     "ps",
4036     "ps_Arab_AF",
4037     "ps"
4038   }, {
4039     "pt",
4040     "pt_Latn_BR",
4041     "pt"
4042   }, {
4043     "rn",
4044     "rn_Latn_BI",
4045     "rn"
4046   }, {
4047     "ro",
4048     "ro_Latn_RO",
4049     "ro"
4050   }, {
4051     "ru",
4052     "ru_Cyrl_RU",
4053     "ru"
4054   }, {
4055     "rw",
4056     "rw_Latn_RW",
4057     "rw"
4058   }, {
4059     "sa",
4060     "sa_Deva_IN",
4061     "sa"
4062   }, {
4063     "se",
4064     "se_Latn_NO",
4065     "se"
4066   }, {
4067     "sg",
4068     "sg_Latn_CF",
4069     "sg"
4070   }, {
4071     "si",
4072     "si_Sinh_LK",
4073     "si"
4074   }, {
4075     "sid",
4076     "sid_Latn_ET",
4077     "sid"
4078   }, {
4079     "sk",
4080     "sk_Latn_SK",
4081     "sk"
4082   }, {
4083     "sl",
4084     "sl_Latn_SI",
4085     "sl"
4086   }, {
4087     "sm",
4088     "sm_Latn_WS",
4089     "sm"
4090   }, {
4091     "so",
4092     "so_Latn_SO",
4093     "so"
4094   }, {
4095     "sq",
4096     "sq_Latn_AL",
4097     "sq"
4098   }, {
4099     "sr",
4100     "sr_Cyrl_RS",
4101     "sr"
4102   }, {
4103     "ss",
4104     "ss_Latn_ZA",
4105     "ss"
4106   }, {
4107     "st",
4108     "st_Latn_ZA",
4109     "st"
4110   }, {
4111     "sv",
4112     "sv_Latn_SE",
4113     "sv"
4114   }, {
4115     "sw",
4116     "sw_Latn_TZ",
4117     "sw"
4118   }, {
4119     "ta",
4120     "ta_Taml_IN",
4121     "ta"
4122   }, {
4123     "te",
4124     "te_Telu_IN",
4125     "te"
4126   }, {
4127     "tet",
4128     "tet_Latn_TL",
4129     "tet"
4130   }, {
4131     "tg",
4132     "tg_Cyrl_TJ",
4133     "tg"
4134   }, {
4135     "th",
4136     "th_Thai_TH",
4137     "th"
4138   }, {
4139     "ti",
4140     "ti_Ethi_ET",
4141     "ti"
4142   }, {
4143     "tig",
4144     "tig_Ethi_ER",
4145     "tig"
4146   }, {
4147     "tk",
4148     "tk_Latn_TM",
4149     "tk"
4150   }, {
4151     "tkl",
4152     "tkl_Latn_TK",
4153     "tkl"
4154   }, {
4155     "tn",
4156     "tn_Latn_ZA",
4157     "tn"
4158   }, {
4159     "to",
4160     "to_Latn_TO",
4161     "to"
4162   }, {
4163     "tpi",
4164     "tpi_Latn_PG",
4165     "tpi"
4166   }, {
4167     "tr",
4168     "tr_Latn_TR",
4169     "tr"
4170   }, {
4171     "ts",
4172     "ts_Latn_ZA",
4173     "ts"
4174   }, {
4175     "tt",
4176     "tt_Cyrl_RU",
4177     "tt"
4178   }, {
4179     "tvl",
4180     "tvl_Latn_TV",
4181     "tvl"
4182   }, {
4183     "ty",
4184     "ty_Latn_PF",
4185     "ty"
4186   }, {
4187     "uk",
4188     "uk_Cyrl_UA",
4189     "uk"
4190   }, {
4191     "und",
4192     "en_Latn_US",
4193     "en"
4194   }, {
4195     "und_AD",
4196     "ca_Latn_AD",
4197     "ca_AD"
4198   }, {
4199     "und_AE",
4200     "ar_Arab_AE",
4201     "ar_AE"
4202   }, {
4203     "und_AF",
4204     "fa_Arab_AF",
4205     "fa_AF"
4206   }, {
4207     "und_AL",
4208     "sq_Latn_AL",
4209     "sq"
4210   }, {
4211     "und_AM",
4212     "hy_Armn_AM",
4213     "hy"
4214   }, {
4215     "und_AO",
4216     "pt_Latn_AO",
4217     "pt_AO"
4218   }, {
4219     "und_AR",
4220     "es_Latn_AR",
4221     "es_AR"
4222   }, {
4223     "und_AS",
4224     "sm_Latn_AS",
4225     "sm_AS"
4226   }, {
4227     "und_AT",
4228     "de_Latn_AT",
4229     "de_AT"
4230   }, {
4231     "und_AW",
4232     "nl_Latn_AW",
4233     "nl_AW"
4234   }, {
4235     "und_AX",
4236     "sv_Latn_AX",
4237     "sv_AX"
4238   }, {
4239     "und_AZ",
4240     "az_Latn_AZ",
4241     "az"
4242   }, {
4243     "und_Arab",
4244     "ar_Arab_EG",
4245     "ar"
4246   }, {
4247     "und_Arab_IN",
4248     "ur_Arab_IN",
4249     "ur_IN"
4250   }, {
4251     "und_Arab_PK",
4252     "ur_Arab_PK",
4253     "ur"
4254   }, {
4255     "und_Arab_SN",
4256     "ar_Arab_SN",
4257     "ar_SN"
4258   }, {
4259     "und_Armn",
4260     "hy_Armn_AM",
4261     "hy"
4262   }, {
4263     "und_BA",
4264     "bs_Latn_BA",
4265     "bs"
4266   }, {
4267     "und_BD",
4268     "bn_Beng_BD",
4269     "bn"
4270   }, {
4271     "und_BE",
4272     "nl_Latn_BE",
4273     "nl_BE"
4274   }, {
4275     "und_BF",
4276     "fr_Latn_BF",
4277     "fr_BF"
4278   }, {
4279     "und_BG",
4280     "bg_Cyrl_BG",
4281     "bg"
4282   }, {
4283     "und_BH",
4284     "ar_Arab_BH",
4285     "ar_BH"
4286   }, {
4287     "und_BI",
4288     "rn_Latn_BI",
4289     "rn"
4290   }, {
4291     "und_BJ",
4292     "fr_Latn_BJ",
4293     "fr_BJ"
4294   }, {
4295     "und_BN",
4296     "ms_Latn_BN",
4297     "ms_BN"
4298   }, {
4299     "und_BO",
4300     "es_Latn_BO",
4301     "es_BO"
4302   }, {
4303     "und_BR",
4304     "pt_Latn_BR",
4305     "pt"
4306   }, {
4307     "und_BT",
4308     "dz_Tibt_BT",
4309     "dz"
4310   }, {
4311     "und_BY",
4312     "be_Cyrl_BY",
4313     "be"
4314   }, {
4315     "und_Beng",
4316     "bn_Beng_BD",
4317     "bn"
4318   }, {
4319     "und_Beng_IN",
4320     "bn_Beng_IN",
4321     "bn_IN"
4322   }, {
4323     "und_CD",
4324     "sw_Latn_CD",
4325     "sw_CD"
4326   }, {
4327     "und_CF",
4328     "fr_Latn_CF",
4329     "fr_CF"
4330   }, {
4331     "und_CG",
4332     "fr_Latn_CG",
4333     "fr_CG"
4334   }, {
4335     "und_CH",
4336     "de_Latn_CH",
4337     "de_CH"
4338   }, {
4339     "und_CI",
4340     "fr_Latn_CI",
4341     "fr_CI"
4342   }, {
4343     "und_CL",
4344     "es_Latn_CL",
4345     "es_CL"
4346   }, {
4347     "und_CM",
4348     "fr_Latn_CM",
4349     "fr_CM"
4350   }, {
4351     "und_CN",
4352     "zh_Hans_CN",
4353     "zh"
4354   }, {
4355     "und_CO",
4356     "es_Latn_CO",
4357     "es_CO"
4358   }, {
4359     "und_CR",
4360     "es_Latn_CR",
4361     "es_CR"
4362   }, {
4363     "und_CU",
4364     "es_Latn_CU",
4365     "es_CU"
4366   }, {
4367     "und_CV",
4368     "pt_Latn_CV",
4369     "pt_CV"
4370   }, {
4371     "und_CY",
4372     "el_Grek_CY",
4373     "el_CY"
4374   }, {
4375     "und_CZ",
4376     "cs_Latn_CZ",
4377     "cs"
4378   }, {
4379     "und_Cher",
4380     "chr_Cher_US",
4381     "chr"
4382   }, {
4383     "und_Cyrl",
4384     "ru_Cyrl_RU",
4385     "ru"
4386   }, {
4387     "und_Cyrl_KZ",
4388     "ru_Cyrl_KZ",
4389     "ru_KZ"
4390   }, {
4391     "und_DE",
4392     "de_Latn_DE",
4393     "de"
4394   }, {
4395     "und_DJ",
4396     "aa_Latn_DJ",
4397     "aa_DJ"
4398   }, {
4399     "und_DK",
4400     "da_Latn_DK",
4401     "da"
4402   }, {
4403     "und_DO",
4404     "es_Latn_DO",
4405     "es_DO"
4406   }, {
4407     "und_DZ",
4408     "ar_Arab_DZ",
4409     "ar_DZ"
4410   }, {
4411     "und_Deva",
4412     "hi_Deva_IN",
4413     "hi"
4414   }, {
4415     "und_EC",
4416     "es_Latn_EC",
4417     "es_EC"
4418   }, {
4419     "und_EE",
4420     "et_Latn_EE",
4421     "et"
4422   }, {
4423     "und_EG",
4424     "ar_Arab_EG",
4425     "ar"
4426   }, {
4427     "und_EH",
4428     "ar_Arab_EH",
4429     "ar_EH"
4430   }, {
4431     "und_ER",
4432     "ti_Ethi_ER",
4433     "ti_ER"
4434   }, {
4435     "und_ES",
4436     "es_Latn_ES",
4437     "es"
4438   }, {
4439     "und_ET",
4440     "am_Ethi_ET",
4441     "am"
4442   }, {
4443     "und_Ethi",
4444     "am_Ethi_ET",
4445     "am"
4446   }, {
4447     "und_Ethi_ER",
4448     "am_Ethi_ER",
4449     "am_ER"
4450   }, {
4451     "und_FI",
4452     "fi_Latn_FI",
4453     "fi"
4454   }, {
4455     "und_FM",
4456     "en_Latn_FM",
4457     "en_FM"
4458   }, {
4459     "und_FO",
4460     "fo_Latn_FO",
4461     "fo"
4462   }, {
4463     "und_FR",
4464     "fr_Latn_FR",
4465     "fr"
4466   }, {
4467     "und_GA",
4468     "fr_Latn_GA",
4469     "fr_GA"
4470   }, {
4471     "und_GE",
4472     "ka_Geor_GE",
4473     "ka"
4474   }, {
4475     "und_GF",
4476     "fr_Latn_GF",
4477     "fr_GF"
4478   }, {
4479     "und_GL",
4480     "kl_Latn_GL",
4481     "kl"
4482   }, {
4483     "und_GN",
4484     "fr_Latn_GN",
4485     "fr_GN"
4486   }, {
4487     "und_GP",
4488     "fr_Latn_GP",
4489     "fr_GP"
4490   }, {
4491     "und_GQ",
4492     "es_Latn_GQ",
4493     "es_GQ"
4494   }, {
4495     "und_GR",
4496     "el_Grek_GR",
4497     "el"
4498   }, {
4499     "und_GT",
4500     "es_Latn_GT",
4501     "es_GT"
4502   }, {
4503     "und_GU",
4504     "en_Latn_GU",
4505     "en_GU"
4506   }, {
4507     "und_GW",
4508     "pt_Latn_GW",
4509     "pt_GW"
4510   }, {
4511     "und_Geor",
4512     "ka_Geor_GE",
4513     "ka"
4514   }, {
4515     "und_Grek",
4516     "el_Grek_GR",
4517     "el"
4518   }, {
4519     "und_Gujr",
4520     "gu_Gujr_IN",
4521     "gu"
4522   }, {
4523     "und_Guru",
4524     "pa_Guru_IN",
4525     "pa"
4526   }, {
4527     "und_HK",
4528     "zh_Hant_HK",
4529     "zh_HK"
4530   }, {
4531     "und_HN",
4532     "es_Latn_HN",
4533     "es_HN"
4534   }, {
4535     "und_HR",
4536     "hr_Latn_HR",
4537     "hr"
4538   }, {
4539     "und_HT",
4540     "ht_Latn_HT",
4541     "ht"
4542   }, {
4543     "und_HU",
4544     "hu_Latn_HU",
4545     "hu"
4546   }, {
4547     "und_Hani",
4548     "zh_Hani_CN",
4549     "zh_Hani"
4550   }, {
4551     "und_Hans",
4552     "zh_Hans_CN",
4553     "zh"
4554   }, {
4555     "und_Hant",
4556     "zh_Hant_TW",
4557     "zh_TW"
4558   }, {
4559     "und_Hebr",
4560     "he_Hebr_IL",
4561     "he"
4562   }, {
4563     "und_IL",
4564     "he_Hebr_IL",
4565     "he"
4566   }, {
4567     "und_IN",
4568     "hi_Deva_IN",
4569     "hi"
4570   }, {
4571     "und_IQ",
4572     "ar_Arab_IQ",
4573     "ar_IQ"
4574   }, {
4575     "und_IR",
4576     "fa_Arab_IR",
4577     "fa"
4578   }, {
4579     "und_IS",
4580     "is_Latn_IS",
4581     "is"
4582   }, {
4583     "und_IT",
4584     "it_Latn_IT",
4585     "it"
4586   }, {
4587     "und_JO",
4588     "ar_Arab_JO",
4589     "ar_JO"
4590   }, {
4591     "und_JP",
4592     "ja_Jpan_JP",
4593     "ja"
4594   }, {
4595     "und_Jpan",
4596     "ja_Jpan_JP",
4597     "ja"
4598   }, {
4599     "und_KG",
4600     "ky_Cyrl_KG",
4601     "ky"
4602   }, {
4603     "und_KH",
4604     "km_Khmr_KH",
4605     "km"
4606   }, {
4607     "und_KM",
4608     "ar_Arab_KM",
4609     "ar_KM"
4610   }, {
4611     "und_KP",
4612     "ko_Kore_KP",
4613     "ko_KP"
4614   }, {
4615     "und_KR",
4616     "ko_Kore_KR",
4617     "ko"
4618   }, {
4619     "und_KW",
4620     "ar_Arab_KW",
4621     "ar_KW"
4622   }, {
4623     "und_KZ",
4624     "ru_Cyrl_KZ",
4625     "ru_KZ"
4626   }, {
4627     "und_Khmr",
4628     "km_Khmr_KH",
4629     "km"
4630   }, {
4631     "und_Knda",
4632     "kn_Knda_IN",
4633     "kn"
4634   }, {
4635     "und_Kore",
4636     "ko_Kore_KR",
4637     "ko"
4638   }, {
4639     "und_LA",
4640     "lo_Laoo_LA",
4641     "lo"
4642   }, {
4643     "und_LB",
4644     "ar_Arab_LB",
4645     "ar_LB"
4646   }, {
4647     "und_LI",
4648     "de_Latn_LI",
4649     "de_LI"
4650   }, {
4651     "und_LK",
4652     "si_Sinh_LK",
4653     "si"
4654   }, {
4655     "und_LS",
4656     "st_Latn_LS",
4657     "st_LS"
4658   }, {
4659     "und_LT",
4660     "lt_Latn_LT",
4661     "lt"
4662   }, {
4663     "und_LU",
4664     "fr_Latn_LU",
4665     "fr_LU"
4666   }, {
4667     "und_LV",
4668     "lv_Latn_LV",
4669     "lv"
4670   }, {
4671     "und_LY",
4672     "ar_Arab_LY",
4673     "ar_LY"
4674   }, {
4675     "und_Laoo",
4676     "lo_Laoo_LA",
4677     "lo"
4678   }, {
4679     "und_Latn_ES",
4680     "es_Latn_ES",
4681     "es"
4682   }, {
4683     "und_Latn_ET",
4684     "en_Latn_ET",
4685     "en_ET"
4686   }, {
4687     "und_Latn_GB",
4688     "en_Latn_GB",
4689     "en_GB"
4690   }, {
4691     "und_Latn_GH",
4692     "ak_Latn_GH",
4693     "ak"
4694   }, {
4695     "und_Latn_ID",
4696     "id_Latn_ID",
4697     "id"
4698   }, {
4699     "und_Latn_IT",
4700     "it_Latn_IT",
4701     "it"
4702   }, {
4703     "und_Latn_NG",
4704     "en_Latn_NG",
4705     "en_NG"
4706   }, {
4707     "und_Latn_TR",
4708     "tr_Latn_TR",
4709     "tr"
4710   }, {
4711     "und_Latn_ZA",
4712     "en_Latn_ZA",
4713     "en_ZA"
4714   }, {
4715     "und_MA",
4716     "ar_Arab_MA",
4717     "ar_MA"
4718   }, {
4719     "und_MC",
4720     "fr_Latn_MC",
4721     "fr_MC"
4722   }, {
4723     "und_MD",
4724     "ro_Latn_MD",
4725     "ro_MD"
4726   }, {
4727     "und_ME",
4728     "sr_Latn_ME",
4729     "sr_ME"
4730   }, {
4731     "und_MG",
4732     "mg_Latn_MG",
4733     "mg"
4734   }, {
4735     "und_MH",
4736     "en_Latn_MH",
4737     "en_MH"
4738   }, {
4739     "und_MK",
4740     "mk_Cyrl_MK",
4741     "mk"
4742   }, {
4743     "und_ML",
4744     "bm_Latn_ML",
4745     "bm"
4746   }, {
4747     "und_MM",
4748     "my_Mymr_MM",
4749     "my"
4750   }, {
4751     "und_MN",
4752     "mn_Cyrl_MN",
4753     "mn"
4754   }, {
4755     "und_MO",
4756     "zh_Hant_MO",
4757     "zh_MO"
4758   }, {
4759     "und_MQ",
4760     "fr_Latn_MQ",
4761     "fr_MQ"
4762   }, {
4763     "und_MR",
4764     "ar_Arab_MR",
4765     "ar_MR"
4766   }, {
4767     "und_MT",
4768     "mt_Latn_MT",
4769     "mt"
4770   }, {
4771     "und_MV",
4772     "dv_Thaa_MV",
4773     "dv"
4774   }, {
4775     "und_MW",
4776     "en_Latn_MW",
4777     "en_MW"
4778   }, {
4779     "und_MX",
4780     "es_Latn_MX",
4781     "es_MX"
4782   }, {
4783     "und_MY",
4784     "ms_Latn_MY",
4785     "ms"
4786   }, {
4787     "und_MZ",
4788     "pt_Latn_MZ",
4789     "pt_MZ"
4790   }, {
4791     "und_Mlym",
4792     "ml_Mlym_IN",
4793     "ml"
4794   }, {
4795     "und_Mymr",
4796     "my_Mymr_MM",
4797     "my"
4798   }, {
4799     "und_NC",
4800     "fr_Latn_NC",
4801     "fr_NC"
4802   }, {
4803     "und_NE",
4804     "ha_Latn_NE",
4805     "ha_NE"
4806   }, {
4807     "und_NG",
4808     "en_Latn_NG",
4809     "en_NG"
4810   }, {
4811     "und_NI",
4812     "es_Latn_NI",
4813     "es_NI"
4814   }, {
4815     "und_NL",
4816     "nl_Latn_NL",
4817     "nl"
4818   }, {
4819     "und_NO",
4820     "no_Latn_NO",  /* Google patch */
4821     "no"  /* Google patch */
4822   }, {
4823     "und_NP",
4824     "ne_Deva_NP",
4825     "ne"
4826   }, {
4827     "und_NR",
4828     "en_Latn_NR",
4829     "en_NR"
4830   }, {
4831     "und_NU",
4832     "en_Latn_NU",
4833     "en_NU"
4834   }, {
4835     "und_OM",
4836     "ar_Arab_OM",
4837     "ar_OM"
4838   }, {
4839     "und_Orya",
4840     "or_Orya_IN",
4841     "or"
4842   }, {
4843     "und_PA",
4844     "es_Latn_PA",
4845     "es_PA"
4846   }, {
4847     "und_PE",
4848     "es_Latn_PE",
4849     "es_PE"
4850   }, {
4851     "und_PF",
4852     "fr_Latn_PF",
4853     "fr_PF"
4854   }, {
4855     "und_PG",
4856     "tpi_Latn_PG",
4857     "tpi"
4858   }, {
4859     "und_PH",
4860     "fil_Latn_PH",
4861     "fil"
4862   }, {
4863     "und_PL",
4864     "pl_Latn_PL",
4865     "pl"
4866   }, {
4867     "und_PM",
4868     "fr_Latn_PM",
4869     "fr_PM"
4870   }, {
4871     "und_PR",
4872     "es_Latn_PR",
4873     "es_PR"
4874   }, {
4875     "und_PS",
4876     "ar_Arab_PS",
4877     "ar_PS"
4878   }, {
4879     "und_PT",
4880     "pt_Latn_PT",
4881     "pt_PT"
4882   }, {
4883     "und_PW",
4884     "pau_Latn_PW",
4885     "pau"
4886   }, {
4887     "und_PY",
4888     "gn_Latn_PY",
4889     "gn"
4890   }, {
4891     "und_QA",
4892     "ar_Arab_QA",
4893     "ar_QA"
4894   }, {
4895     "und_RE",
4896     "fr_Latn_RE",
4897     "fr_RE"
4898   }, {
4899     "und_RO",
4900     "ro_Latn_RO",
4901     "ro"
4902   }, {
4903     "und_RS",
4904     "sr_Cyrl_RS",
4905     "sr"
4906   }, {
4907     "und_RU",
4908     "ru_Cyrl_RU",
4909     "ru"
4910   }, {
4911     "und_RW",
4912     "rw_Latn_RW",
4913     "rw"
4914   }, {
4915     "und_SA",
4916     "ar_Arab_SA",
4917     "ar_SA"
4918   }, {
4919     "und_SD",
4920     "ar_Arab_SD",
4921     "ar_SD"
4922   }, {
4923     "und_SE",
4924     "sv_Latn_SE",
4925     "sv"
4926   }, {
4927     "und_SG",
4928     "en_Latn_SG",
4929     "en_SG"
4930   }, {
4931     "und_SI",
4932     "sl_Latn_SI",
4933     "sl"
4934   }, {
4935     "und_SJ",
4936     "no_Latn_SJ",  /* Google patch */
4937     "no_SJ"  /* Google patch */
4938   }, {
4939     "und_SK",
4940     "sk_Latn_SK",
4941     "sk"
4942   }, {
4943     "und_SM",
4944     "it_Latn_SM",
4945     "it_SM"
4946   }, {
4947     "und_SN",
4948     "fr_Latn_SN",
4949     "fr_SN"
4950   }, {
4951     "und_SO",
4952     "so_Latn_SO",
4953     "so"
4954   }, {
4955     "und_SR",
4956     "nl_Latn_SR",
4957     "nl_SR"
4958   }, {
4959     "und_ST",
4960     "pt_Latn_ST",
4961     "pt_ST"
4962   }, {
4963     "und_SV",
4964     "es_Latn_SV",
4965     "es_SV"
4966   }, {
4967     "und_SY",
4968     "ar_Arab_SY",
4969     "ar_SY"
4970   }, {
4971     "und_Sinh",
4972     "si_Sinh_LK",
4973     "si"
4974   }, {
4975     "und_TD",
4976     "fr_Latn_TD",
4977     "fr_TD"
4978   }, {
4979     "und_TG",
4980     "fr_Latn_TG",
4981     "fr_TG"
4982   }, {
4983     "und_TH",
4984     "th_Thai_TH",
4985     "th"
4986   }, {
4987     "und_TJ",
4988     "tg_Cyrl_TJ",
4989     "tg"
4990   }, {
4991     "und_TK",
4992     "tkl_Latn_TK",
4993     "tkl"
4994   }, {
4995     "und_TL",
4996     "pt_Latn_TL",
4997     "pt_TL"
4998   }, {
4999     "und_TM",
5000     "tk_Latn_TM",
5001     "tk"
5002   }, {
5003     "und_TN",
5004     "ar_Arab_TN",
5005     "ar_TN"
5006   }, {
5007     "und_TO",
5008     "to_Latn_TO",
5009     "to"
5010   }, {
5011     "und_TR",
5012     "tr_Latn_TR",
5013     "tr"
5014   }, {
5015     "und_TV",
5016     "tvl_Latn_TV",
5017     "tvl"
5018   }, {
5019     "und_TW",
5020     "zh_Hant_TW",
5021     "zh_TW"
5022   }, {
5023     "und_Taml",
5024     "ta_Taml_IN",
5025     "ta"
5026   }, {
5027     "und_Telu",
5028     "te_Telu_IN",
5029     "te"
5030   }, {
5031     "und_Thaa",
5032     "dv_Thaa_MV",
5033     "dv"
5034   }, {
5035     "und_Thai",
5036     "th_Thai_TH",
5037     "th"
5038   }, {
5039     "und_Tibt",
5040     "bo_Tibt_CN",
5041     "bo"
5042   }, {
5043     "und_UA",
5044     "uk_Cyrl_UA",
5045     "uk"
5046   }, {
5047     "und_UY",
5048     "es_Latn_UY",
5049     "es_UY"
5050   }, {
5051     "und_UZ",
5052     "uz_Latn_UZ",
5053     "uz"
5054   }, {
5055     "und_VA",
5056     "it_Latn_VA",
5057     "it_VA"
5058   }, {
5059     "und_VE",
5060     "es_Latn_VE",
5061     "es_VE"
5062   }, {
5063     "und_VN",
5064     "vi_Latn_VN",
5065     "vi"
5066   }, {
5067     "und_VU",
5068     "bi_Latn_VU",
5069     "bi"
5070   }, {
5071     "und_WF",
5072     "fr_Latn_WF",
5073     "fr_WF"
5074   }, {
5075     "und_WS",
5076     "sm_Latn_WS",
5077     "sm"
5078   }, {
5079     "und_YE",
5080     "ar_Arab_YE",
5081     "ar_YE"
5082   }, {
5083     "und_YT",
5084     "fr_Latn_YT",
5085     "fr_YT"
5086   }, {
5087     "und_Yiii",
5088     "ii_Yiii_CN",
5089     "ii"
5090   }, {
5091     "ur",
5092     "ur_Arab_PK",
5093     "ur"
5094   }, {
5095     "uz",
5096     "uz_Latn_UZ",
5097     "uz"
5098   }, {
5099     "uz_AF",
5100     "uz_Arab_AF",
5101     "uz_AF"
5102   }, {
5103     "uz_Arab",
5104     "uz_Arab_AF",
5105     "uz_AF"
5106   }, {
5107     "ve",
5108     "ve_Latn_ZA",
5109     "ve"
5110   }, {
5111     "vi",
5112     "vi_Latn_VN",
5113     "vi"
5114   }, {
5115     "wal",
5116     "wal_Ethi_ET",
5117     "wal"
5118   }, {
5119     "wo",
5120     "wo_Latn_SN",
5121     "wo"
5122   }, {
5123     "xh",
5124     "xh_Latn_ZA",
5125     "xh"
5126   }, {
5127     "yo",
5128     "yo_Latn_NG",
5129     "yo"
5130   }, {
5131     "zh",
5132     "zh_Hans_CN",
5133     "zh"
5134   }, {
5135     "zh_HK",
5136     "zh_Hant_HK",
5137     "zh_HK"
5138   }, {
5139     "zh_Hani",
5140     "zh_Hani_CN", /* changed due to cldrbug 6204, may be an error */
5141     "zh_Hani", /* changed due to cldrbug 6204, may be an error */
5142   }, {
5143     "zh_Hant",
5144     "zh_Hant_TW",
5145     "zh_TW"
5146   }, {
5147     "zh_MO",
5148     "zh_Hant_MO",
5149     "zh_MO"
5150   }, {
5151     "zh_TW",
5152     "zh_Hant_TW",
5153     "zh_TW"
5154   }, {
5155     "zu",
5156     "zu_Latn_ZA",
5157     "zu"
5158   }, {
5159     "und",
5160     "en_Latn_US",
5161     "en"
5162   }, {
5163     "und_ZZ",
5164     "en_Latn_US",
5165     "en"
5166   }, {
5167     "und_CN",
5168     "zh_Hans_CN",
5169     "zh"
5170   }, {
5171     "und_TW",
5172     "zh_Hant_TW",
5173     "zh_TW"
5174   }, {
5175     "und_HK",
5176     "zh_Hant_HK",
5177     "zh_HK"
5178   }, {
5179     "und_AQ",
5180     "_Latn_AQ",
5181     "_AQ"
5182   }, {
5183     "und_Zzzz",
5184     "en_Latn_US",
5185     "en"
5186   }, {
5187     "und_Zzzz_ZZ",
5188     "en_Latn_US",
5189     "en"
5190   }, {
5191     "und_Zzzz_CN",
5192     "zh_Hans_CN",
5193     "zh"
5194   }, {
5195     "und_Zzzz_TW",
5196     "zh_Hant_TW",
5197     "zh_TW"
5198   }, {
5199     "und_Zzzz_HK",
5200     "zh_Hant_HK",
5201     "zh_HK"
5202   }, {
5203     "und_Zzzz_AQ",
5204     "_Latn_AQ",
5205     "_AQ"
5206   }, {
5207     "und_Latn",
5208     "en_Latn_US",
5209     "en"
5210   }, {
5211     "und_Latn_ZZ",
5212     "en_Latn_US",
5213     "en"
5214   }, {
5215     "und_Latn_CN",
5216     "za_Latn_CN",
5217     "za"
5218   }, {
5219     "und_Latn_TW",
5220     "trv_Latn_TW",
5221     "trv"
5222   }, {
5223     "und_Latn_HK",
5224     "zh_Latn_HK",
5225     "zh_Latn_HK"
5226   }, {
5227     "und_Latn_AQ",
5228     "_Latn_AQ",
5229     "_AQ"
5230   }, {
5231     "und_Hans",
5232     "zh_Hans_CN",
5233     "zh"
5234   }, {
5235     "und_Hans_ZZ",
5236     "zh_Hans_CN",
5237     "zh"
5238   }, {
5239     "und_Hans_CN",
5240     "zh_Hans_CN",
5241     "zh"
5242   }, {
5243     "und_Hans_TW",
5244     "zh_Hans_TW",
5245     "zh_Hans_TW"
5246   }, {
5247     "und_Hans_HK",
5248     "zh_Hans_HK",
5249     "zh_Hans_HK"
5250   }, {
5251     "und_Hans_AQ",
5252     "zh_Hans_AQ",
5253     "zh_AQ"
5254   }, {
5255     "und_Hant",
5256     "zh_Hant_TW",
5257     "zh_TW"
5258   }, {
5259     "und_Hant_ZZ",
5260     "zh_Hant_TW",
5261     "zh_TW"
5262   }, {
5263     "und_Hant_CN",
5264     "zh_Hant_CN",
5265     "zh_Hant_CN"
5266   }, {
5267     "und_Hant_TW",
5268     "zh_Hant_TW",
5269     "zh_TW"
5270   }, {
5271     "und_Hant_HK",
5272     "zh_Hant_HK",
5273     "zh_HK"
5274   }, {
5275     "und_Hant_AQ",
5276     "zh_Hant_AQ",
5277     "zh_Hant_AQ"
5278   }, {
5279     "und_Moon",
5280     "en_Moon_US",
5281     "en_Moon"
5282   }, {
5283     "und_Moon_ZZ",
5284     "en_Moon_US",
5285     "en_Moon"
5286   }, {
5287     "und_Moon_CN",
5288     "zh_Moon_CN",
5289     "zh_Moon"
5290   }, {
5291     "und_Moon_TW",
5292     "zh_Moon_TW",
5293     "zh_Moon_TW"
5294   }, {
5295     "und_Moon_HK",
5296     "zh_Moon_HK",
5297     "zh_Moon_HK"
5298   }, {
5299     "und_Moon_AQ",
5300     "_Moon_AQ",
5301     "_Moon_AQ"
5302   }, {
5303     "es",
5304     "es_Latn_ES",
5305     "es"
5306   }, {
5307     "es_ZZ",
5308     "es_Latn_ES",
5309     "es"
5310   }, {
5311     "es_CN",
5312     "es_Latn_CN",
5313     "es_CN"
5314   }, {
5315     "es_TW",
5316     "es_Latn_TW",
5317     "es_TW"
5318   }, {
5319     "es_HK",
5320     "es_Latn_HK",
5321     "es_HK"
5322   }, {
5323     "es_AQ",
5324     "es_Latn_AQ",
5325     "es_AQ"
5326   }, {
5327     "es_Zzzz",
5328     "es_Latn_ES",
5329     "es"
5330   }, {
5331     "es_Zzzz_ZZ",
5332     "es_Latn_ES",
5333     "es"
5334   }, {
5335     "es_Zzzz_CN",
5336     "es_Latn_CN",
5337     "es_CN"
5338   }, {
5339     "es_Zzzz_TW",
5340     "es_Latn_TW",
5341     "es_TW"
5342   }, {
5343     "es_Zzzz_HK",
5344     "es_Latn_HK",
5345     "es_HK"
5346   }, {
5347     "es_Zzzz_AQ",
5348     "es_Latn_AQ",
5349     "es_AQ"
5350   }, {
5351     "es_Latn",
5352     "es_Latn_ES",
5353     "es"
5354   }, {
5355     "es_Latn_ZZ",
5356     "es_Latn_ES",
5357     "es"
5358   }, {
5359     "es_Latn_CN",
5360     "es_Latn_CN",
5361     "es_CN"
5362   }, {
5363     "es_Latn_TW",
5364     "es_Latn_TW",
5365     "es_TW"
5366   }, {
5367     "es_Latn_HK",
5368     "es_Latn_HK",
5369     "es_HK"
5370   }, {
5371     "es_Latn_AQ",
5372     "es_Latn_AQ",
5373     "es_AQ"
5374   }, {
5375     "es_Hans",
5376     "es_Hans_ES",
5377     "es_Hans"
5378   }, {
5379     "es_Hans_ZZ",
5380     "es_Hans_ES",
5381     "es_Hans"
5382   }, {
5383     "es_Hans_CN",
5384     "es_Hans_CN",
5385     "es_Hans_CN"
5386   }, {
5387     "es_Hans_TW",
5388     "es_Hans_TW",
5389     "es_Hans_TW"
5390   }, {
5391     "es_Hans_HK",
5392     "es_Hans_HK",
5393     "es_Hans_HK"
5394   }, {
5395     "es_Hans_AQ",
5396     "es_Hans_AQ",
5397     "es_Hans_AQ"
5398   }, {
5399     "es_Hant",
5400     "es_Hant_ES",
5401     "es_Hant"
5402   }, {
5403     "es_Hant_ZZ",
5404     "es_Hant_ES",
5405     "es_Hant"
5406   }, {
5407     "es_Hant_CN",
5408     "es_Hant_CN",
5409     "es_Hant_CN"
5410   }, {
5411     "es_Hant_TW",
5412     "es_Hant_TW",
5413     "es_Hant_TW"
5414   }, {
5415     "es_Hant_HK",
5416     "es_Hant_HK",
5417     "es_Hant_HK"
5418   }, {
5419     "es_Hant_AQ",
5420     "es_Hant_AQ",
5421     "es_Hant_AQ"
5422   }, {
5423     "es_Moon",
5424     "es_Moon_ES",
5425     "es_Moon"
5426   }, {
5427     "es_Moon_ZZ",
5428     "es_Moon_ES",
5429     "es_Moon"
5430   }, {
5431     "es_Moon_CN",
5432     "es_Moon_CN",
5433     "es_Moon_CN"
5434   }, {
5435     "es_Moon_TW",
5436     "es_Moon_TW",
5437     "es_Moon_TW"
5438   }, {
5439     "es_Moon_HK",
5440     "es_Moon_HK",
5441     "es_Moon_HK"
5442   }, {
5443     "es_Moon_AQ",
5444     "es_Moon_AQ",
5445     "es_Moon_AQ"
5446   }, {
5447     "zh",
5448     "zh_Hans_CN",
5449     "zh"
5450   }, {
5451     "zh_ZZ",
5452     "zh_Hans_CN",
5453     "zh"
5454   }, {
5455     "zh_CN",
5456     "zh_Hans_CN",
5457     "zh"
5458   }, {
5459     "zh_TW",
5460     "zh_Hant_TW",
5461     "zh_TW"
5462   }, {
5463     "zh_HK",
5464     "zh_Hant_HK",
5465     "zh_HK"
5466   }, {
5467     "zh_AQ",
5468     "zh_Hans_AQ",
5469     "zh_AQ"
5470   }, {
5471     "zh_Zzzz",
5472     "zh_Hans_CN",
5473     "zh"
5474   }, {
5475     "zh_Zzzz_ZZ",
5476     "zh_Hans_CN",
5477     "zh"
5478   }, {
5479     "zh_Zzzz_CN",
5480     "zh_Hans_CN",
5481     "zh"
5482   }, {
5483     "zh_Zzzz_TW",
5484     "zh_Hant_TW",
5485     "zh_TW"
5486   }, {
5487     "zh_Zzzz_HK",
5488     "zh_Hant_HK",
5489     "zh_HK"
5490   }, {
5491     "zh_Zzzz_AQ",
5492     "zh_Hans_AQ",
5493     "zh_AQ"
5494   }, {
5495     "zh_Latn",
5496     "zh_Latn_CN",
5497     "zh_Latn"
5498   }, {
5499     "zh_Latn_ZZ",
5500     "zh_Latn_CN",
5501     "zh_Latn"
5502   }, {
5503     "zh_Latn_CN",
5504     "zh_Latn_CN",
5505     "zh_Latn"
5506   }, {
5507     "zh_Latn_TW",
5508     "zh_Latn_TW",
5509     "zh_Latn_TW"
5510   }, {
5511     "zh_Latn_HK",
5512     "zh_Latn_HK",
5513     "zh_Latn_HK"
5514   }, {
5515     "zh_Latn_AQ",
5516     "zh_Latn_AQ",
5517     "zh_Latn_AQ"
5518   }, {
5519     "zh_Hans",
5520     "zh_Hans_CN",
5521     "zh"
5522   }, {
5523     "zh_Hans_ZZ",
5524     "zh_Hans_CN",
5525     "zh"
5526   }, {
5527     "zh_Hans_TW",
5528     "zh_Hans_TW",
5529     "zh_Hans_TW"
5530   }, {
5531     "zh_Hans_HK",
5532     "zh_Hans_HK",
5533     "zh_Hans_HK"
5534   }, {
5535     "zh_Hans_AQ",
5536     "zh_Hans_AQ",
5537     "zh_AQ"
5538   }, {
5539     "zh_Hant",
5540     "zh_Hant_TW",
5541     "zh_TW"
5542   }, {
5543     "zh_Hant_ZZ",
5544     "zh_Hant_TW",
5545     "zh_TW"
5546   }, {
5547     "zh_Hant_CN",
5548     "zh_Hant_CN",
5549     "zh_Hant_CN"
5550   }, {
5551     "zh_Hant_AQ",
5552     "zh_Hant_AQ",
5553     "zh_Hant_AQ"
5554   }, {
5555     "zh_Moon",
5556     "zh_Moon_CN",
5557     "zh_Moon"
5558   }, {
5559     "zh_Moon_ZZ",
5560     "zh_Moon_CN",
5561     "zh_Moon"
5562   }, {
5563     "zh_Moon_CN",
5564     "zh_Moon_CN",
5565     "zh_Moon"
5566   }, {
5567     "zh_Moon_TW",
5568     "zh_Moon_TW",
5569     "zh_Moon_TW"
5570   }, {
5571     "zh_Moon_HK",
5572     "zh_Moon_HK",
5573     "zh_Moon_HK"
5574   }, {
5575     "zh_Moon_AQ",
5576     "zh_Moon_AQ",
5577     "zh_Moon_AQ"
5578   }, {
5579     "art",
5580     "",
5581     ""
5582   }, {
5583     "art_ZZ",
5584     "",
5585     ""
5586   }, {
5587     "art_CN",
5588     "",
5589     ""
5590   }, {
5591     "art_TW",
5592     "",
5593     ""
5594   }, {
5595     "art_HK",
5596     "",
5597     ""
5598   }, {
5599     "art_AQ",
5600     "",
5601     ""
5602   }, {
5603     "art_Zzzz",
5604     "",
5605     ""
5606   }, {
5607     "art_Zzzz_ZZ",
5608     "",
5609     ""
5610   }, {
5611     "art_Zzzz_CN",
5612     "",
5613     ""
5614   }, {
5615     "art_Zzzz_TW",
5616     "",
5617     ""
5618   }, {
5619     "art_Zzzz_HK",
5620     "",
5621     ""
5622   }, {
5623     "art_Zzzz_AQ",
5624     "",
5625     ""
5626   }, {
5627     "art_Latn",
5628     "",
5629     ""
5630   }, {
5631     "art_Latn_ZZ",
5632     "",
5633     ""
5634   }, {
5635     "art_Latn_CN",
5636     "",
5637     ""
5638   }, {
5639     "art_Latn_TW",
5640     "",
5641     ""
5642   }, {
5643     "art_Latn_HK",
5644     "",
5645     ""
5646   }, {
5647     "art_Latn_AQ",
5648     "",
5649     ""
5650   }, {
5651     "art_Hans",
5652     "",
5653     ""
5654   }, {
5655     "art_Hans_ZZ",
5656     "",
5657     ""
5658   }, {
5659     "art_Hans_CN",
5660     "",
5661     ""
5662   }, {
5663     "art_Hans_TW",
5664     "",
5665     ""
5666   }, {
5667     "art_Hans_HK",
5668     "",
5669     ""
5670   }, {
5671     "art_Hans_AQ",
5672     "",
5673     ""
5674   }, {
5675     "art_Hant",
5676     "",
5677     ""
5678   }, {
5679     "art_Hant_ZZ",
5680     "",
5681     ""
5682   }, {
5683     "art_Hant_CN",
5684     "",
5685     ""
5686   }, {
5687     "art_Hant_TW",
5688     "",
5689     ""
5690   }, {
5691     "art_Hant_HK",
5692     "",
5693     ""
5694   }, {
5695     "art_Hant_AQ",
5696     "",
5697     ""
5698   }, {
5699     "art_Moon",
5700     "",
5701     ""
5702   }, {
5703     "art_Moon_ZZ",
5704     "",
5705     ""
5706   }, {
5707     "art_Moon_CN",
5708     "",
5709     ""
5710   }, {
5711     "art_Moon_TW",
5712     "",
5713     ""
5714   }, {
5715     "art_Moon_HK",
5716     "",
5717     ""
5718   }, {
5719     "art_Moon_AQ",
5720     "",
5721     ""
5722   }, {
5723     "de@collation=phonebook",
5724     "de_Latn_DE@collation=phonebook",
5725     "de@collation=phonebook"
5726   }
5727 };
5728 
5729 typedef struct errorDataTag {
5730     const char* tag;
5731     const char* expected;
5732     UErrorCode uerror;
5733     int32_t  bufferSize;
5734 } errorData;
5735 
5736 const errorData maximizeErrors[] = {
5737     {
5738         "enfueiujhytdf",
5739         NULL,
5740         U_ILLEGAL_ARGUMENT_ERROR,
5741         -1
5742     },
5743     {
5744         "en_THUJIOGIURJHGJFURYHFJGURYYYHHGJURHG",
5745         NULL,
5746         U_ILLEGAL_ARGUMENT_ERROR,
5747         -1
5748     },
5749     {
5750         "en_THUJIOGIURJHGJFURYHFJGURYYYHHGJURHG",
5751         NULL,
5752         U_ILLEGAL_ARGUMENT_ERROR,
5753         -1
5754     },
5755     {
5756         "en_Latn_US_POSIX@currency=EURO",
5757         "en_Latn_US_POSIX@currency=EURO",
5758         U_BUFFER_OVERFLOW_ERROR,
5759         29
5760     },
5761     {
5762         "en_Latn_US_POSIX@currency=EURO",
5763         "en_Latn_US_POSIX@currency=EURO",
5764         U_STRING_NOT_TERMINATED_WARNING,
5765         30
5766     }
5767 };
5768 
5769 const errorData minimizeErrors[] = {
5770     {
5771         "enfueiujhytdf",
5772         NULL,
5773         U_ILLEGAL_ARGUMENT_ERROR,
5774         -1
5775     },
5776     {
5777         "en_THUJIOGIURJHGJFURYHFJGURYYYHHGJURHG",
5778         NULL,
5779         U_ILLEGAL_ARGUMENT_ERROR,
5780         -1
5781     },
5782     {
5783         "en_Latn_US_POSIX@currency=EURO",
5784         "en__POSIX@currency=EURO",
5785         U_BUFFER_OVERFLOW_ERROR,
5786         22
5787     },
5788     {
5789         "en_Latn_US_POSIX@currency=EURO",
5790         "en__POSIX@currency=EURO",
5791         U_STRING_NOT_TERMINATED_WARNING,
5792         23
5793     }
5794 };
5795 
getExpectedReturnValue(const errorData * data)5796 static int32_t getExpectedReturnValue(const errorData* data)
5797 {
5798     if (data->uerror == U_BUFFER_OVERFLOW_ERROR ||
5799         data->uerror == U_STRING_NOT_TERMINATED_WARNING)
5800     {
5801         return (int32_t)strlen(data->expected);
5802     }
5803     else
5804     {
5805         return -1;
5806     }
5807 }
5808 
getBufferSize(const errorData * data,int32_t actualSize)5809 static int32_t getBufferSize(const errorData* data, int32_t actualSize)
5810 {
5811     if (data->expected == NULL)
5812     {
5813         return actualSize;
5814     }
5815     else if (data->bufferSize < 0)
5816     {
5817         return (int32_t)strlen(data->expected) + 1;
5818     }
5819     else
5820     {
5821         return data->bufferSize;
5822     }
5823 }
5824 
TestLikelySubtags()5825 static void TestLikelySubtags()
5826 {
5827     char buffer[ULOC_FULLNAME_CAPACITY + ULOC_KEYWORD_AND_VALUES_CAPACITY + 1];
5828     int32_t i = 0;
5829 
5830     for (; i < UPRV_LENGTHOF(basic_maximize_data); ++i)
5831     {
5832         UErrorCode status = U_ZERO_ERROR;
5833         const char* const minimal = basic_maximize_data[i][0];
5834         const char* const maximal = basic_maximize_data[i][1];
5835 
5836         /* const int32_t length = */
5837             uloc_addLikelySubtags(
5838                 minimal,
5839                 buffer,
5840                 sizeof(buffer),
5841                 &status);
5842         if (U_FAILURE(status)) {
5843             log_err_status(status, "  unexpected failure of uloc_addLikelySubtags(), minimal \"%s\" status %s\n", minimal, u_errorName(status));
5844             status = U_ZERO_ERROR;
5845         }
5846         else if (uprv_strlen(maximal) == 0) {
5847             if (uprv_stricmp(minimal, buffer) != 0) {
5848                 log_err("  unexpected maximal value \"%s\" in uloc_addLikelySubtags(), minimal \"%s\" = \"%s\"\n", maximal, minimal, buffer);
5849             }
5850         }
5851         else if (uprv_stricmp(maximal, buffer) != 0) {
5852             log_err("  maximal doesn't match expected %s in uloc_addLikelySubtags(), minimal \"%s\" = %s\n", maximal, minimal, buffer);
5853         }
5854     }
5855 
5856     for (i = 0; i < UPRV_LENGTHOF(basic_minimize_data); ++i) {
5857 
5858         UErrorCode status = U_ZERO_ERROR;
5859         const char* const maximal = basic_minimize_data[i][0];
5860         const char* const minimal = basic_minimize_data[i][1];
5861 
5862         /* const int32_t length = */
5863             uloc_minimizeSubtags(
5864                 maximal,
5865                 buffer,
5866                 sizeof(buffer),
5867                 &status);
5868 
5869         if (U_FAILURE(status)) {
5870             log_err_status(status, "  unexpected failure of uloc_MinimizeSubtags(), maximal \"%s\" status %s\n", maximal, u_errorName(status));
5871             status = U_ZERO_ERROR;
5872         }
5873         else if (uprv_strlen(minimal) == 0) {
5874             if (uprv_stricmp(maximal, buffer) != 0) {
5875                 log_err("  unexpected minimal value \"%s\" in uloc_minimizeSubtags(), maximal \"%s\" = \"%s\"\n", minimal, maximal, buffer);
5876             }
5877         }
5878         else if (uprv_stricmp(minimal, buffer) != 0) {
5879             log_err("  minimal doesn't match expected %s in uloc_MinimizeSubtags(), maximal \"%s\" = %s\n", minimal, maximal, buffer);
5880         }
5881     }
5882 
5883     for (i = 0; i < UPRV_LENGTHOF(full_data); ++i) {
5884 
5885         UErrorCode status = U_ZERO_ERROR;
5886         const char* const minimal = full_data[i][0];
5887         const char* const maximal = full_data[i][1];
5888 
5889         /* const int32_t length = */
5890             uloc_addLikelySubtags(
5891                 minimal,
5892                 buffer,
5893                 sizeof(buffer),
5894                 &status);
5895         if (U_FAILURE(status)) {
5896             log_err_status(status, "  unexpected failure of uloc_addLikelySubtags(), minimal \"%s\" status \"%s\"\n", minimal, u_errorName(status));
5897             status = U_ZERO_ERROR;
5898         }
5899         else if (uprv_strlen(maximal) == 0) {
5900             if (uprv_stricmp(minimal, buffer) != 0) {
5901                 log_err("  unexpected maximal value \"%s\" in uloc_addLikelySubtags(), minimal \"%s\" = \"%s\"\n", maximal, minimal, buffer);
5902             }
5903         }
5904         else if (uprv_stricmp(maximal, buffer) != 0) {
5905             log_err("  maximal doesn't match expected \"%s\" in uloc_addLikelySubtags(), minimal \"%s\" = \"%s\"\n", maximal, minimal, buffer);
5906         }
5907     }
5908 
5909     for (i = 0; i < UPRV_LENGTHOF(full_data); ++i) {
5910 
5911         UErrorCode status = U_ZERO_ERROR;
5912         const char* const maximal = full_data[i][1];
5913         const char* const minimal = full_data[i][2];
5914 
5915         if (strlen(maximal) > 0) {
5916 
5917             /* const int32_t length = */
5918                 uloc_minimizeSubtags(
5919                     maximal,
5920                     buffer,
5921                     sizeof(buffer),
5922                     &status);
5923 
5924             if (U_FAILURE(status)) {
5925                 log_err_status(status, "  unexpected failure of uloc_minimizeSubtags(), maximal \"%s\" status %s\n", maximal, u_errorName(status));
5926                 status = U_ZERO_ERROR;
5927             }
5928             else if (uprv_strlen(minimal) == 0) {
5929                 if (uprv_stricmp(maximal, buffer) != 0) {
5930                     log_err("  unexpected minimal value \"%s\" in uloc_minimizeSubtags(), maximal \"%s\" = \"%s\"\n", minimal, maximal, buffer);
5931                 }
5932             }
5933             else if (uprv_stricmp(minimal, buffer) != 0) {
5934                 log_err("  minimal doesn't match expected %s in uloc_MinimizeSubtags(), maximal \"%s\" = %s\n", minimal, maximal, buffer);
5935             }
5936         }
5937     }
5938 
5939     for (i = 0; i < UPRV_LENGTHOF(maximizeErrors); ++i) {
5940 
5941         UErrorCode status = U_ZERO_ERROR;
5942         const char* const minimal = maximizeErrors[i].tag;
5943         const char* const maximal = maximizeErrors[i].expected;
5944         const UErrorCode expectedStatus = maximizeErrors[i].uerror;
5945         const int32_t expectedLength = getExpectedReturnValue(&maximizeErrors[i]);
5946         const int32_t bufferSize = getBufferSize(&maximizeErrors[i], sizeof(buffer));
5947 
5948         const int32_t length =
5949             uloc_addLikelySubtags(
5950                 minimal,
5951                 buffer,
5952                 bufferSize,
5953                 &status);
5954 
5955         if (status == U_ZERO_ERROR) {
5956             log_err("  unexpected U_ZERO_ERROR for uloc_addLikelySubtags(), minimal \"%s\" expected status %s\n", minimal, u_errorName(expectedStatus));
5957             status = U_ZERO_ERROR;
5958         }
5959         else if (status != expectedStatus) {
5960             log_err_status(status, "  unexpected status for uloc_addLikelySubtags(), minimal \"%s\" expected status %s, but got %s\n", minimal, u_errorName(expectedStatus), u_errorName(status));
5961         }
5962         else if (length != expectedLength) {
5963             log_err("  unexpected length for uloc_addLikelySubtags(), minimal \"%s\" expected length %d, but got %d\n", minimal, expectedLength, length);
5964         }
5965         else if (status == U_BUFFER_OVERFLOW_ERROR || status == U_STRING_NOT_TERMINATED_WARNING) {
5966             if (uprv_strnicmp(maximal, buffer, bufferSize) != 0) {
5967                 log_err("  maximal doesn't match expected %s in uloc_addLikelySubtags(), minimal \"%s\" = %*s\n",
5968                     maximal, minimal, (int)sizeof(buffer), buffer);
5969             }
5970         }
5971     }
5972 
5973     for (i = 0; i < UPRV_LENGTHOF(minimizeErrors); ++i) {
5974 
5975         UErrorCode status = U_ZERO_ERROR;
5976         const char* const maximal = minimizeErrors[i].tag;
5977         const char* const minimal = minimizeErrors[i].expected;
5978         const UErrorCode expectedStatus = minimizeErrors[i].uerror;
5979         const int32_t expectedLength = getExpectedReturnValue(&minimizeErrors[i]);
5980         const int32_t bufferSize = getBufferSize(&minimizeErrors[i], sizeof(buffer));
5981 
5982         const int32_t length =
5983             uloc_minimizeSubtags(
5984                 maximal,
5985                 buffer,
5986                 bufferSize,
5987                 &status);
5988 
5989         if (status == U_ZERO_ERROR) {
5990             log_err("  unexpected U_ZERO_ERROR for uloc_minimizeSubtags(), maximal \"%s\" expected status %s\n", maximal, u_errorName(expectedStatus));
5991             status = U_ZERO_ERROR;
5992         }
5993         else if (status != expectedStatus) {
5994             log_err_status(status, "  unexpected status for uloc_minimizeSubtags(), maximal \"%s\" expected status %s, but got %s\n", maximal, u_errorName(expectedStatus), u_errorName(status));
5995         }
5996         else if (length != expectedLength) {
5997             log_err("  unexpected length for uloc_minimizeSubtags(), maximal \"%s\" expected length %d, but got %d\n", maximal, expectedLength, length);
5998         }
5999         else if (status == U_BUFFER_OVERFLOW_ERROR || status == U_STRING_NOT_TERMINATED_WARNING) {
6000             if (uprv_strnicmp(minimal, buffer, bufferSize) != 0) {
6001                 log_err("  minimal doesn't match expected \"%s\" in uloc_minimizeSubtags(), minimal \"%s\" = \"%*s\"\n",
6002                     minimal, maximal, (int)sizeof(buffer), buffer);
6003             }
6004         }
6005     }
6006 }
6007 
6008 const char* const locale_to_langtag[][3] = {
6009     {"",            "und",          "und"},
6010     {"en",          "en",           "en"},
6011     {"en_US",       "en-US",        "en-US"},
6012     {"iw_IL",       "he-IL",        "he-IL"},
6013     {"sr_Latn_SR",  "sr-Latn-SR",   "sr-Latn-SR"},
6014     {"en__POSIX",   "en-u-va-posix", "en-u-va-posix"},
6015     {"en_POSIX",    "en-u-va-posix", "en-u-va-posix"},
6016     {"en_US_POSIX_VAR", "en-US-posix-x-lvariant-var", NULL},  /* variant POSIX_VAR is processed as regular variant */
6017     {"en_US_VAR_POSIX", "en-US-x-lvariant-var-posix", NULL},  /* variant VAR_POSIX is processed as regular variant */
6018     {"en_US_POSIX@va=posix2",   "en-US-u-va-posix2",  "en-US-u-va-posix2"},           /* if keyword va=xxx already exists, variant POSIX is simply dropped */
6019     {"en_US_POSIX@ca=japanese",  "en-US-u-ca-japanese-va-posix", "en-US-u-ca-japanese-va-posix"},
6020     {"und_555",     "und-555",      "und-555"},
6021     {"123",         "und",          NULL},
6022     {"%$#&",        "und",          NULL},
6023     {"_Latn",       "und-Latn",     "und-Latn"},
6024     {"_DE",         "und-DE",       "und-DE"},
6025     {"und_FR",      "und-FR",       "und-FR"},
6026     {"th_TH_TH",    "th-TH-x-lvariant-th", NULL},
6027     {"bogus",       "bogus",        "bogus"},
6028     {"foooobarrr",  "und",          NULL},
6029     {"aa_BB_CYRL",  "aa-BB-x-lvariant-cyrl", NULL},
6030     {"en_US_1234",  "en-US-1234",   "en-US-1234"},
6031     {"en_US_VARIANTA_VARIANTB", "en-US-varianta-variantb",  "en-US-varianta-variantb"},
6032     {"ja__9876_5432",   "ja-9876-5432", "ja-9876-5432"},
6033     {"zh_Hant__VAR",    "zh-Hant-x-lvariant-var", NULL},
6034     {"es__BADVARIANT_GOODVAR",  "es-goodvar",   NULL},
6035     {"en@calendar=gregorian",   "en-u-ca-gregory",  "en-u-ca-gregory"},
6036     {"de@collation=phonebook;calendar=gregorian",   "de-u-ca-gregory-co-phonebk",   "de-u-ca-gregory-co-phonebk"},
6037     {"th@numbers=thai;z=extz;x=priv-use;a=exta",   "th-a-exta-u-nu-thai-z-extz-x-priv-use", "th-a-exta-u-nu-thai-z-extz-x-priv-use"},
6038     {"en@timezone=America/New_York;calendar=japanese",    "en-u-ca-japanese-tz-usnyc",    "en-u-ca-japanese-tz-usnyc"},
6039     {"en@timezone=US/Eastern",  "en-u-tz-usnyc",    "en-u-tz-usnyc"},
6040     {"en@x=x-y-z;a=a-b-c",  "en-x-x-y-z",   NULL},
6041     {"it@collation=badcollationtype;colStrength=identical;cu=usd-eur", "it-u-cu-usd-eur-ks-identic",  NULL},
6042     {"en_US_POSIX", "en-US-u-va-posix", "en-US-u-va-posix"},
6043     {"en_US_POSIX@calendar=japanese;currency=EUR","en-US-u-ca-japanese-cu-eur-va-posix", "en-US-u-ca-japanese-cu-eur-va-posix"},
6044     {"@x=elmer",    "x-elmer",      "x-elmer"},
6045     {"en@x=elmer",  "en-x-elmer",   "en-x-elmer"},
6046     {"@x=elmer;a=exta", "und-a-exta-x-elmer",   "und-a-exta-x-elmer"},
6047     {"en_US@attribute=attr1-attr2;calendar=gregorian", "en-US-u-attr1-attr2-ca-gregory", "en-US-u-attr1-attr2-ca-gregory"},
6048     /* #12671 */
6049     {"en@a=bar;attribute=baz",  "en-a-bar-u-baz",   "en-a-bar-u-baz"},
6050     {"en@a=bar;attribute=baz;x=u-foo",  "en-a-bar-u-baz-x-u-foo",   "en-a-bar-u-baz-x-u-foo"},
6051     {"en@attribute=baz",    "en-u-baz", "en-u-baz"},
6052     {"en@attribute=baz;calendar=islamic-civil", "en-u-baz-ca-islamic-civil",    "en-u-baz-ca-islamic-civil"},
6053     {"en@a=bar;calendar=islamic-civil;x=u-foo", "en-a-bar-u-ca-islamic-civil-x-u-foo",  "en-a-bar-u-ca-islamic-civil-x-u-foo"},
6054     {"en@a=bar;attribute=baz;calendar=islamic-civil;x=u-foo",   "en-a-bar-u-baz-ca-islamic-civil-x-u-foo",  "en-a-bar-u-baz-ca-islamic-civil-x-u-foo"},
6055     {"en@9=efg;a=baz",    "en-9-efg-a-baz", "en-9-efg-a-baz"},
6056 
6057     // Before ICU 64, ICU locale canonicalization had some additional mappings.
6058     // They were removed for ICU-20187 "drop support for long-obsolete locale ID variants".
6059     // The following now uses standard canonicalization.
6060     {"az_AZ_CYRL", "az-AZ-x-lvariant-cyrl", NULL},
6061 
6062     {NULL,          NULL,           NULL}
6063 };
6064 
TestToLanguageTag(void)6065 static void TestToLanguageTag(void) {
6066     char langtag[256];
6067     int32_t i;
6068     UErrorCode status;
6069     int32_t len;
6070     const char *inloc;
6071     const char *expected;
6072 
6073     for (i = 0; locale_to_langtag[i][0] != NULL; i++) {
6074         inloc = locale_to_langtag[i][0];
6075 
6076         /* testing non-strict mode */
6077         status = U_ZERO_ERROR;
6078         langtag[0] = 0;
6079         expected = locale_to_langtag[i][1];
6080 
6081         len = uloc_toLanguageTag(inloc, langtag, sizeof(langtag), FALSE, &status);
6082         (void)len;    /* Suppress set but not used warning. */
6083         if (U_FAILURE(status)) {
6084             if (expected != NULL) {
6085                 log_err("Error returned by uloc_toLanguageTag for locale id [%s] - error: %s\n",
6086                     inloc, u_errorName(status));
6087             }
6088         } else {
6089             if (expected == NULL) {
6090                 log_err("Error should be returned by uloc_toLanguageTag for locale id [%s], but [%s] is returned without errors\n",
6091                     inloc, langtag);
6092             } else if (uprv_strcmp(langtag, expected) != 0) {
6093                 log_data_err("uloc_toLanguageTag returned language tag [%s] for input locale [%s] - expected: [%s]. Are you missing data?\n",
6094                     langtag, inloc, expected);
6095             }
6096         }
6097 
6098         /* testing strict mode */
6099         status = U_ZERO_ERROR;
6100         langtag[0] = 0;
6101         expected = locale_to_langtag[i][2];
6102 
6103         len = uloc_toLanguageTag(inloc, langtag, sizeof(langtag), TRUE, &status);
6104         if (U_FAILURE(status)) {
6105             if (expected != NULL) {
6106                 log_data_err("Error returned by uloc_toLanguageTag {strict} for locale id [%s] - error: %s Are you missing data?\n",
6107                     inloc, u_errorName(status));
6108             }
6109         } else {
6110             if (expected == NULL) {
6111                 log_err("Error should be returned by uloc_toLanguageTag {strict} for locale id [%s], but [%s] is returned without errors\n",
6112                     inloc, langtag);
6113             } else if (uprv_strcmp(langtag, expected) != 0) {
6114                 log_err("uloc_toLanguageTag {strict} returned language tag [%s] for input locale [%s] - expected: [%s]\n",
6115                     langtag, inloc, expected);
6116             }
6117         }
6118     }
6119 }
6120 
TestBug20132(void)6121 static void TestBug20132(void) {
6122     char langtag[256];
6123     UErrorCode status;
6124     int32_t len;
6125 
6126     static const char inloc[] = "en-C";
6127     static const char expected[] = "en-x-lvariant-c";
6128     const int32_t expected_len = (int32_t)uprv_strlen(expected);
6129 
6130     /* Before ICU-20132 was fixed, calling uloc_toLanguageTag() with a too small
6131      * buffer would not immediately return the buffer size actually needed, but
6132      * instead require several iterations before getting the correct size. */
6133 
6134     status = U_ZERO_ERROR;
6135     len = uloc_toLanguageTag(inloc, langtag, 1, FALSE, &status);
6136 
6137     if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) {
6138         log_data_err("Error returned by uloc_toLanguageTag for locale id [%s] - error: %s Are you missing data?\n",
6139             inloc, u_errorName(status));
6140     }
6141 
6142     if (len != expected_len) {
6143         log_err("Bad length returned by uloc_toLanguageTag for locale id [%s]: %i != %i\n", inloc, len, expected_len);
6144     }
6145 
6146     status = U_ZERO_ERROR;
6147     len = uloc_toLanguageTag(inloc, langtag, expected_len, FALSE, &status);
6148 
6149     if (U_FAILURE(status)) {
6150         log_data_err("Error returned by uloc_toLanguageTag for locale id [%s] - error: %s Are you missing data?\n",
6151             inloc, u_errorName(status));
6152     }
6153 
6154     if (len != expected_len) {
6155         log_err("Bad length returned by uloc_toLanguageTag for locale id [%s]: %i != %i\n", inloc, len, expected_len);
6156     } else if (uprv_strncmp(langtag, expected, expected_len) != 0) {
6157         log_data_err("uloc_toLanguageTag returned language tag [%.*s] for input locale [%s] - expected: [%s]. Are you missing data?\n",
6158             len, langtag, inloc, expected);
6159     }
6160 }
6161 
6162 #define FULL_LENGTH -1
6163 static const struct {
6164     const char  *bcpID;
6165     const char  *locID;
6166     int32_t     len;
6167 } langtag_to_locale[] = {
6168     {"en",                  "en",                   FULL_LENGTH},
6169     {"en-us",               "en_US",                FULL_LENGTH},
6170     {"und-US",              "_US",                  FULL_LENGTH},
6171     {"und-latn",            "_Latn",                FULL_LENGTH},
6172     {"en-US-posix",         "en_US_POSIX",          FULL_LENGTH},
6173     {"de-de_euro",          "de",                   2},
6174     {"kok-IN",              "kok_IN",               FULL_LENGTH},
6175     {"123",                 "",                     0},
6176     {"en_us",               "",                     0},
6177     {"en-latn-x",           "en_Latn",              7},
6178     {"art-lojban",          "jbo",                  FULL_LENGTH},
6179     {"zh-hakka",            "hak",                  FULL_LENGTH},
6180     {"zh-cmn-CH",           "cmn_CH",               FULL_LENGTH},
6181     {"zh-cmn-CH-u-co-pinyin", "cmn_CH@collation=pinyin", FULL_LENGTH},
6182     {"xxx-yy",              "xxx_YY",               FULL_LENGTH},
6183     {"fr-234",              "fr_234",               FULL_LENGTH},
6184     {"i-default",           "en@x=i-default",       FULL_LENGTH},
6185     {"i-test",              "",                     0},
6186     {"ja-jp-jp",            "ja_JP",                5},
6187     {"bogus",               "bogus",                FULL_LENGTH},
6188     {"boguslang",           "",                     0},
6189     {"EN-lATN-us",          "en_Latn_US",           FULL_LENGTH},
6190     {"und-variant-1234",    "__VARIANT_1234",       FULL_LENGTH},
6191     {"und-varzero-var1-vartwo", "__VARZERO",        11},
6192     {"en-u-ca-gregory",     "en@calendar=gregorian",    FULL_LENGTH},
6193     {"en-U-cu-USD",         "en@currency=usd",      FULL_LENGTH},
6194     {"en-US-u-va-posix",    "en_US_POSIX",          FULL_LENGTH},
6195     {"en-us-u-ca-gregory-va-posix", "en_US_POSIX@calendar=gregorian",   FULL_LENGTH},
6196     {"en-us-posix-u-va-posix",   "en_US_POSIX@va=posix",    FULL_LENGTH},
6197     {"en-us-u-va-posix2",        "en_US@va=posix2",         FULL_LENGTH},
6198     {"en-us-vari1-u-va-posix",   "en_US_VARI1@va=posix",    FULL_LENGTH},
6199     {"ar-x-1-2-3",          "ar@x=1-2-3",           FULL_LENGTH},
6200     {"fr-u-nu-latn-cu-eur", "fr@currency=eur;numbers=latn", FULL_LENGTH},
6201     {"de-k-kext-u-co-phonebk-nu-latn",  "de@collation=phonebook;k=kext;numbers=latn",   FULL_LENGTH},
6202     {"ja-u-cu-jpy-ca-jp",   "ja@calendar=yes;currency=jpy;jp=yes",  FULL_LENGTH},
6203     {"en-us-u-tz-usnyc",    "en_US@timezone=America/New_York",  FULL_LENGTH},
6204     {"und-a-abc-def",       "und@a=abc-def",        FULL_LENGTH},
6205     {"zh-u-ca-chinese-x-u-ca-chinese",  "zh@calendar=chinese;x=u-ca-chinese",   FULL_LENGTH},
6206     {"x-elmer",             "@x=elmer",             FULL_LENGTH},
6207     {"en-US-u-attr1-attr2-ca-gregory", "en_US@attribute=attr1-attr2;calendar=gregorian",    FULL_LENGTH},
6208     {"sr-u-kn",             "sr@colnumeric=yes",    FULL_LENGTH},
6209     {"de-u-kn-co-phonebk",  "de@collation=phonebook;colnumeric=yes",    FULL_LENGTH},
6210     {"en-u-attr2-attr1-kn-kb",  "en@attribute=attr1-attr2;colbackwards=yes;colnumeric=yes", FULL_LENGTH},
6211     {"ja-u-ijkl-efgh-abcd-ca-japanese-xx-yyy-zzz-kn",   "ja@attribute=abcd-efgh-ijkl;calendar=japanese;colnumeric=yes;xx=yyy-zzz",  FULL_LENGTH},
6212     {"de-u-xc-xphonebk-co-phonebk-ca-buddhist-mo-very-lo-extensi-xd-that-de-should-vc-probably-xz-killthebuffer",
6213      "de@calendar=buddhist;collation=phonebook;de=should;lo=extensi;mo=very;vc=probably;xc=xphonebk;xd=that;xz=yes", 91},
6214     {"de-1901-1901", "de__1901", 7},
6215     {"de-DE-1901-1901", "de_DE_1901", 10},
6216     {"en-a-bbb-a-ccc", "en@a=bbb", 8},
6217     /* #12761 */
6218     {"en-a-bar-u-baz",      "en@a=bar;attribute=baz",   FULL_LENGTH},
6219     {"en-a-bar-u-baz-x-u-foo",  "en@a=bar;attribute=baz;x=u-foo",   FULL_LENGTH},
6220     {"en-u-baz",            "en@attribute=baz",     FULL_LENGTH},
6221     {"en-u-baz-ca-islamic-civil",   "en@attribute=baz;calendar=islamic-civil",  FULL_LENGTH},
6222     {"en-a-bar-u-ca-islamic-civil-x-u-foo", "en@a=bar;calendar=islamic-civil;x=u-foo",  FULL_LENGTH},
6223     {"en-a-bar-u-baz-ca-islamic-civil-x-u-foo", "en@a=bar;attribute=baz;calendar=islamic-civil;x=u-foo",    FULL_LENGTH},
6224     {"und-Arab-u-em-emoji", "_Arab@em=emoji", FULL_LENGTH},
6225     {"und-Latn-u-em-emoji", "_Latn@em=emoji", FULL_LENGTH},
6226     {"und-Latn-DE-u-em-emoji", "_Latn_DE@em=emoji", FULL_LENGTH},
6227     {"und-Zzzz-DE-u-em-emoji", "_Zzzz_DE@em=emoji", FULL_LENGTH},
6228     {"und-DE-u-em-emoji", "_DE@em=emoji", FULL_LENGTH},
6229     // #20098
6230     {"hant-cmn-cn", "hant", 4},
6231     {"zh-cmn-TW", "cmn_TW", FULL_LENGTH},
6232     {"zh-x_t-ab", "zh", 2},
6233     {"zh-hans-cn-u-ca-x_t-u", "zh_Hans_CN@calendar=yes",  15},
6234     /* #20140 dupe keys in U-extension */
6235     {"zh-u-ca-chinese-ca-gregory", "zh@calendar=chinese", FULL_LENGTH},
6236     {"zh-u-ca-gregory-co-pinyin-ca-chinese", "zh@calendar=gregorian;collation=pinyin", FULL_LENGTH},
6237     {"de-latn-DE-1901-u-co-phonebk-co-pinyin-ca-gregory", "de_Latn_DE_1901@calendar=gregorian;collation=phonebook", FULL_LENGTH},
6238     {"th-u-kf-nu-thai-kf-false", "th@colcasefirst=yes;numbers=thai", FULL_LENGTH},
6239     /* #9562 IANA language tag data update */
6240     {"en-gb-oed", "en_GB_OXENDICT", FULL_LENGTH},
6241     {"i-navajo", "nv", FULL_LENGTH},
6242     {"i-navajo-a-foo", "nv@a=foo", FULL_LENGTH},
6243     {"i-navajo-latn-us", "nv_Latn_US", FULL_LENGTH},
6244     {"sgn-br", "bzs", FULL_LENGTH},
6245     {"sgn-br-u-co-phonebk", "bzs@collation=phonebook", FULL_LENGTH},
6246     {"ja-latn-hepburn-heploc", "ja_Latn__ALALC97", FULL_LENGTH},
6247     {"ja-latn-hepburn-heploc-u-ca-japanese", "ja_Latn__ALALC97@calendar=japanese", FULL_LENGTH},
6248     {"en-a-bcde-0-fgh", "en@0=fgh;a=bcde", FULL_LENGTH},
6249 };
6250 
TestForLanguageTag(void)6251 static void TestForLanguageTag(void) {
6252     char locale[256];
6253     int32_t i;
6254     UErrorCode status;
6255     int32_t parsedLen;
6256     int32_t expParsedLen;
6257 
6258     for (i = 0; i < UPRV_LENGTHOF(langtag_to_locale); i++) {
6259         status = U_ZERO_ERROR;
6260         locale[0] = 0;
6261         expParsedLen = langtag_to_locale[i].len;
6262         if (expParsedLen == FULL_LENGTH) {
6263             expParsedLen = (int32_t)uprv_strlen(langtag_to_locale[i].bcpID);
6264         }
6265         uloc_forLanguageTag(langtag_to_locale[i].bcpID, locale, sizeof(locale), &parsedLen, &status);
6266         if (U_FAILURE(status)) {
6267             log_err_status(status, "Error returned by uloc_forLanguageTag for language tag [%s] - error: %s\n",
6268                 langtag_to_locale[i].bcpID, u_errorName(status));
6269         } else {
6270             if (uprv_strcmp(langtag_to_locale[i].locID, locale) != 0) {
6271                 log_data_err("uloc_forLanguageTag returned locale [%s] for input language tag [%s] - expected: [%s]\n",
6272                     locale, langtag_to_locale[i].bcpID, langtag_to_locale[i].locID);
6273             }
6274             if (parsedLen != expParsedLen) {
6275                 log_err("uloc_forLanguageTag parsed length of %d for input language tag [%s] - expected parsed length: %d\n",
6276                     parsedLen, langtag_to_locale[i].bcpID, expParsedLen);
6277             }
6278         }
6279     }
6280 }
6281 
6282 static const struct {
6283     const char  *input;
6284     const char  *canonical;
6285 } langtag_to_canonical[] = {
6286     {"de-DD", "de-DE"},
6287     {"de-DD-u-co-phonebk", "de-DE-u-co-phonebk"},
6288     {"jw-id", "jv-ID"},
6289     {"jw-id-u-ca-islamic-civil", "jv-ID-u-ca-islamic-civil"},
6290     {"mo-md", "ro-MD"},
6291     {"my-bu-u-nu-mymr", "my-MM-u-nu-mymr"},
6292     {"yuu-ru", "yug-RU"},
6293 };
6294 
6295 
TestLangAndRegionCanonicalize(void)6296 static void TestLangAndRegionCanonicalize(void) {
6297     char locale[256];
6298     char canonical[256];
6299     int32_t i;
6300     UErrorCode status;
6301     for (i = 0; i < UPRV_LENGTHOF(langtag_to_canonical); i++) {
6302         status = U_ZERO_ERROR;
6303         const char* input = langtag_to_canonical[i].input;
6304         uloc_forLanguageTag(input, locale, sizeof(locale), NULL, &status);
6305         uloc_toLanguageTag(locale, canonical, sizeof(canonical), TRUE, &status);
6306         if (U_FAILURE(status)) {
6307             log_err_status(status, "Error returned by uloc_forLanguageTag or uloc_toLanguageTag "
6308                            "for language tag [%s] - error: %s\n", input, u_errorName(status));
6309         } else {
6310             const char* expected_canonical = langtag_to_canonical[i].canonical;
6311             if (uprv_strcmp(expected_canonical, canonical) != 0) {
6312                 log_data_err("input language tag [%s] is canonicalized to [%s] - expected: [%s]\n",
6313                     input, canonical, expected_canonical);
6314             }
6315         }
6316     }
6317 }
6318 
TestToUnicodeLocaleKey(void)6319 static void TestToUnicodeLocaleKey(void)
6320 {
6321     /* $IN specifies the result should be the input pointer itself */
6322     static const char* DATA[][2] = {
6323         {"calendar",    "ca"},
6324         {"CALEndar",    "ca"},  /* difference casing */
6325         {"ca",          "ca"},  /* bcp key itself */
6326         {"kv",          "kv"},  /* no difference between legacy and bcp */
6327         {"foo",         NULL},  /* unknown, bcp ill-formed */
6328         {"ZZ",          "$IN"}, /* unknown, bcp well-formed -  */
6329         {NULL,          NULL}
6330     };
6331 
6332     int32_t i;
6333     for (i = 0; DATA[i][0] != NULL; i++) {
6334         const char* keyword = DATA[i][0];
6335         const char* expected = DATA[i][1];
6336         const char* bcpKey = NULL;
6337 
6338         bcpKey = uloc_toUnicodeLocaleKey(keyword);
6339         if (expected == NULL) {
6340             if (bcpKey != NULL) {
6341                 log_err("toUnicodeLocaleKey: keyword=%s => %s, expected=NULL\n", keyword, bcpKey);
6342             }
6343         } else if (bcpKey == NULL) {
6344             log_data_err("toUnicodeLocaleKey: keyword=%s => NULL, expected=%s\n", keyword, expected);
6345         } else if (uprv_strcmp(expected, "$IN") == 0) {
6346             if (bcpKey != keyword) {
6347                 log_err("toUnicodeLocaleKey: keyword=%s => %s, expected=%s(input pointer)\n", keyword, bcpKey, keyword);
6348             }
6349         } else if (uprv_strcmp(bcpKey, expected) != 0) {
6350             log_err("toUnicodeLocaleKey: keyword=%s => %s, expected=%s\n", keyword, bcpKey, expected);
6351         }
6352     }
6353 }
6354 
TestBug20321UnicodeLocaleKey(void)6355 static void TestBug20321UnicodeLocaleKey(void)
6356 {
6357     // key = alphanum alpha ;
6358     static const char* invalid[] = {
6359         "a0",
6360         "00",
6361         "a@",
6362         "0@",
6363         "@a",
6364         "@a",
6365         "abc",
6366         "0bc",
6367     };
6368     for (int i = 0; i < UPRV_LENGTHOF(invalid); i++) {
6369         const char* bcpKey = NULL;
6370         bcpKey = uloc_toUnicodeLocaleKey(invalid[i]);
6371         if (bcpKey != NULL) {
6372             log_err("toUnicodeLocaleKey: keyword=%s => %s, expected=NULL\n", invalid[i], bcpKey);
6373         }
6374     }
6375     static const char* valid[] = {
6376         "aa",
6377         "0a",
6378     };
6379     for (int i = 0; i < UPRV_LENGTHOF(valid); i++) {
6380         const char* bcpKey = NULL;
6381         bcpKey = uloc_toUnicodeLocaleKey(valid[i]);
6382         if (bcpKey == NULL) {
6383             log_err("toUnicodeLocaleKey: keyword=%s => NULL, expected!=NULL\n", valid[i]);
6384         }
6385     }
6386 }
6387 
TestToLegacyKey(void)6388 static void TestToLegacyKey(void)
6389 {
6390     /* $IN specifies the result should be the input pointer itself */
6391     static const char* DATA[][2] = {
6392         {"kb",          "colbackwards"},
6393         {"kB",          "colbackwards"},    /* different casing */
6394         {"Collation",   "collation"},   /* keyword itself with different casing */
6395         {"kv",          "kv"},  /* no difference between legacy and bcp */
6396         {"foo",         "$IN"}, /* unknown, bcp ill-formed */
6397         {"ZZ",          "$IN"}, /* unknown, bcp well-formed */
6398         {"e=mc2",       NULL},  /* unknown, bcp/legacy ill-formed */
6399         {NULL,          NULL}
6400     };
6401 
6402     int32_t i;
6403     for (i = 0; DATA[i][0] != NULL; i++) {
6404         const char* keyword = DATA[i][0];
6405         const char* expected = DATA[i][1];
6406         const char* legacyKey = NULL;
6407 
6408         legacyKey = uloc_toLegacyKey(keyword);
6409         if (expected == NULL) {
6410             if (legacyKey != NULL) {
6411                 log_err("toLegacyKey: keyword=%s => %s, expected=NULL\n", keyword, legacyKey);
6412             }
6413         } else if (legacyKey == NULL) {
6414             log_err("toLegacyKey: keyword=%s => NULL, expected=%s\n", keyword, expected);
6415         } else if (uprv_strcmp(expected, "$IN") == 0) {
6416             if (legacyKey != keyword) {
6417                 log_err("toLegacyKey: keyword=%s => %s, expected=%s(input pointer)\n", keyword, legacyKey, keyword);
6418             }
6419         } else if (uprv_strcmp(legacyKey, expected) != 0) {
6420             log_data_err("toUnicodeLocaleKey: keyword=%s, %s, expected=%s\n", keyword, legacyKey, expected);
6421         }
6422     }
6423 }
6424 
TestToUnicodeLocaleType(void)6425 static void TestToUnicodeLocaleType(void)
6426 {
6427     /* $IN specifies the result should be the input pointer itself */
6428     static const char* DATA[][3] = {
6429         {"tz",              "Asia/Kolkata",     "inccu"},
6430         {"calendar",        "gregorian",        "gregory"},
6431         {"ca",              "gregorian",        "gregory"},
6432         {"ca",              "Gregorian",        "gregory"},
6433         {"ca",              "buddhist",         "buddhist"},
6434         {"Calendar",        "Japanese",         "japanese"},
6435         {"calendar",        "Islamic-Civil",    "islamic-civil"},
6436         {"calendar",        "islamicc",         "islamic-civil"},   /* bcp type alias */
6437         {"colalternate",    "NON-IGNORABLE",    "noignore"},
6438         {"colcaselevel",    "yes",              "true"},
6439         {"rg",              "GBzzzz",           "$IN"},
6440         {"tz",              "america/new_york", "usnyc"},
6441         {"tz",              "Asia/Kolkata",     "inccu"},
6442         {"timezone",        "navajo",           "usden"},
6443         {"ca",              "aaaa",             "$IN"},     /* unknown type, well-formed type */
6444         {"ca",              "gregory-japanese-islamic", "$IN"}, /* unknown type, well-formed type */
6445         {"zz",              "gregorian",        NULL},      /* unknown key, ill-formed type */
6446         {"co",              "foo-",             NULL},      /* unknown type, ill-formed type */
6447         {"variableTop",     "00A0",             "$IN"},     /* valid codepoints type */
6448         {"variableTop",     "wxyz",             "$IN"},     /* invalid codepoints type - return as is for now */
6449         {"kr",              "space-punct",      "space-punct"}, /* valid reordercode type */
6450         {"kr",              "digit-spacepunct", NULL},      /* invalid (bcp ill-formed) reordercode type */
6451         {NULL,              NULL,               NULL}
6452     };
6453 
6454     int32_t i;
6455     for (i = 0; DATA[i][0] != NULL; i++) {
6456         const char* keyword = DATA[i][0];
6457         const char* value = DATA[i][1];
6458         const char* expected = DATA[i][2];
6459         const char* bcpType = NULL;
6460 
6461         bcpType = uloc_toUnicodeLocaleType(keyword, value);
6462         if (expected == NULL) {
6463             if (bcpType != NULL) {
6464                 log_err("toUnicodeLocaleType: keyword=%s, value=%s => %s, expected=NULL\n", keyword, value, bcpType);
6465             }
6466         } else if (bcpType == NULL) {
6467             log_data_err("toUnicodeLocaleType: keyword=%s, value=%s => NULL, expected=%s\n", keyword, value, expected);
6468         } else if (uprv_strcmp(expected, "$IN") == 0) {
6469             if (bcpType != value) {
6470                 log_err("toUnicodeLocaleType: keyword=%s, value=%s => %s, expected=%s(input pointer)\n", keyword, value, bcpType, value);
6471             }
6472         } else if (uprv_strcmp(bcpType, expected) != 0) {
6473             log_data_err("toUnicodeLocaleType: keyword=%s, value=%s => %s, expected=%s\n", keyword, value, bcpType, expected);
6474         }
6475     }
6476 }
6477 
TestToLegacyType(void)6478 static void TestToLegacyType(void)
6479 {
6480     /* $IN specifies the result should be the input pointer itself */
6481     static const char* DATA[][3] = {
6482         {"calendar",        "gregory",          "gregorian"},
6483         {"ca",              "gregory",          "gregorian"},
6484         {"ca",              "Gregory",          "gregorian"},
6485         {"ca",              "buddhist",         "buddhist"},
6486         {"Calendar",        "Japanese",         "japanese"},
6487         {"calendar",        "Islamic-Civil",    "islamic-civil"},
6488         {"calendar",        "islamicc",         "islamic-civil"},   /* bcp type alias */
6489         {"colalternate",    "noignore",         "non-ignorable"},
6490         {"colcaselevel",    "true",             "yes"},
6491         {"rg",              "gbzzzz",           "gbzzzz"},
6492         {"tz",              "usnyc",            "America/New_York"},
6493         {"tz",              "inccu",            "Asia/Calcutta"},
6494         {"timezone",        "usden",            "America/Denver"},
6495         {"timezone",        "usnavajo",         "America/Denver"},  /* bcp type alias */
6496         {"colstrength",     "quarternary",      "quaternary"},  /* type alias */
6497         {"ca",              "aaaa",             "$IN"}, /* unknown type */
6498         {"calendar",        "gregory-japanese-islamic", "$IN"}, /* unknown type, well-formed type */
6499         {"zz",              "gregorian",        "$IN"}, /* unknown key, bcp ill-formed type */
6500         {"ca",              "gregorian-calendar",   "$IN"}, /* known key, bcp ill-formed type */
6501         {"co",              "e=mc2",            NULL},  /* known key, ill-formed bcp/legacy type */
6502         {"variableTop",     "00A0",             "$IN"},     /* valid codepoints type */
6503         {"variableTop",     "wxyz",             "$IN"},    /* invalid codepoints type - return as is for now */
6504         {"kr",              "space-punct",      "space-punct"}, /* valid reordercode type */
6505         {"kr",              "digit-spacepunct", "digit-spacepunct"},    /* invalid reordercode type, but ok for legacy syntax */
6506         {NULL,              NULL,               NULL}
6507     };
6508 
6509     int32_t i;
6510     for (i = 0; DATA[i][0] != NULL; i++) {
6511         const char* keyword = DATA[i][0];
6512         const char* value = DATA[i][1];
6513         const char* expected = DATA[i][2];
6514         const char* legacyType = NULL;
6515 
6516         legacyType = uloc_toLegacyType(keyword, value);
6517         if (expected == NULL) {
6518             if (legacyType != NULL) {
6519                 log_err("toLegacyType: keyword=%s, value=%s => %s, expected=NULL\n", keyword, value, legacyType);
6520             }
6521         } else if (legacyType == NULL) {
6522             log_err("toLegacyType: keyword=%s, value=%s => NULL, expected=%s\n", keyword, value, expected);
6523         } else if (uprv_strcmp(expected, "$IN") == 0) {
6524             if (legacyType != value) {
6525                 log_err("toLegacyType: keyword=%s, value=%s => %s, expected=%s(input pointer)\n", keyword, value, legacyType, value);
6526             }
6527         } else if (uprv_strcmp(legacyType, expected) != 0) {
6528             log_data_err("toLegacyType: keyword=%s, value=%s => %s, expected=%s\n", keyword, value, legacyType, expected);
6529         } else {
6530             log_verbose("toLegacyType: keyword=%s, value=%s => %s\n", keyword, value, legacyType);
6531         }
6532     }
6533 }
6534 
6535 
6536 
test_unicode_define(const char * namech,char ch,const char * nameu,UChar uch)6537 static void test_unicode_define(const char *namech, char ch, const char *nameu, UChar uch)
6538 {
6539   UChar asUch[1];
6540   asUch[0]=0;
6541   log_verbose("Testing whether %s[\\x%02x,'%c'] == %s[U+%04X]\n", namech, ch,(int)ch, nameu, (int) uch);
6542   u_charsToUChars(&ch, asUch, 1);
6543   if(asUch[0] != uch) {
6544     log_err("FAIL:  %s[\\x%02x,'%c'] maps to U+%04X, but %s = U+%04X\n", namech, ch, (int)ch, (int)asUch[0], nameu, (int)uch);
6545   } else {
6546     log_verbose(" .. OK, == U+%04X\n", (int)asUch[0]);
6547   }
6548 }
6549 
6550 #define TEST_UNICODE_DEFINE(x,y) test_unicode_define(#x, (char)(x), #y, (UChar)(y))
6551 
TestUnicodeDefines(void)6552 static void TestUnicodeDefines(void) {
6553   TEST_UNICODE_DEFINE(ULOC_KEYWORD_SEPARATOR, ULOC_KEYWORD_SEPARATOR_UNICODE);
6554   TEST_UNICODE_DEFINE(ULOC_KEYWORD_ASSIGN, ULOC_KEYWORD_ASSIGN_UNICODE);
6555   TEST_UNICODE_DEFINE(ULOC_KEYWORD_ITEM_SEPARATOR, ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE);
6556 }
6557 
TestIsRightToLeft()6558 static void TestIsRightToLeft() {
6559     // API test only. More test cases in intltest/LocaleTest.
6560     if(uloc_isRightToLeft("root") || !uloc_isRightToLeft("EN-HEBR")) {
6561         log_err("uloc_isRightToLeft() failed");
6562     }
6563 }
6564 
6565 typedef struct {
6566     const char * badLocaleID;
6567     const char * displayLocale;
6568     const char * expectedName;
6569     UErrorCode   expectedStatus;
6570 } BadLocaleItem;
6571 
6572 static const BadLocaleItem badLocaleItems[] = {
6573     { "-9223372036854775808", "en", "Unknown language (9223372036854775808)", U_USING_DEFAULT_WARNING },
6574     /* add more in the future */
6575     { NULL, NULL, NULL, U_ZERO_ERROR } /* terminator */
6576 };
6577 
6578 enum { kUBufDispNameMax = 128, kBBufDispNameMax = 256 };
6579 
TestBadLocaleIDs()6580 static void TestBadLocaleIDs() {
6581     const BadLocaleItem* itemPtr;
6582     for (itemPtr = badLocaleItems; itemPtr->badLocaleID != NULL; itemPtr++) {
6583         UChar ubufExpect[kUBufDispNameMax], ubufGet[kUBufDispNameMax];
6584         UErrorCode status = U_ZERO_ERROR;
6585         int32_t ulenExpect = u_unescape(itemPtr->expectedName, ubufExpect, kUBufDispNameMax);
6586         int32_t ulenGet = uloc_getDisplayName(itemPtr->badLocaleID, itemPtr->displayLocale, ubufGet, kUBufDispNameMax, &status);
6587         if (status != itemPtr->expectedStatus ||
6588                 (U_SUCCESS(status) && (ulenGet != ulenExpect || u_strncmp(ubufGet, ubufExpect, ulenExpect) != 0))) {
6589             char bbufExpect[kBBufDispNameMax], bbufGet[kBBufDispNameMax];
6590             u_austrncpy(bbufExpect, ubufExpect, ulenExpect);
6591             u_austrncpy(bbufGet, ubufGet, ulenGet);
6592             log_err("FAIL: For localeID %s, displayLocale %s, calling uloc_getDisplayName:\n"
6593                     "    expected status %-26s, name (len %2d): %s\n"
6594                     "    got      status %-26s, name (len %2d): %s\n",
6595                     itemPtr->badLocaleID, itemPtr->displayLocale,
6596                     u_errorName(itemPtr->expectedStatus), ulenExpect, bbufExpect,
6597                     u_errorName(status), ulenGet, bbufGet );
6598         }
6599     }
6600 }
6601 
6602 // Test case for ICU-20370.
6603 // The issue shows as an Addresss Sanitizer failure.
TestBug20370()6604 static void TestBug20370() {
6605     const char *localeID = "x-privatebutreallylongtagfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar";
6606     uint32_t lcid = uloc_getLCID(localeID);
6607     if (lcid != 0) {
6608         log_err("FAIL: Expected LCID value of 0 for invalid localeID input.");
6609     }
6610 }
6611 
6612 // Test case for ICU-20149
6613 // Handle the duplicate U extension attribute
TestBug20149()6614 static void TestBug20149() {
6615     const char *localeID = "zh-u-foo-foo-co-pinyin";
6616     char locale[256];
6617     UErrorCode status = U_ZERO_ERROR;
6618     int32_t parsedLen;
6619     locale[0] = '\0';
6620     uloc_forLanguageTag(localeID, locale, sizeof(locale), &parsedLen, &status);
6621     if (U_FAILURE(status) ||
6622         0 !=strcmp("zh@attribute=foo;collation=pinyin", locale)) {
6623         log_err("ERROR: in uloc_forLanguageTag %s return %s\n", myErrorName(status), locale);
6624     }
6625 }
6626