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