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