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