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