]> git.saurik.com Git - apple/icu.git/blob - icuSources/test/cintltst/cloctst.c
ICU-66108.tar.gz
[apple/icu.git] / icuSources / test / cintltst / cloctst.c
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4 * COPYRIGHT:
5 * Copyright (c) 1997-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 ********************************************************************/
8 /*****************************************************************************
9 *
10 * File CLOCTST.C
11 *
12 * Modification History:
13 * Name Description
14 * Madhu Katragadda Ported for C API
15 ******************************************************************************
16 */
17 #include "cloctst.h"
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include "cintltst.h"
22 #include "cmemory.h"
23 #include "cstring.h"
24 #include "uparse.h"
25 #include "uresimp.h"
26 #include "uassert.h"
27 #include "cmemory.h"
28
29 #include "unicode/putil.h"
30 #include "unicode/ubrk.h"
31 #include "unicode/uchar.h"
32 #include "unicode/ucol.h"
33 #include "unicode/udat.h"
34 #include "unicode/uloc.h"
35 #include "unicode/umsg.h"
36 #include "unicode/ures.h"
37 #include "unicode/uset.h"
38 #include "unicode/ustring.h"
39 #include "unicode/utypes.h"
40 #include "unicode/ulocdata.h"
41 #include "unicode/uldnames.h"
42 #include "unicode/parseerr.h" /* may not be included with some uconfig switches */
43 #include "udbgutil.h"
44 #if !U_PLATFORM_HAS_WIN32_API
45 #include "unicode/ualoc.h" /* Apple-specific */
46 #endif
47
48 static void TestNullDefault(void);
49 static void TestNonexistentLanguageExemplars(void);
50 static void TestLocDataErrorCodeChaining(void);
51 static void TestLocDataWithRgTag(void);
52 static void TestLanguageExemplarsFallbacks(void);
53 static void TestDisplayNameBrackets(void);
54
55 static void TestUnicodeDefines(void);
56
57 static void TestIsRightToLeft(void);
58 static void TestBadLocaleIDs(void);
59 static void TestBug20370(void);
60 static void TestBug20321UnicodeLocaleKey(void);
61
62 static void TestUldnNameVariants(void);
63 static void TestRootUndEmpty(void);
64 #if !U_PLATFORM_HAS_WIN32_API
65 // These test functionality that does not exist in the AAS/Windows version of Apple ICU
66 static void TestGetLanguagesForRegion(void);
67 static void TestGetAppleParent(void);
68 static void TestAppleLocalizationsToUsePerf(void);
69 static void TestAppleLocalizationsToUse(void);
70 #endif
71 static void TestNorwegianDisplayNames(void);
72 static void TestSpecificDisplayNames(void);
73
74 void PrintDataTable();
75
76 /*---------------------------------------------------
77 table of valid data
78 --------------------------------------------------- */
79 #define LOCALE_SIZE 9
80 #define LOCALE_INFO_SIZE 28
81
82 static const char* const rawData2[LOCALE_INFO_SIZE][LOCALE_SIZE] = {
83 /* language code */
84 { "en", "fr", "ca", "el", "no", "zh", "de", "es", "ja" },
85 /* script code */
86 { "", "", "", "", "", "", "", "", "" },
87 /* country code */
88 { "US", "FR", "ES", "GR", "NO", "CN", "DE", "", "JP" },
89 /* variant code */
90 { "", "", "", "", "NY", "", "", "", "" },
91 /* full name */
92 { "en_US", "fr_FR", "ca_ES",
93 "el_GR", "no_NO_NY", "zh_Hans_CN",
94 "de_DE@collation=phonebook", "es@collation=traditional", "ja_JP@calendar=japanese" },
95 /* ISO-3 language */
96 { "eng", "fra", "cat", "ell", "nor", "zho", "deu", "spa", "jpn" },
97 /* ISO-3 country */
98 { "USA", "FRA", "ESP", "GRC", "NOR", "CHN", "DEU", "", "JPN" },
99 /* LCID */
100 { "409", "40c", "403", "408", "814", "804", "10407", "40a", "411" },
101
102 /* display language (English) */
103 { "English", "French", "Catalan", "Greek", "Norwegian", "Chinese", "German", "Spanish", "Japanese" },
104 /* display script code (English) */
105 { "", "", "", "", "", "Simplified Han", "", "", "" },
106 /* display country (English) */
107 { "United States", "France", "Spain", "Greece", "Norway", "China mainland", "Germany", "", "Japan" },
108 /* display variant (English) */
109 { "", "", "", "", "NY", "", "", "", "" },
110 /* display name (English) */
111 { "English (United States)", "French (France)", "Catalan (Spain)",
112 "Greek (Greece)", "Norwegian (Norway, NY)", "Chinese, Simplified (China mainland)",
113 "German (Germany, Sort Order=Phonebook Sort Order)", "Spanish (Sort Order=Traditional Sort Order)", "Japanese (Japan, Calendar=Japanese Calendar)" },
114
115 /* display language (French) */
116 { "anglais", "fran\\u00E7ais", "catalan", "grec", "norv\\u00E9gien", "chinois", "allemand", "espagnol", "japonais" },
117 /* display script code (French) */
118 { "", "", "", "", "", "sinogrammes simplifi\\u00e9s", "", "", "" },
119 /* display country (French) */
120 { "\\u00C9tats-Unis", "France", "Espagne", "Gr\\u00E8ce", "Norv\\u00E8ge", "Chine continentale", "Allemagne", "", "Japon" },
121 /* display variant (French) */
122 { "", "", "", "", "NY", "", "", "", "" },
123 /* display name (French) */
124 { "anglais (\\u00C9tats-Unis)", "fran\\u00E7ais (France)", "catalan (Espagne)",
125 "grec (Gr\\u00E8ce)", "norv\\u00E9gien (Norv\\u00E8ge, NY)", "chinois simplifi\\u00e9 (Chine continentale)",
126 "allemand (Allemagne, ordre de tri=ordre de l\\u2019annuaire)", "espagnol (ordre de tri=ordre traditionnel)", "japonais (Japon, calendrier=calendrier japonais)" },
127
128 /* display language (Catalan) */
129 { "angl\\u00E8s", "franc\\u00E8s", "catal\\u00E0", "grec", "noruec", "xin\\u00E8s", "alemany", "espanyol", "japon\\u00E8s" },
130 /* display script code (Catalan) */
131 { "", "", "", "", "", "han simplificat", "", "", "" },
132 /* display country (Catalan) */
133 { "Estats Units", "Fran\\u00E7a", "Espanya", "Gr\\u00E8cia", "Noruega", "Xina continental", "Alemanya", "", "Jap\\u00F3" },
134 /* display variant (Catalan) */
135 { "", "", "", "", "NY", "", "", "", "" },
136 /* display name (Catalan) */
137 { "angl\\u00E8s (Estats Units)", "franc\\u00E8s (Fran\\u00E7a)", "catal\\u00E0 (Espanya)",
138 "grec (Gr\\u00E8cia)", "noruec (Noruega, NY)", "xin\\u00E8s simplificat (Xina continental)",
139 "alemany (Alemanya, ordenaci\\u00F3=ordre de la guia telef\\u00F2nica)", "espanyol (ordenaci\\u00F3=ordre tradicional)", "japon\\u00E8s (Jap\\u00F3, calendari=calendari japon\\u00e8s)" },
140
141 /* display language (Greek) */
142 {
143 "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac",
144 "\\u0393\\u03b1\\u03bb\\u03bb\\u03b9\\u03ba\\u03ac",
145 "\\u039a\\u03b1\\u03c4\\u03b1\\u03bb\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac",
146 "\\u0395\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac",
147 "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac",
148 "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC",
149 "\\u0393\\u03B5\\u03C1\\u03BC\\u03B1\\u03BD\\u03B9\\u03BA\\u03AC",
150 "\\u0399\\u03C3\\u03C0\\u03B1\\u03BD\\u03B9\\u03BA\\u03AC",
151 "\\u0399\\u03B1\\u03C0\\u03C9\\u03BD\\u03B9\\u03BA\\u03AC"
152 },
153 /* display script code (Greek) */
154
155 { "", "", "", "", "", "\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03bf \\u03a7\\u03b1\\u03bd", "", "", "" },
156 /* display country (Greek) */
157 {
158 "\\u0397\\u03BD\\u03C9\\u03BC\\u03AD\\u03BD\\u03B5\\u03C2 \\u03A0\\u03BF\\u03BB\\u03B9\\u03C4\\u03B5\\u03AF\\u03B5\\u03C2",
159 "\\u0393\\u03b1\\u03bb\\u03bb\\u03af\\u03b1",
160 "\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1",
161 "\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1",
162 "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1",
163 "\\u039A\\u03AF\\u03BD\\u03B1 \\u03B7\\u03C0\\u03B5\\u03B9\\u03C1\\u03C9\\u03C4\\u03B9\\u03BA\\u03AE",
164 "\\u0393\\u03B5\\u03C1\\u03BC\\u03B1\\u03BD\\u03AF\\u03B1",
165 "",
166 "\\u0399\\u03B1\\u03C0\\u03C9\\u03BD\\u03AF\\u03B1"
167 },
168 /* display variant (Greek) */
169 { "", "", "", "", "NY", "", "", "", "" }, /* TODO: currently there is no translation for NY in Greek fix this test when we have it */
170 /* display name (Greek) */
171 {
172 "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac (\\u0397\\u03BD\\u03C9\\u03BC\\u03AD\\u03BD\\u03B5\\u03C2 \\u03A0\\u03BF\\u03BB\\u03B9\\u03C4\\u03B5\\u03AF\\u03B5\\u03C2)",
173 "\\u0393\\u03b1\\u03bb\\u03bb\\u03b9\\u03ba\\u03ac (\\u0393\\u03b1\\u03bb\\u03bb\\u03af\\u03b1)",
174 "\\u039a\\u03b1\\u03c4\\u03b1\\u03bb\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1)",
175 "\\u0395\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac (\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1)",
176 "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac (\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1, NY)",
177 "\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03b1 \\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC (\\u039A\\u03AF\\u03BD\\u03B1 \\u03B7\\u03C0\\u03B5\\u03B9\\u03C1\\u03C9\\u03C4\\u03B9\\u03BA\\u03AE)",
178 "\\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)",
179 "\\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)",
180 "\\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)"
181 }
182 };
183
184 static UChar*** dataTable=0;
185 enum {
186 ENGLISH = 0,
187 FRENCH = 1,
188 CATALAN = 2,
189 GREEK = 3,
190 NORWEGIAN = 4
191 };
192
193 enum {
194 LANG = 0,
195 SCRIPT = 1,
196 CTRY = 2,
197 VAR = 3,
198 NAME = 4,
199 LANG3 = 5,
200 CTRY3 = 6,
201 LCID = 7,
202 DLANG_EN = 8,
203 DSCRIPT_EN = 9,
204 DCTRY_EN = 10,
205 DVAR_EN = 11,
206 DNAME_EN = 12,
207 DLANG_FR = 13,
208 DSCRIPT_FR = 14,
209 DCTRY_FR = 15,
210 DVAR_FR = 16,
211 DNAME_FR = 17,
212 DLANG_CA = 18,
213 DSCRIPT_CA = 19,
214 DCTRY_CA = 20,
215 DVAR_CA = 21,
216 DNAME_CA = 22,
217 DLANG_EL = 23,
218 DSCRIPT_EL = 24,
219 DCTRY_EL = 25,
220 DVAR_EL = 26,
221 DNAME_EL = 27
222 };
223
224 #define TESTCASE(name) addTest(root, &name, "tsutil/cloctst/" #name)
225
226 void addLocaleTest(TestNode** root);
227
228 void addLocaleTest(TestNode** root)
229 {
230 TESTCASE(TestObsoleteNames); /* srl- move */
231 TESTCASE(TestBasicGetters);
232 TESTCASE(TestNullDefault);
233 TESTCASE(TestPrefixes);
234 TESTCASE(TestSimpleResourceInfo);
235 TESTCASE(TestDisplayNames);
236 TESTCASE(TestGetAvailableLocales);
237 TESTCASE(TestGetAvailableLocalesByType);
238 TESTCASE(TestDataDirectory);
239 #if !UCONFIG_NO_FILE_IO && !UCONFIG_NO_LEGACY_CONVERSION
240 TESTCASE(TestISOFunctions);
241 #endif
242 TESTCASE(TestISO3Fallback);
243 TESTCASE(TestUninstalledISO3Names);
244 TESTCASE(TestSimpleDisplayNames);
245 TESTCASE(TestVariantParsing);
246 TESTCASE(TestKeywordVariants);
247 TESTCASE(TestKeywordVariantParsing);
248 TESTCASE(TestCanonicalization);
249 TESTCASE(TestCanonicalizationBuffer);
250 TESTCASE(TestKeywordSet);
251 TESTCASE(TestKeywordSetError);
252 TESTCASE(TestDisplayKeywords);
253 TESTCASE(TestDisplayKeywordValues);
254 TESTCASE(TestGetBaseName);
255 #if !UCONFIG_NO_FILE_IO
256 TESTCASE(TestGetLocale);
257 #endif
258 TESTCASE(TestDisplayNameWarning);
259 TESTCASE(TestNonexistentLanguageExemplars);
260 TESTCASE(TestLocDataErrorCodeChaining);
261 TESTCASE(TestLocDataWithRgTag);
262 TESTCASE(TestLanguageExemplarsFallbacks);
263 TESTCASE(TestCalendar);
264 TESTCASE(TestDateFormat);
265 TESTCASE(TestCollation);
266 TESTCASE(TestULocale);
267 TESTCASE(TestUResourceBundle);
268 TESTCASE(TestDisplayName);
269 TESTCASE(TestAcceptLanguage);
270 TESTCASE(TestGetLocaleForLCID);
271 TESTCASE(TestOrientation);
272 TESTCASE(TestLikelySubtags);
273 TESTCASE(TestToLanguageTag);
274 TESTCASE(TestBug20132);
275 TESTCASE(TestBug20149);
276 TESTCASE(TestForLanguageTag);
277 TESTCASE(TestLangAndRegionCanonicalize);
278 TESTCASE(TestTrailingNull);
279 TESTCASE(TestUnicodeDefines);
280 TESTCASE(TestEnglishExemplarCharacters);
281 TESTCASE(TestDisplayNameBrackets);
282 TESTCASE(TestIsRightToLeft);
283 TESTCASE(TestToUnicodeLocaleKey);
284 TESTCASE(TestToLegacyKey);
285 TESTCASE(TestToUnicodeLocaleType);
286 TESTCASE(TestToLegacyType);
287 TESTCASE(TestBadLocaleIDs);
288 TESTCASE(TestBug20370);
289 TESTCASE(TestBug20321UnicodeLocaleKey);
290 TESTCASE(TestUldnNameVariants);
291 TESTCASE(TestRootUndEmpty);
292 #if !U_PLATFORM_HAS_WIN32_API
293 // These test functionality that does not exist in the AAS/Windows version of Apple ICU
294 TESTCASE(TestGetLanguagesForRegion);
295 TESTCASE(TestGetAppleParent);
296 TESTCASE(TestAppleLocalizationsToUsePerf); // must be the first test to call ualoc_localizationsToUse
297 TESTCASE(TestAppleLocalizationsToUse);
298 #endif
299 TESTCASE(TestNorwegianDisplayNames);
300 TESTCASE(TestSpecificDisplayNames);
301 }
302
303
304 /* testing uloc(), uloc_getName(), uloc_getLanguage(), uloc_getVariant(), uloc_getCountry() */
305 static void TestBasicGetters() {
306 int32_t i;
307 int32_t cap;
308 UErrorCode status = U_ZERO_ERROR;
309 char *testLocale = 0;
310 char *temp = 0, *name = 0;
311 log_verbose("Testing Basic Getters\n");
312 for (i = 0; i < LOCALE_SIZE; i++) {
313 testLocale=(char*)malloc(sizeof(char) * (strlen(rawData2[NAME][i])+1));
314 strcpy(testLocale,rawData2[NAME][i]);
315
316 log_verbose("Testing %s .....\n", testLocale);
317 cap=uloc_getLanguage(testLocale, NULL, 0, &status);
318 if(status==U_BUFFER_OVERFLOW_ERROR){
319 status=U_ZERO_ERROR;
320 temp=(char*)malloc(sizeof(char) * (cap+1));
321 uloc_getLanguage(testLocale, temp, cap+1, &status);
322 }
323 if(U_FAILURE(status)){
324 log_err("ERROR: in uloc_getLanguage %s\n", myErrorName(status));
325 }
326 if (0 !=strcmp(temp,rawData2[LANG][i])) {
327 log_err(" Language code mismatch: %s versus %s\n", temp, rawData2[LANG][i]);
328 }
329
330
331 cap=uloc_getCountry(testLocale, temp, cap, &status);
332 if(status==U_BUFFER_OVERFLOW_ERROR){
333 status=U_ZERO_ERROR;
334 temp=(char*)realloc(temp, sizeof(char) * (cap+1));
335 uloc_getCountry(testLocale, temp, cap+1, &status);
336 }
337 if(U_FAILURE(status)){
338 log_err("ERROR: in uloc_getCountry %s\n", myErrorName(status));
339 }
340 if (0 != strcmp(temp, rawData2[CTRY][i])) {
341 log_err(" Country code mismatch: %s versus %s\n", temp, rawData2[CTRY][i]);
342
343 }
344
345 cap=uloc_getVariant(testLocale, temp, cap, &status);
346 if(status==U_BUFFER_OVERFLOW_ERROR){
347 status=U_ZERO_ERROR;
348 temp=(char*)realloc(temp, sizeof(char) * (cap+1));
349 uloc_getVariant(testLocale, temp, cap+1, &status);
350 }
351 if(U_FAILURE(status)){
352 log_err("ERROR: in uloc_getVariant %s\n", myErrorName(status));
353 }
354 if (0 != strcmp(temp, rawData2[VAR][i])) {
355 log_err("Variant code mismatch: %s versus %s\n", temp, rawData2[VAR][i]);
356 }
357
358 cap=uloc_getName(testLocale, NULL, 0, &status);
359 if(status==U_BUFFER_OVERFLOW_ERROR){
360 status=U_ZERO_ERROR;
361 name=(char*)malloc(sizeof(char) * (cap+1));
362 uloc_getName(testLocale, name, cap+1, &status);
363 } else if(status==U_ZERO_ERROR) {
364 log_err("ERROR: in uloc_getName(%s,NULL,0,..), expected U_BUFFER_OVERFLOW_ERROR!\n", testLocale);
365 }
366 if(U_FAILURE(status)){
367 log_err("ERROR: in uloc_getName %s\n", myErrorName(status));
368 }
369 if (0 != strcmp(name, rawData2[NAME][i])){
370 log_err(" Mismatch in getName: %s versus %s\n", name, rawData2[NAME][i]);
371 }
372
373 free(temp);
374 free(name);
375
376 free(testLocale);
377 }
378 }
379
380 static void TestNullDefault() {
381 UErrorCode status = U_ZERO_ERROR;
382 char original[ULOC_FULLNAME_CAPACITY];
383
384 uprv_strcpy(original, uloc_getDefault());
385 uloc_setDefault("qq_BLA", &status);
386 if (uprv_strcmp(uloc_getDefault(), "qq_BLA") != 0) {
387 log_err(" Mismatch in uloc_setDefault: qq_BLA versus %s\n", uloc_getDefault());
388 }
389 uloc_setDefault(NULL, &status);
390 if (uprv_strcmp(uloc_getDefault(), original) != 0) {
391 log_err(" uloc_setDefault(NULL, &status) didn't get the default locale back!\n");
392 }
393
394 {
395 /* Test that set & get of default locale work, and that
396 * default locales are cached and reused, and not overwritten.
397 */
398 const char *n_en_US;
399 const char *n_fr_FR;
400 const char *n2_en_US;
401
402 status = U_ZERO_ERROR;
403 uloc_setDefault("en_US", &status);
404 n_en_US = uloc_getDefault();
405 if (strcmp(n_en_US, "en_US") != 0) {
406 log_err("Wrong result from uloc_getDefault(). Expected \"en_US\", got \"%s\"\n", n_en_US);
407 }
408
409 uloc_setDefault("fr_FR", &status);
410 n_fr_FR = uloc_getDefault();
411 if (strcmp(n_en_US, "en_US") != 0) {
412 log_err("uloc_setDefault altered previously default string."
413 "Expected \"en_US\", got \"%s\"\n", n_en_US);
414 }
415 if (strcmp(n_fr_FR, "fr_FR") != 0) {
416 log_err("Wrong result from uloc_getDefault(). Expected \"fr_FR\", got %s\n", n_fr_FR);
417 }
418
419 uloc_setDefault("en_US", &status);
420 n2_en_US = uloc_getDefault();
421 if (strcmp(n2_en_US, "en_US") != 0) {
422 log_err("Wrong result from uloc_getDefault(). Expected \"en_US\", got \"%s\"\n", n_en_US);
423 }
424 if (n2_en_US != n_en_US) {
425 log_err("Default locale cache failed to reuse en_US locale.\n");
426 }
427
428 if (U_FAILURE(status)) {
429 log_err("Failure returned from uloc_setDefault - \"%s\"\n", u_errorName(status));
430 }
431
432 }
433
434 }
435 /* Test the i- and x- and @ and . functionality
436 */
437
438 #define PREFIXBUFSIZ 128
439
440 static void TestPrefixes() {
441 int row = 0;
442 int n;
443 const char *loc, *expected;
444
445 static const char * const testData[][7] =
446 {
447 /* NULL canonicalize() column means "expect same as getName()" */
448 {"sv", "", "FI", "AL", "sv-fi-al", "sv_FI_AL", NULL},
449 {"en", "", "GB", "", "en-gb", "en_GB", NULL},
450 {"i-hakka", "", "MT", "XEMXIJA", "i-hakka_MT_XEMXIJA", "i-hakka_MT_XEMXIJA", NULL},
451 {"i-hakka", "", "CN", "", "i-hakka_CN", "i-hakka_CN", NULL},
452 {"i-hakka", "", "MX", "", "I-hakka_MX", "i-hakka_MX", NULL},
453 {"x-klingon", "", "US", "SANJOSE", "X-KLINGON_us_SANJOSE", "x-klingon_US_SANJOSE", NULL},
454 {"hy", "", "", "AREVMDA", "hy_AREVMDA", "hy__AREVMDA", "hyw"},
455 {"de", "", "", "1901", "de-1901", "de__1901", NULL},
456 {"mr", "", "", "", "mr.utf8", "mr.utf8", "mr"},
457 {"de", "", "TV", "", "de-tv.koi8r", "de_TV.koi8r", "de_TV"},
458 {"x-piglatin", "", "ML", "", "x-piglatin_ML.MBE", "x-piglatin_ML.MBE", "x-piglatin_ML"}, /* Multibyte English */
459 {"i-cherokee", "","US", "", "i-Cherokee_US.utf7", "i-cherokee_US.utf7", "i-cherokee_US"},
460 {"x-filfli", "", "MT", "FILFLA", "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA"},
461 {"no", "", "NO", "NY", "no-no-ny.utf32@B", "no_NO_NY.utf32@B", "no_NO_NY_B"},
462 {"no", "", "NO", "", "no-no.utf32@B", "no_NO.utf32@B", "no_NO_B"},
463 {"no", "", "", "NY", "no__ny", "no__NY", NULL},
464 {"no", "", "", "", "no@ny", "no@ny", "no__NY"},
465 {"el", "Latn", "", "", "el-latn", "el_Latn", NULL},
466 {"en", "Cyrl", "RU", "", "en-cyrl-ru", "en_Cyrl_RU", NULL},
467 {"qq", "Qqqq", "QQ", "QQ", "qq_Qqqq_QQ_QQ", "qq_Qqqq_QQ_QQ", NULL},
468 {"qq", "Qqqq", "", "QQ", "qq_Qqqq__QQ", "qq_Qqqq__QQ", NULL},
469 {"ab", "Cdef", "GH", "IJ", "ab_cdef_gh_ij", "ab_Cdef_GH_IJ", NULL}, /* total garbage */
470
471 // Before ICU 64, ICU locale canonicalization had some additional mappings.
472 // They were removed for ICU-20187 "drop support for long-obsolete locale ID variants".
473 // The following now use standard canonicalization.
474 {"zh", "Hans", "", "PINYIN", "zh-Hans-pinyin", "zh_Hans__PINYIN", "zh_Hans__PINYIN"},
475 {"zh", "Hant", "TW", "STROKE", "zh-hant_TW_STROKE", "zh_Hant_TW_STROKE", "zh_Hant_TW_STROKE"},
476
477 {NULL,NULL,NULL,NULL,NULL,NULL,NULL}
478 };
479
480 static const char * const testTitles[] = {
481 "uloc_getLanguage()",
482 "uloc_getScript()",
483 "uloc_getCountry()",
484 "uloc_getVariant()",
485 "name",
486 "uloc_getName()",
487 "uloc_canonicalize()"
488 };
489
490 char buf[PREFIXBUFSIZ];
491 int32_t len;
492 UErrorCode err;
493
494
495 for(row=0;testData[row][0] != NULL;row++) {
496 loc = testData[row][NAME];
497 log_verbose("Test #%d: %s\n", row, loc);
498
499 err = U_ZERO_ERROR;
500 len=0;
501 buf[0]=0;
502 for(n=0;n<=(NAME+2);n++) {
503 if(n==NAME) continue;
504
505 for(len=0;len<PREFIXBUFSIZ;len++) {
506 buf[len] = '%'; /* Set a tripwire.. */
507 }
508 len = 0;
509
510 switch(n) {
511 case LANG:
512 len = uloc_getLanguage(loc, buf, PREFIXBUFSIZ, &err);
513 break;
514
515 case SCRIPT:
516 len = uloc_getScript(loc, buf, PREFIXBUFSIZ, &err);
517 break;
518
519 case CTRY:
520 len = uloc_getCountry(loc, buf, PREFIXBUFSIZ, &err);
521 break;
522
523 case VAR:
524 len = uloc_getVariant(loc, buf, PREFIXBUFSIZ, &err);
525 break;
526
527 case NAME+1:
528 len = uloc_getName(loc, buf, PREFIXBUFSIZ, &err);
529 break;
530
531 case NAME+2:
532 len = uloc_canonicalize(loc, buf, PREFIXBUFSIZ, &err);
533 break;
534
535 default:
536 strcpy(buf, "**??");
537 len=4;
538 }
539
540 if(U_FAILURE(err)) {
541 log_err("#%d: %s on %s: err %s\n",
542 row, testTitles[n], loc, u_errorName(err));
543 } else {
544 log_verbose("#%d: %s on %s: -> [%s] (length %d)\n",
545 row, testTitles[n], loc, buf, len);
546
547 if(len != (int32_t)strlen(buf)) {
548 log_err("#%d: %s on %s: -> [%s] (length returned %d, actual %d!)\n",
549 row, testTitles[n], loc, buf, len, strlen(buf)+1);
550
551 }
552
553 /* see if they smashed something */
554 if(buf[len+1] != '%') {
555 log_err("#%d: %s on %s: -> [%s] - wrote [%X] out ofbounds!\n",
556 row, testTitles[n], loc, buf, buf[len+1]);
557 }
558
559 expected = testData[row][n];
560 if (expected == NULL && n == (NAME+2)) {
561 /* NULL expected canonicalize() means "expect same as getName()" */
562 expected = testData[row][NAME+1];
563 }
564 if(strcmp(buf, expected)) {
565 log_err("#%d: %s on %s: -> [%s] (expected '%s'!)\n",
566 row, testTitles[n], loc, buf, expected);
567
568 }
569 }
570 }
571 }
572 }
573
574
575 /* testing uloc_getISO3Language(), uloc_getISO3Country(), */
576 static void TestSimpleResourceInfo() {
577 int32_t i;
578 char* testLocale = 0;
579 UChar* expected = 0;
580
581 const char* temp;
582 char temp2[20];
583 testLocale=(char*)malloc(sizeof(char) * 1);
584 expected=(UChar*)malloc(sizeof(UChar) * 1);
585
586 setUpDataTable();
587 log_verbose("Testing getISO3Language and getISO3Country\n");
588 for (i = 0; i < LOCALE_SIZE; i++) {
589
590 testLocale=(char*)realloc(testLocale, sizeof(char) * (u_strlen(dataTable[NAME][i])+1));
591 u_austrcpy(testLocale, dataTable[NAME][i]);
592
593 log_verbose("Testing %s ......\n", testLocale);
594
595 temp=uloc_getISO3Language(testLocale);
596 expected=(UChar*)realloc(expected, sizeof(UChar) * (strlen(temp) + 1));
597 u_uastrcpy(expected,temp);
598 if (0 != u_strcmp(expected, dataTable[LANG3][i])) {
599 log_err(" ISO-3 language code mismatch: %s versus %s\n", austrdup(expected),
600 austrdup(dataTable[LANG3][i]));
601 }
602
603 temp=uloc_getISO3Country(testLocale);
604 expected=(UChar*)realloc(expected, sizeof(UChar) * (strlen(temp) + 1));
605 u_uastrcpy(expected,temp);
606 if (0 != u_strcmp(expected, dataTable[CTRY3][i])) {
607 log_err(" ISO-3 Country code mismatch: %s versus %s\n", austrdup(expected),
608 austrdup(dataTable[CTRY3][i]));
609 }
610 sprintf(temp2, "%x", (int)uloc_getLCID(testLocale));
611 if (strcmp(temp2, rawData2[LCID][i]) != 0) {
612 log_err("LCID mismatch: %s versus %s\n", temp2 , rawData2[LCID][i]);
613 }
614 }
615
616 free(expected);
617 free(testLocale);
618 cleanUpDataTable();
619 }
620
621 /* if len < 0, we convert until we hit UChar 0x0000, which is not output. will add trailing null
622 * if there's room but won't be included in result. result < 0 indicates an error.
623 * Returns the number of chars written (not those that would be written if there's enough room.*/
624 static int32_t UCharsToEscapedAscii(const UChar* utext, int32_t len, char* resultChars, int32_t buflen) {
625 static const struct {
626 char escapedChar;
627 UChar sourceVal;
628 } ESCAPE_MAP[] = {
629 /*a*/ {'a', 0x07},
630 /*b*/ {'b', 0x08},
631 /*e*/ {'e', 0x1b},
632 /*f*/ {'f', 0x0c},
633 /*n*/ {'n', 0x0a},
634 /*r*/ {'r', 0x0d},
635 /*t*/ {'t', 0x09},
636 /*v*/ {'v', 0x0b}
637 };
638 static const int32_t ESCAPE_MAP_LENGTH = UPRV_LENGTHOF(ESCAPE_MAP);
639 static const char HEX_DIGITS[] = {
640 '0', '1', '2', '3', '4', '5', '6', '7',
641 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
642 };
643 int32_t i, j;
644 int32_t resultLen = 0;
645 const int32_t limit = len<0 ? buflen : len; /* buflen is long enough to hit the buffer limit */
646 const int32_t escapeLimit1 = buflen-2;
647 const int32_t escapeLimit2 = buflen-6;
648 UChar uc;
649
650 if(utext==NULL || resultChars==NULL || buflen<0) {
651 return -1;
652 }
653
654 for(i=0;i<limit && resultLen<buflen;++i) {
655 uc=utext[i];
656 if(len<0 && uc==0) {
657 break;
658 }
659 if(uc<0x20) {
660 for(j=0;j<ESCAPE_MAP_LENGTH && uc!=ESCAPE_MAP[j].sourceVal;j++) {
661 }
662 if(j<ESCAPE_MAP_LENGTH) {
663 if(resultLen>escapeLimit1) {
664 break;
665 }
666 resultChars[resultLen++]='\\';
667 resultChars[resultLen++]=ESCAPE_MAP[j].escapedChar;
668 continue;
669 }
670 } else if(uc<0x7f) {
671 u_austrncpy(resultChars + resultLen, &uc, 1);
672 resultLen++;
673 continue;
674 }
675
676 if(resultLen>escapeLimit2) {
677 break;
678 }
679
680 /* have to escape the uchar */
681 resultChars[resultLen++]='\\';
682 resultChars[resultLen++]='u';
683 resultChars[resultLen++]=HEX_DIGITS[(uc>>12)&0xff];
684 resultChars[resultLen++]=HEX_DIGITS[(uc>>8)&0xff];
685 resultChars[resultLen++]=HEX_DIGITS[(uc>>4)&0xff];
686 resultChars[resultLen++]=HEX_DIGITS[uc&0xff];
687 }
688
689 if(resultLen<buflen) {
690 resultChars[resultLen] = 0;
691 }
692
693 return resultLen;
694 }
695
696 /*
697 * Jitterbug 2439 -- markus 20030425
698 *
699 * The lookup of display names must not fall back through the default
700 * locale because that yields useless results.
701 */
702 static void TestDisplayNames()
703 {
704 UChar buffer[100];
705 UErrorCode errorCode=U_ZERO_ERROR;
706 int32_t length;
707 log_verbose("Testing getDisplayName for different locales\n");
708
709 log_verbose(" In locale = en_US...\n");
710 doTestDisplayNames("en_US", DLANG_EN);
711 log_verbose(" In locale = fr_FR....\n");
712 doTestDisplayNames("fr_FR", DLANG_FR);
713 log_verbose(" In locale = ca_ES...\n");
714 doTestDisplayNames("ca_ES", DLANG_CA);
715 log_verbose(" In locale = gr_EL..\n");
716 doTestDisplayNames("el_GR", DLANG_EL);
717
718 /* test that the default locale has a display name for its own language */
719 errorCode=U_ZERO_ERROR;
720 length=uloc_getDisplayLanguage(NULL, NULL, buffer, UPRV_LENGTHOF(buffer), &errorCode);
721 if(U_FAILURE(errorCode) || (length<=3 && buffer[0]<=0x7f)) {
722 /* check <=3 to reject getting the language code as a display name */
723 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));
724 }
725
726 /* test that we get the language code itself for an unknown language, and a default warning */
727 errorCode=U_ZERO_ERROR;
728 length=uloc_getDisplayLanguage("qq", "rr", buffer, UPRV_LENGTHOF(buffer), &errorCode);
729 if(errorCode!=U_USING_DEFAULT_WARNING || length!=2 || buffer[0]!=0x71 || buffer[1]!=0x71) {
730 log_err("error getting the display string for an unknown language - %s\n", u_errorName(errorCode));
731 }
732
733 /* test that we get a default warning for a display name where one component is unknown (4255) */
734 errorCode=U_ZERO_ERROR;
735 length=uloc_getDisplayName("qq_US_POSIX", "en_US", buffer, UPRV_LENGTHOF(buffer), &errorCode);
736 if(errorCode!=U_USING_DEFAULT_WARNING) {
737 log_err("error getting the display name for a locale with an unknown language - %s\n", u_errorName(errorCode));
738 }
739
740 {
741 int32_t i;
742 static const char *aLocale = "es@collation=traditional;calendar=japanese";
743 static const char *testL[] = { "en_US",
744 "fr_FR",
745 "ca_ES",
746 "el_GR" };
747 static const char *expect[] = { "Spanish (Calendar=Japanese Calendar, Sort Order=Traditional Sort Order)", /* note sorted order of keywords */
748 "espagnol (calendrier=calendrier japonais, ordre de tri=ordre traditionnel)",
749 "espanyol (calendari=calendari japon\\u00e8s, ordenaci\\u00f3=ordre tradicional)",
750 "\\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)" };
751 UChar *expectBuffer;
752
753 for(i=0;i<UPRV_LENGTHOF(testL);i++) {
754 errorCode = U_ZERO_ERROR;
755 uloc_getDisplayName(aLocale, testL[i], buffer, UPRV_LENGTHOF(buffer), &errorCode);
756 if(U_FAILURE(errorCode)) {
757 log_err("FAIL in uloc_getDisplayName(%s,%s,..) -> %s\n", aLocale, testL[i], u_errorName(errorCode));
758 } else {
759 expectBuffer = CharsToUChars(expect[i]);
760 if(u_strcmp(buffer,expectBuffer)) {
761 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));
762 } else {
763 log_verbose("pass in uloc_getDisplayName(%s,%s,..) got '%s'\n", aLocale, testL[i], expect[i]);
764 }
765 free(expectBuffer);
766 }
767 }
768 }
769
770 /* test that we properly preflight and return data when there's a non-default pattern,
771 see ticket #8262. */
772 {
773 int32_t i;
774 static const char *locale="az_Cyrl";
775 static const char *displayLocale="ja";
776 static const char *expectedChars =
777 "\\u30a2\\u30bc\\u30eb\\u30d0\\u30a4\\u30b8\\u30e3\\u30f3\\u8a9e"
778 "\\uff08\\u30ad\\u30ea\\u30eb\\u6587\\u5b57\\uff09";
779 UErrorCode ec=U_ZERO_ERROR;
780 UChar result[256];
781 int32_t len;
782 int32_t preflightLen=uloc_getDisplayName(locale, displayLocale, NULL, 0, &ec);
783 /* inconvenient semantics when preflighting, this condition is expected... */
784 if(ec==U_BUFFER_OVERFLOW_ERROR) {
785 ec=U_ZERO_ERROR;
786 }
787 len=uloc_getDisplayName(locale, displayLocale, result, UPRV_LENGTHOF(result), &ec);
788 if(U_FAILURE(ec)) {
789 log_err("uloc_getDisplayName(%s, %s...) returned error: %s",
790 locale, displayLocale, u_errorName(ec));
791 } else {
792 UChar *expected=CharsToUChars(expectedChars);
793 int32_t expectedLen=u_strlen(expected);
794
795 if(len!=expectedLen) {
796 log_data_err("uloc_getDisplayName(%s, %s...) returned string of length %d, expected length %d",
797 locale, displayLocale, len, expectedLen);
798 } else if(preflightLen!=expectedLen) {
799 log_err("uloc_getDisplayName(%s, %s...) returned preflight length %d, expected length %d",
800 locale, displayLocale, preflightLen, expectedLen);
801 } else if(u_strncmp(result, expected, len)) {
802 int32_t cap=len*6+1; /* worst case + space for trailing null */
803 char* resultChars=(char*)malloc(cap);
804 int32_t resultCharsLen=UCharsToEscapedAscii(result, len, resultChars, cap);
805 if(resultCharsLen<0 || resultCharsLen<cap-1) {
806 log_err("uloc_getDisplayName(%s, %s...) mismatch", locale, displayLocale);
807 } else {
808 log_err("uloc_getDisplayName(%s, %s...) returned '%s' but expected '%s'",
809 locale, displayLocale, resultChars, expectedChars);
810 }
811 free(resultChars);
812 resultChars=NULL;
813 } else {
814 /* test all buffer sizes */
815 for(i=len+1;i>=0;--i) {
816 len=uloc_getDisplayName(locale, displayLocale, result, i, &ec);
817 if(ec==U_BUFFER_OVERFLOW_ERROR) {
818 ec=U_ZERO_ERROR;
819 }
820 if(U_FAILURE(ec)) {
821 log_err("using buffer of length %d returned error %s", i, u_errorName(ec));
822 break;
823 }
824 if(len!=expectedLen) {
825 log_err("with buffer of length %d, expected length %d but got %d", i, expectedLen, len);
826 break;
827 }
828 /* There's no guarantee about what's in the buffer if we've overflowed, in particular,
829 * we don't know that it's been filled, so no point in checking. */
830 }
831 }
832
833 free(expected);
834 }
835 }
836 }
837
838
839 /* test for uloc_getAvialable() and uloc_countAvilable()*/
840 static void TestGetAvailableLocales()
841 {
842
843 const char *locList;
844 int32_t locCount,i;
845
846 log_verbose("Testing the no of avialable locales\n");
847 locCount=uloc_countAvailable();
848 if (locCount == 0)
849 log_data_err("countAvailable() returned an empty list!\n");
850
851 /* use something sensible w/o hardcoding the count */
852 else if(locCount < 0){
853 log_data_err("countAvailable() returned a wrong value!= %d\n", locCount);
854 }
855 else{
856 log_info("Number of locales returned = %d\n", locCount);
857 }
858 for(i=0;i<locCount;i++){
859 locList=uloc_getAvailable(i);
860
861 log_verbose(" %s\n", locList);
862 }
863 }
864
865 static void TestGetAvailableLocalesByType() {
866 UErrorCode status = U_ZERO_ERROR;
867
868 UEnumeration* uenum = uloc_openAvailableByType(ULOC_AVAILABLE_DEFAULT, &status);
869 assertSuccess("Constructing the UEnumeration", &status);
870
871 assertIntEquals("countAvailable() should be same in old and new methods",
872 uloc_countAvailable(),
873 uenum_count(uenum, &status));
874
875 for (int32_t i = 0; i < uloc_countAvailable(); i++) {
876 const char* old = uloc_getAvailable(i);
877 int32_t len = 0;
878 const char* new = uenum_next(uenum, &len, &status);
879 assertEquals("Old and new strings should equal", old, new);
880 assertIntEquals("String length should be correct", uprv_strlen(old), len);
881 }
882 assertPtrEquals("Should get nullptr on the last string",
883 NULL, uenum_next(uenum, NULL, &status));
884
885 uenum_close(uenum);
886
887 uenum = uloc_openAvailableByType(ULOC_AVAILABLE_ONLY_LEGACY_ALIASES, &status);
888 UBool found_he = FALSE;
889 UBool found_iw = FALSE;
890 const char* loc;
891 while ((loc = uenum_next(uenum, NULL, &status))) {
892 if (uprv_strcmp("he", loc) == 0) {
893 found_he = TRUE;
894 }
895 if (uprv_strcmp("iw", loc) == 0) {
896 found_iw = TRUE;
897 }
898 }
899 assertTrue("Should NOT have found he amongst the legacy/alias locales", !found_he);
900 assertTrue("Should have found iw amongst the legacy/alias locales", found_iw);
901 uenum_close(uenum);
902
903 uenum = uloc_openAvailableByType(ULOC_AVAILABLE_WITH_LEGACY_ALIASES, &status);
904 found_he = FALSE;
905 found_iw = FALSE;
906 const UChar* uloc; // test the UChar conversion
907 int32_t count = 0;
908 while ((uloc = uenum_unext(uenum, NULL, &status))) {
909 if (u_strcmp(u"iw", uloc) == 0) {
910 found_iw = TRUE;
911 }
912 if (u_strcmp(u"he", uloc) == 0) {
913 found_he = TRUE;
914 }
915 count++;
916 }
917 assertTrue("Should have found he amongst all locales", found_he);
918 assertTrue("Should have found iw amongst all locales", found_iw);
919 assertIntEquals("Should return as many strings as claimed",
920 count, uenum_count(uenum, &status));
921
922 // Reset the enumeration and it should still work
923 uenum_reset(uenum, &status);
924 count = 0;
925 while ((loc = uenum_next(uenum, NULL, &status))) {
926 count++;
927 }
928 assertIntEquals("After reset, should return as many strings as claimed",
929 count, uenum_count(uenum, &status));
930
931 uenum_close(uenum);
932
933 assertSuccess("No errors should have occurred", &status);
934 }
935
936 /* test for u_getDataDirectory, u_setDataDirectory, uloc_getISO3Language */
937 static void TestDataDirectory()
938 {
939
940 char oldDirectory[512];
941 const char *temp,*testValue1,*testValue2,*testValue3;
942 const char path[40] ="d:\\icu\\source\\test\\intltest" U_FILE_SEP_STRING; /*give the required path */
943
944 log_verbose("Testing getDataDirectory()\n");
945 temp = u_getDataDirectory();
946 strcpy(oldDirectory, temp);
947
948 testValue1=uloc_getISO3Language("en_US");
949 log_verbose("first fetch of language retrieved %s\n", testValue1);
950
951 if (0 != strcmp(testValue1,"eng")){
952 log_err("Initial check of ISO3 language failed: expected \"eng\", got %s \n", testValue1);
953 }
954
955 /*defining the path for DataDirectory */
956 log_verbose("Testing setDataDirectory\n");
957 u_setDataDirectory( path );
958 if(strcmp(path, u_getDataDirectory())==0)
959 log_verbose("setDataDirectory working fine\n");
960 else
961 log_err("Error in setDataDirectory. Directory not set correctly - came back as [%s], expected [%s]\n", u_getDataDirectory(), path);
962
963 testValue2=uloc_getISO3Language("en_US");
964 log_verbose("second fetch of language retrieved %s \n", testValue2);
965
966 u_setDataDirectory(oldDirectory);
967 testValue3=uloc_getISO3Language("en_US");
968 log_verbose("third fetch of language retrieved %s \n", testValue3);
969
970 if (0 != strcmp(testValue3,"eng")) {
971 log_err("get/setDataDirectory() failed: expected \"eng\", got \" %s \" \n", testValue3);
972 }
973 }
974
975
976
977 /*=========================================================== */
978
979 static UChar _NUL=0;
980
981 static void doTestDisplayNames(const char* displayLocale, int32_t compareIndex)
982 {
983 UErrorCode status = U_ZERO_ERROR;
984 int32_t i;
985 int32_t maxresultsize;
986
987 const char *testLocale;
988
989
990 UChar *testLang = 0;
991 UChar *testScript = 0;
992 UChar *testCtry = 0;
993 UChar *testVar = 0;
994 UChar *testName = 0;
995
996
997 UChar* expectedLang = 0;
998 UChar* expectedScript = 0;
999 UChar* expectedCtry = 0;
1000 UChar* expectedVar = 0;
1001 UChar* expectedName = 0;
1002
1003 setUpDataTable();
1004
1005 for(i=0;i<LOCALE_SIZE; ++i)
1006 {
1007 testLocale=rawData2[NAME][i];
1008
1009 log_verbose("Testing..... %s\n", testLocale);
1010
1011 maxresultsize=0;
1012 maxresultsize=uloc_getDisplayLanguage(testLocale, displayLocale, NULL, maxresultsize, &status);
1013 if(status==U_BUFFER_OVERFLOW_ERROR)
1014 {
1015 status=U_ZERO_ERROR;
1016 testLang=(UChar*)malloc(sizeof(UChar) * (maxresultsize+1));
1017 uloc_getDisplayLanguage(testLocale, displayLocale, testLang, maxresultsize + 1, &status);
1018 }
1019 else
1020 {
1021 testLang=&_NUL;
1022 }
1023 if(U_FAILURE(status)){
1024 log_err("Error in getDisplayLanguage() %s\n", myErrorName(status));
1025 }
1026
1027 maxresultsize=0;
1028 maxresultsize=uloc_getDisplayScript(testLocale, displayLocale, NULL, maxresultsize, &status);
1029 if(status==U_BUFFER_OVERFLOW_ERROR)
1030 {
1031 status=U_ZERO_ERROR;
1032 testScript=(UChar*)malloc(sizeof(UChar) * (maxresultsize+1));
1033 uloc_getDisplayScript(testLocale, displayLocale, testScript, maxresultsize + 1, &status);
1034 }
1035 else
1036 {
1037 testScript=&_NUL;
1038 }
1039 if(U_FAILURE(status)){
1040 log_err("Error in getDisplayScript() %s\n", myErrorName(status));
1041 }
1042
1043 maxresultsize=0;
1044 maxresultsize=uloc_getDisplayCountry(testLocale, displayLocale, NULL, maxresultsize, &status);
1045 if(status==U_BUFFER_OVERFLOW_ERROR)
1046 {
1047 status=U_ZERO_ERROR;
1048 testCtry=(UChar*)malloc(sizeof(UChar) * (maxresultsize+1));
1049 uloc_getDisplayCountry(testLocale, displayLocale, testCtry, maxresultsize + 1, &status);
1050 }
1051 else
1052 {
1053 testCtry=&_NUL;
1054 }
1055 if(U_FAILURE(status)){
1056 log_err("Error in getDisplayCountry() %s\n", myErrorName(status));
1057 }
1058
1059 maxresultsize=0;
1060 maxresultsize=uloc_getDisplayVariant(testLocale, displayLocale, NULL, maxresultsize, &status);
1061 if(status==U_BUFFER_OVERFLOW_ERROR)
1062 {
1063 status=U_ZERO_ERROR;
1064 testVar=(UChar*)malloc(sizeof(UChar) * (maxresultsize+1));
1065 uloc_getDisplayVariant(testLocale, displayLocale, testVar, maxresultsize + 1, &status);
1066 }
1067 else
1068 {
1069 testVar=&_NUL;
1070 }
1071 if(U_FAILURE(status)){
1072 log_err("Error in getDisplayVariant() %s\n", myErrorName(status));
1073 }
1074
1075 maxresultsize=0;
1076 maxresultsize=uloc_getDisplayName(testLocale, displayLocale, NULL, maxresultsize, &status);
1077 if(status==U_BUFFER_OVERFLOW_ERROR)
1078 {
1079 status=U_ZERO_ERROR;
1080 testName=(UChar*)malloc(sizeof(UChar) * (maxresultsize+1));
1081 uloc_getDisplayName(testLocale, displayLocale, testName, maxresultsize + 1, &status);
1082 }
1083 else
1084 {
1085 testName=&_NUL;
1086 }
1087 if(U_FAILURE(status)){
1088 log_err("Error in getDisplayName() %s\n", myErrorName(status));
1089 }
1090
1091 expectedLang=dataTable[compareIndex][i];
1092 if(u_strlen(expectedLang)== 0)
1093 expectedLang=dataTable[DLANG_EN][i];
1094
1095 expectedScript=dataTable[compareIndex + 1][i];
1096 if(u_strlen(expectedScript)== 0)
1097 expectedScript=dataTable[DSCRIPT_EN][i];
1098
1099 expectedCtry=dataTable[compareIndex + 2][i];
1100 if(u_strlen(expectedCtry)== 0)
1101 expectedCtry=dataTable[DCTRY_EN][i];
1102
1103 expectedVar=dataTable[compareIndex + 3][i];
1104 if(u_strlen(expectedVar)== 0)
1105 expectedVar=dataTable[DVAR_EN][i];
1106
1107 expectedName=dataTable[compareIndex + 4][i];
1108 if(u_strlen(expectedName) == 0)
1109 expectedName=dataTable[DNAME_EN][i];
1110
1111 if (0 !=u_strcmp(testLang,expectedLang)) {
1112 log_data_err(" Display Language mismatch: got %s expected %s displayLocale=%s (Are you missing data?)\n", austrdup(testLang), austrdup(expectedLang), displayLocale);
1113 }
1114
1115 if (0 != u_strcmp(testScript,expectedScript)) {
1116 log_data_err(" Display Script mismatch: got %s expected %s displayLocale=%s (Are you missing data?)\n", austrdup(testScript), austrdup(expectedScript), displayLocale);
1117 }
1118
1119 if (0 != u_strcmp(testCtry,expectedCtry)) {
1120 log_data_err(" Display Country mismatch: got %s expected %s displayLocale=%s (Are you missing data?)\n", austrdup(testCtry), austrdup(expectedCtry), displayLocale);
1121 }
1122
1123 if (0 != u_strcmp(testVar,expectedVar)) {
1124 log_data_err(" Display Variant mismatch: got %s expected %s displayLocale=%s (Are you missing data?)\n", austrdup(testVar), austrdup(expectedVar), displayLocale);
1125 }
1126
1127 if(0 != u_strcmp(testName, expectedName)) {
1128 log_data_err(" Display Name mismatch: got %s expected %s displayLocale=%s (Are you missing data?)\n", austrdup(testName), austrdup(expectedName), displayLocale);
1129 }
1130
1131 if(testName!=&_NUL) {
1132 free(testName);
1133 }
1134 if(testLang!=&_NUL) {
1135 free(testLang);
1136 }
1137 if(testScript!=&_NUL) {
1138 free(testScript);
1139 }
1140 if(testCtry!=&_NUL) {
1141 free(testCtry);
1142 }
1143 if(testVar!=&_NUL) {
1144 free(testVar);
1145 }
1146 }
1147 cleanUpDataTable();
1148 }
1149
1150 /*------------------------------
1151 * TestDisplayNameBrackets
1152 */
1153
1154 typedef struct {
1155 const char * displayLocale;
1156 const char * namedRegion;
1157 const char * namedLocale;
1158 const char * regionName;
1159 const char * ulocLocaleName;
1160 const char * uldnLocaleName;
1161 } DisplayNameBracketsItem;
1162
1163 static const DisplayNameBracketsItem displayNameBracketsItems[] = {
1164 { "en", "CC", "en_CC", "Cocos (Keeling) Islands", "English (Cocos [Keeling] Islands)", "English (Cocos [Keeling] Islands)" },
1165 { "en", "MM", "my_MM", "Myanmar (Burma)", "Burmese (Myanmar [Burma])", "Burmese (Myanmar)" },
1166 { "en", "MM", "my_Mymr_MM", "Myanmar (Burma)", "Burmese (Myanmar, Myanmar [Burma])", "Burmese (Myanmar, Myanmar)" },
1167 { "zh", "CC", "en_CC", "\\u79D1\\u79D1\\u65AF\\uFF08\\u57FA\\u6797\\uFF09\\u7FA4\\u5C9B",
1168 "\\u82F1\\u8BED\\uFF08\\u79D1\\u79D1\\u65AF\\uFF3B\\u57FA\\u6797\\uFF3D\\u7FA4\\u5C9B\\uFF09",
1169 "\\u82F1\\u8BED\\uFF08\\u79D1\\u79D1\\u65AF\\uFF3B\\u57FA\\u6797\\uFF3D\\u7FA4\\u5C9B\\uFF09" },
1170 { "zh", "CG", "fr_CG", "\\u521A\\u679C\\uFF08\\u5E03\\uFF09",
1171 "\\u6CD5\\u8BED\\uFF08\\u521A\\u679C\\uFF3B\\u5E03\\uFF3D\\uFF09",
1172 "\\u6CD5\\u8BED\\uFF08\\u521A\\u679C\\uFF3B\\u5E03\\uFF3D\\uFF09" },
1173 { NULL, NULL, NULL, NULL, NULL, NULL }
1174 };
1175
1176 enum { kDisplayNameBracketsMax = 128 };
1177
1178 static void TestDisplayNameBrackets()
1179 {
1180 const DisplayNameBracketsItem * itemPtr = displayNameBracketsItems;
1181 for (; itemPtr->displayLocale != NULL; itemPtr++) {
1182 ULocaleDisplayNames * uldn;
1183 UErrorCode status;
1184 UChar expectRegionName[kDisplayNameBracketsMax];
1185 UChar expectUlocLocaleName[kDisplayNameBracketsMax];
1186 UChar expectUldnLocaleName[kDisplayNameBracketsMax];
1187 UChar getName[kDisplayNameBracketsMax];
1188 int32_t ulen;
1189
1190 (void) u_unescape(itemPtr->regionName, expectRegionName, kDisplayNameBracketsMax);
1191 (void) u_unescape(itemPtr->ulocLocaleName, expectUlocLocaleName, kDisplayNameBracketsMax);
1192 (void) u_unescape(itemPtr->uldnLocaleName, expectUldnLocaleName, kDisplayNameBracketsMax);
1193
1194 status = U_ZERO_ERROR;
1195 ulen = uloc_getDisplayCountry(itemPtr->namedLocale, itemPtr->displayLocale, getName, kDisplayNameBracketsMax, &status);
1196 if ( U_FAILURE(status) || u_strcmp(getName, expectRegionName) != 0 ) {
1197 log_data_err("uloc_getDisplayCountry for displayLocale %s and namedLocale %s returns unexpected name or status %s\n", itemPtr->displayLocale, itemPtr->namedLocale, myErrorName(status));
1198 }
1199
1200 status = U_ZERO_ERROR;
1201 ulen = uloc_getDisplayName(itemPtr->namedLocale, itemPtr->displayLocale, getName, kDisplayNameBracketsMax, &status);
1202 if ( U_FAILURE(status) || u_strcmp(getName, expectUlocLocaleName) != 0 ) {
1203 log_data_err("uloc_getDisplayName for displayLocale %s and namedLocale %s returns unexpected name or status %s\n", itemPtr->displayLocale, itemPtr->namedLocale, myErrorName(status));
1204 }
1205 if ( U_FAILURE(status) ) {
1206 log_data_err("uloc_getDisplayName for displayLocale %s and namedLocale %-10s returns unexpected status %s\n", itemPtr->displayLocale, itemPtr->namedLocale, myErrorName(status));
1207 } else if ( u_strcmp(getName, expectUlocLocaleName) != 0 ) {
1208 char bbuf[128];
1209 u_strToUTF8(bbuf, 128, NULL, getName, ulen, &status);
1210 log_data_err("uloc_getDisplayName for displayLocale %s and namedLocale %-10s returns unexpected name (len %d): \"%s\"\n", itemPtr->displayLocale, itemPtr->namedLocale, ulen, bbuf);
1211 }
1212
1213 #if !UCONFIG_NO_FORMATTING
1214 status = U_ZERO_ERROR;
1215 uldn = uldn_open(itemPtr->displayLocale, ULDN_STANDARD_NAMES, &status);
1216 if (U_SUCCESS(status)) {
1217 status = U_ZERO_ERROR;
1218 ulen = uldn_regionDisplayName(uldn, itemPtr->namedRegion, getName, kDisplayNameBracketsMax, &status);
1219 if ( U_FAILURE(status) || u_strcmp(getName, expectRegionName) != 0 ) {
1220 log_data_err("uldn_regionDisplayName for displayLocale %s and namedRegion %s returns unexpected name or status %s\n", itemPtr->displayLocale, itemPtr->namedRegion, myErrorName(status));
1221 }
1222
1223 status = U_ZERO_ERROR;
1224 ulen = uldn_localeDisplayName(uldn, itemPtr->namedLocale, getName, kDisplayNameBracketsMax, &status);
1225 if ( U_FAILURE(status) ) {
1226 log_data_err("uldn_localeDisplayName for displayLocale %s and namedLocale %-10s returns unexpected status %s\n", itemPtr->displayLocale, itemPtr->namedLocale, myErrorName(status));
1227 } else if ( u_strcmp(getName, expectUldnLocaleName) != 0 ) {
1228 char bbuf[128];
1229 u_strToUTF8(bbuf, 128, NULL, getName, ulen, &status);
1230 log_data_err("uldn_localeDisplayName for displayLocale %s and namedLocale %-10s returns unexpected name (len %d): \"%s\"\n", itemPtr->displayLocale, itemPtr->namedLocale, ulen, bbuf);
1231 }
1232
1233 uldn_close(uldn);
1234 } else {
1235 log_data_err("uldn_open fails for displayLocale %s, status=%s\n", itemPtr->displayLocale, u_errorName(status));
1236 }
1237 #endif
1238 (void)ulen; /* Suppress variable not used warning */
1239 }
1240 }
1241
1242 /*------------------------------
1243 * TestISOFunctions
1244 */
1245
1246 #if !UCONFIG_NO_FILE_IO && !UCONFIG_NO_LEGACY_CONVERSION
1247 /* test for uloc_getISOLanguages, uloc_getISOCountries */
1248 static void TestISOFunctions()
1249 {
1250 const char* const* str=uloc_getISOLanguages();
1251 const char* const* str1=uloc_getISOCountries();
1252 const char* test;
1253 const char *key = NULL;
1254 int32_t count = 0, skipped = 0;
1255 int32_t expect;
1256 UResourceBundle *res;
1257 UResourceBundle *subRes;
1258 UErrorCode status = U_ZERO_ERROR;
1259
1260 /* test getISOLanguages*/
1261 /*str=uloc_getISOLanguages(); */
1262 log_verbose("Testing ISO Languages: \n");
1263
1264 /* use structLocale - this data is no longer in root */
1265 res = ures_openDirect(loadTestData(&status), "structLocale", &status);
1266 subRes = ures_getByKey(res, "Languages", NULL, &status);
1267 if (U_FAILURE(status)) {
1268 log_data_err("There is an error in structLocale's ures_getByKey(\"Languages\"), status=%s\n", u_errorName(status));
1269 return;
1270 }
1271
1272 expect = ures_getSize(subRes);
1273 for(count = 0; *(str+count) != 0; count++)
1274 {
1275 key = NULL;
1276 test = *(str+count);
1277 status = U_ZERO_ERROR;
1278
1279 do {
1280 /* Skip over language tags. This API only returns language codes. */
1281 skipped += (key != NULL);
1282 ures_getNextString(subRes, NULL, &key, &status);
1283 }
1284 while (key != NULL && strchr(key, '_'));
1285
1286 if(key == NULL)
1287 break;
1288 /* TODO: Consider removing sh, which is deprecated */
1289 if(strcmp(key,"root") == 0 || strcmp(key,"Fallback") == 0 || strcmp(key,"sh") == 0) {
1290 ures_getNextString(subRes, NULL, &key, &status);
1291 skipped++;
1292 }
1293 #if U_CHARSET_FAMILY==U_ASCII_FAMILY
1294 /* This code only works on ASCII machines where the keys are stored in ASCII order */
1295 if(strcmp(test,key)) {
1296 /* The first difference usually implies the place where things get out of sync */
1297 log_err("FAIL Language diff at offset %d, \"%s\" != \"%s\"\n", count, test, key);
1298 }
1299 #endif
1300
1301 if(!strcmp(test,"in"))
1302 log_err("FAIL getISOLanguages() has obsolete language code %s\n", test);
1303 if(!strcmp(test,"iw"))
1304 log_err("FAIL getISOLanguages() has obsolete language code %s\n", test);
1305 if(!strcmp(test,"ji"))
1306 log_err("FAIL getISOLanguages() has obsolete language code %s\n", test);
1307 if(!strcmp(test,"jw"))
1308 log_err("FAIL getISOLanguages() has obsolete language code %s\n", test);
1309 if(!strcmp(test,"sh"))
1310 log_err("FAIL getISOLanguages() has obsolete language code %s\n", test);
1311 }
1312
1313 expect -= skipped; /* Ignore the skipped resources from structLocale */
1314
1315 if(count!=expect) {
1316 log_err("There is an error in getISOLanguages, got %d, expected %d (as per structLocale)\n", count, expect);
1317 }
1318
1319 subRes = ures_getByKey(res, "Countries", subRes, &status);
1320 log_verbose("Testing ISO Countries");
1321 skipped = 0;
1322 expect = ures_getSize(subRes) - 1; /* Skip ZZ */
1323 for(count = 0; *(str1+count) != 0; count++)
1324 {
1325 key = NULL;
1326 test = *(str1+count);
1327 do {
1328 /* Skip over numeric UN tags. This API only returns ISO-3166 codes. */
1329 skipped += (key != NULL);
1330 ures_getNextString(subRes, NULL, &key, &status);
1331 }
1332 while (key != NULL && strlen(key) != 2);
1333
1334 if(key == NULL)
1335 break;
1336 /* TODO: Consider removing CS, which is deprecated */
1337 while(strcmp(key,"QO") == 0 || strcmp(key,"QU") == 0 || strcmp(key,"CS") == 0) {
1338 ures_getNextString(subRes, NULL, &key, &status);
1339 skipped++;
1340 }
1341 #if U_CHARSET_FAMILY==U_ASCII_FAMILY
1342 /* This code only works on ASCII machines where the keys are stored in ASCII order */
1343 if(strcmp(test,key)) {
1344 /* The first difference usually implies the place where things get out of sync */
1345 log_err("FAIL Country diff at offset %d, \"%s\" != \"%s\"\n", count, test, key);
1346 }
1347 #endif
1348 if(!strcmp(test,"FX"))
1349 log_err("FAIL getISOCountries() has obsolete country code %s\n", test);
1350 if(!strcmp(test,"YU"))
1351 log_err("FAIL getISOCountries() has obsolete country code %s\n", test);
1352 if(!strcmp(test,"ZR"))
1353 log_err("FAIL getISOCountries() has obsolete country code %s\n", test);
1354 }
1355
1356 ures_getNextString(subRes, NULL, &key, &status);
1357 if (strcmp(key, "ZZ") != 0) {
1358 log_err("ZZ was expected to be the last entry in structLocale, but got %s\n", key);
1359 }
1360 #if U_CHARSET_FAMILY==U_EBCDIC_FAMILY
1361 /* On EBCDIC machines, the numbers are sorted last. Account for those in the skipped value too. */
1362 key = NULL;
1363 do {
1364 /* Skip over numeric UN tags. uloc_getISOCountries only returns ISO-3166 codes. */
1365 skipped += (key != NULL);
1366 ures_getNextString(subRes, NULL, &key, &status);
1367 }
1368 while (U_SUCCESS(status) && key != NULL && strlen(key) != 2);
1369 #endif
1370 expect -= skipped; /* Ignore the skipped resources from structLocale */
1371 if(count!=expect)
1372 {
1373 log_err("There is an error in getISOCountries, got %d, expected %d \n", count, expect);
1374 }
1375 ures_close(subRes);
1376 ures_close(res);
1377 }
1378 #endif
1379
1380 static void setUpDataTable()
1381 {
1382 int32_t i,j;
1383 dataTable = (UChar***)(calloc(sizeof(UChar**),LOCALE_INFO_SIZE));
1384
1385 for (i = 0; i < LOCALE_INFO_SIZE; i++) {
1386 dataTable[i] = (UChar**)(calloc(sizeof(UChar*),LOCALE_SIZE));
1387 for (j = 0; j < LOCALE_SIZE; j++){
1388 dataTable[i][j] = CharsToUChars(rawData2[i][j]);
1389 }
1390 }
1391 }
1392
1393 static void cleanUpDataTable()
1394 {
1395 int32_t i,j;
1396 if(dataTable != NULL) {
1397 for (i=0; i<LOCALE_INFO_SIZE; i++) {
1398 for(j = 0; j < LOCALE_SIZE; j++) {
1399 free(dataTable[i][j]);
1400 }
1401 free(dataTable[i]);
1402 }
1403 free(dataTable);
1404 }
1405 dataTable = NULL;
1406 }
1407
1408 /**
1409 * @bug 4011756 4011380
1410 */
1411 static void TestISO3Fallback()
1412 {
1413 const char* test="xx_YY";
1414
1415 const char * result;
1416
1417 result = uloc_getISO3Language(test);
1418
1419 /* Conform to C API usage */
1420
1421 if (!result || (result[0] != 0))
1422 log_err("getISO3Language() on xx_YY returned %s instead of \"\"");
1423
1424 result = uloc_getISO3Country(test);
1425
1426 if (!result || (result[0] != 0))
1427 log_err("getISO3Country() on xx_YY returned %s instead of \"\"");
1428 }
1429
1430 /**
1431 * @bug 4118587
1432 */
1433 static void TestSimpleDisplayNames()
1434 {
1435 /*
1436 This test is different from TestDisplayNames because TestDisplayNames checks
1437 fallback behavior, combination of language and country names to form locale
1438 names, and other stuff like that. This test just checks specific language
1439 and country codes to make sure we have the correct names for them.
1440 */
1441 char languageCodes[] [4] = { "he", "id", "iu", "ug", "yi", "za", "419" };
1442 const char* languageNames [] = { "Hebrew", "Indonesian", "Inuktitut", "Uyghur", "Yiddish",
1443 "Zhuang", "419" };
1444 const char* inLocale [] = { "en_US", "zh_Hant"};
1445 UErrorCode status=U_ZERO_ERROR;
1446
1447 int32_t i;
1448 int32_t localeIndex = 0;
1449 for (i = 0; i < 7; i++) {
1450 UChar *testLang=0;
1451 UChar *expectedLang=0;
1452 int size=0;
1453
1454 if (i == 6) {
1455 localeIndex = 1; /* Use the second locale for the rest of the test. */
1456 }
1457
1458 size=uloc_getDisplayLanguage(languageCodes[i], inLocale[localeIndex], NULL, size, &status);
1459 if(status==U_BUFFER_OVERFLOW_ERROR) {
1460 status=U_ZERO_ERROR;
1461 testLang=(UChar*)malloc(sizeof(UChar) * (size + 1));
1462 uloc_getDisplayLanguage(languageCodes[i], inLocale[localeIndex], testLang, size + 1, &status);
1463 }
1464 expectedLang=(UChar*)malloc(sizeof(UChar) * (strlen(languageNames[i])+1));
1465 u_uastrcpy(expectedLang, languageNames[i]);
1466 if (u_strcmp(testLang, expectedLang) != 0)
1467 log_data_err("Got wrong display name for %s : Expected \"%s\", got \"%s\".\n",
1468 languageCodes[i], languageNames[i], austrdup(testLang));
1469 free(testLang);
1470 free(expectedLang);
1471 }
1472
1473 }
1474
1475 /**
1476 * @bug 4118595
1477 */
1478 static void TestUninstalledISO3Names()
1479 {
1480 /* This test checks to make sure getISO3Language and getISO3Country work right
1481 even for locales that are not installed. */
1482 static const char iso2Languages [][4] = { "am", "ba", "fy", "mr", "rn",
1483 "ss", "tw", "zu" };
1484 static const char iso3Languages [][5] = { "amh", "bak", "fry", "mar", "run",
1485 "ssw", "twi", "zul" };
1486 static const char iso2Countries [][6] = { "am_AF", "ba_BW", "fy_KZ", "mr_MO", "rn_MN",
1487 "ss_SB", "tw_TC", "zu_ZW" };
1488 static const char iso3Countries [][4] = { "AFG", "BWA", "KAZ", "MAC", "MNG",
1489 "SLB", "TCA", "ZWE" };
1490 int32_t i;
1491
1492 for (i = 0; i < 8; i++) {
1493 UErrorCode err = U_ZERO_ERROR;
1494 const char *test;
1495 test = uloc_getISO3Language(iso2Languages[i]);
1496 if(strcmp(test, iso3Languages[i]) !=0 || U_FAILURE(err))
1497 log_err("Got wrong ISO3 code for %s : Expected \"%s\", got \"%s\". %s\n",
1498 iso2Languages[i], iso3Languages[i], test, myErrorName(err));
1499 }
1500 for (i = 0; i < 8; i++) {
1501 UErrorCode err = U_ZERO_ERROR;
1502 const char *test;
1503 test = uloc_getISO3Country(iso2Countries[i]);
1504 if(strcmp(test, iso3Countries[i]) !=0 || U_FAILURE(err))
1505 log_err("Got wrong ISO3 code for %s : Expected \"%s\", got \"%s\". %s\n",
1506 iso2Countries[i], iso3Countries[i], test, myErrorName(err));
1507 }
1508 }
1509
1510
1511 static void TestVariantParsing()
1512 {
1513 static const char* en_US_custom="en_US_De Anza_Cupertino_California_United States_Earth";
1514 static const char* dispName="English (United States, DE ANZA_CUPERTINO_CALIFORNIA_UNITED STATES_EARTH)";
1515 static const char* dispVar="DE ANZA_CUPERTINO_CALIFORNIA_UNITED STATES_EARTH";
1516 static const char* shortVariant="fr_FR_foo";
1517 static const char* bogusVariant="fr_FR__foo";
1518 static const char* bogusVariant2="fr_FR_foo_";
1519 static const char* bogusVariant3="fr_FR__foo_";
1520
1521
1522 UChar displayVar[100];
1523 UChar displayName[100];
1524 UErrorCode status=U_ZERO_ERROR;
1525 UChar* got=0;
1526 int32_t size=0;
1527 size=uloc_getDisplayVariant(en_US_custom, "en_US", NULL, size, &status);
1528 if(status==U_BUFFER_OVERFLOW_ERROR) {
1529 status=U_ZERO_ERROR;
1530 got=(UChar*)realloc(got, sizeof(UChar) * (size+1));
1531 uloc_getDisplayVariant(en_US_custom, "en_US", got, size + 1, &status);
1532 }
1533 else {
1534 log_err("FAIL: Didn't get U_BUFFER_OVERFLOW_ERROR\n");
1535 }
1536 u_uastrcpy(displayVar, dispVar);
1537 if(u_strcmp(got,displayVar)!=0) {
1538 log_err("FAIL: getDisplayVariant() Wanted %s, got %s\n", dispVar, austrdup(got));
1539 }
1540 size=0;
1541 size=uloc_getDisplayName(en_US_custom, "en_US", NULL, size, &status);
1542 if(status==U_BUFFER_OVERFLOW_ERROR) {
1543 status=U_ZERO_ERROR;
1544 got=(UChar*)realloc(got, sizeof(UChar) * (size+1));
1545 uloc_getDisplayName(en_US_custom, "en_US", got, size + 1, &status);
1546 }
1547 else {
1548 log_err("FAIL: Didn't get U_BUFFER_OVERFLOW_ERROR\n");
1549 }
1550 u_uastrcpy(displayName, dispName);
1551 if(u_strcmp(got,displayName)!=0) {
1552 if (status == U_USING_DEFAULT_WARNING) {
1553 log_data_err("FAIL: getDisplayName() got %s. Perhaps you are missing data?\n", u_errorName(status));
1554 } else {
1555 log_err("FAIL: getDisplayName() Wanted %s, got %s\n", dispName, austrdup(got));
1556 }
1557 }
1558
1559 size=0;
1560 status=U_ZERO_ERROR;
1561 size=uloc_getDisplayVariant(shortVariant, NULL, NULL, size, &status);
1562 if(status==U_BUFFER_OVERFLOW_ERROR) {
1563 status=U_ZERO_ERROR;
1564 got=(UChar*)realloc(got, sizeof(UChar) * (size+1));
1565 uloc_getDisplayVariant(shortVariant, NULL, got, size + 1, &status);
1566 }
1567 else {
1568 log_err("FAIL: Didn't get U_BUFFER_OVERFLOW_ERROR\n");
1569 }
1570 if(strcmp(austrdup(got),"FOO")!=0) {
1571 log_err("FAIL: getDisplayVariant() Wanted: foo Got: %s\n", austrdup(got));
1572 }
1573 size=0;
1574 status=U_ZERO_ERROR;
1575 size=uloc_getDisplayVariant(bogusVariant, NULL, NULL, size, &status);
1576 if(status==U_BUFFER_OVERFLOW_ERROR) {
1577 status=U_ZERO_ERROR;
1578 got=(UChar*)realloc(got, sizeof(UChar) * (size+1));
1579 uloc_getDisplayVariant(bogusVariant, NULL, got, size + 1, &status);
1580 }
1581 else {
1582 log_err("FAIL: Didn't get U_BUFFER_OVERFLOW_ERROR\n");
1583 }
1584 if(strcmp(austrdup(got),"_FOO")!=0) {
1585 log_err("FAIL: getDisplayVariant() Wanted: _FOO Got: %s\n", austrdup(got));
1586 }
1587 size=0;
1588 status=U_ZERO_ERROR;
1589 size=uloc_getDisplayVariant(bogusVariant2, NULL, NULL, size, &status);
1590 if(status==U_BUFFER_OVERFLOW_ERROR) {
1591 status=U_ZERO_ERROR;
1592 got=(UChar*)realloc(got, sizeof(UChar) * (size+1));
1593 uloc_getDisplayVariant(bogusVariant2, NULL, got, size + 1, &status);
1594 }
1595 else {
1596 log_err("FAIL: Didn't get U_BUFFER_OVERFLOW_ERROR\n");
1597 }
1598 if(strcmp(austrdup(got),"FOO_")!=0) {
1599 log_err("FAIL: getDisplayVariant() Wanted: FOO_ Got: %s\n", austrdup(got));
1600 }
1601 size=0;
1602 status=U_ZERO_ERROR;
1603 size=uloc_getDisplayVariant(bogusVariant3, NULL, NULL, size, &status);
1604 if(status==U_BUFFER_OVERFLOW_ERROR) {
1605 status=U_ZERO_ERROR;
1606 got=(UChar*)realloc(got, sizeof(UChar) * (size+1));
1607 uloc_getDisplayVariant(bogusVariant3, NULL, got, size + 1, &status);
1608 }
1609 else {
1610 log_err("FAIL: Didn't get U_BUFFER_OVERFLOW_ERROR\n");
1611 }
1612 if(strcmp(austrdup(got),"_FOO_")!=0) {
1613 log_err("FAIL: getDisplayVariant() Wanted: _FOO_ Got: %s\n", austrdup(got));
1614 }
1615 free(got);
1616 }
1617
1618
1619 static void TestObsoleteNames(void)
1620 {
1621 int32_t i;
1622 UErrorCode status = U_ZERO_ERROR;
1623 char buff[256];
1624
1625 static const struct
1626 {
1627 char locale[9];
1628 char lang3[4];
1629 char lang[4];
1630 char ctry3[4];
1631 char ctry[4];
1632 } tests[] =
1633 {
1634 { "eng_USA", "eng", "en", "USA", "US" },
1635 { "kok", "kok", "kok", "", "" },
1636 { "in", "ind", "in", "", "" },
1637 { "id", "ind", "id", "", "" }, /* NO aliasing */
1638 { "sh", "srp", "sh", "", "" },
1639 { "zz_CS", "", "zz", "SCG", "CS" },
1640 { "zz_FX", "", "zz", "FXX", "FX" },
1641 { "zz_RO", "", "zz", "ROU", "RO" },
1642 { "zz_TP", "", "zz", "TMP", "TP" },
1643 { "zz_TL", "", "zz", "TLS", "TL" },
1644 { "zz_ZR", "", "zz", "ZAR", "ZR" },
1645 { "zz_FXX", "", "zz", "FXX", "FX" }, /* no aliasing. Doesn't go to PS(PSE). */
1646 { "zz_ROM", "", "zz", "ROU", "RO" },
1647 { "zz_ROU", "", "zz", "ROU", "RO" },
1648 { "zz_ZAR", "", "zz", "ZAR", "ZR" },
1649 { "zz_TMP", "", "zz", "TMP", "TP" },
1650 { "zz_TLS", "", "zz", "TLS", "TL" },
1651 { "zz_YUG", "", "zz", "YUG", "YU" },
1652 { "mlt_PSE", "mlt", "mt", "PSE", "PS" },
1653 { "iw", "heb", "iw", "", "" },
1654 { "ji", "yid", "ji", "", "" },
1655 { "jw", "jaw", "jw", "", "" },
1656 { "sh", "srp", "sh", "", "" },
1657 { "", "", "", "", "" }
1658 };
1659
1660 for(i=0;tests[i].locale[0];i++)
1661 {
1662 const char *locale;
1663
1664 locale = tests[i].locale;
1665 log_verbose("** %s:\n", locale);
1666
1667 status = U_ZERO_ERROR;
1668 if(strcmp(tests[i].lang3,uloc_getISO3Language(locale)))
1669 {
1670 log_err("FAIL: uloc_getISO3Language(%s)==\t\"%s\",\t expected \"%s\"\n",
1671 locale, uloc_getISO3Language(locale), tests[i].lang3);
1672 }
1673 else
1674 {
1675 log_verbose(" uloc_getISO3Language()==\t\"%s\"\n",
1676 uloc_getISO3Language(locale) );
1677 }
1678
1679 status = U_ZERO_ERROR;
1680 uloc_getLanguage(locale, buff, 256, &status);
1681 if(U_FAILURE(status))
1682 {
1683 log_err("FAIL: error getting language from %s\n", locale);
1684 }
1685 else
1686 {
1687 if(strcmp(buff,tests[i].lang))
1688 {
1689 log_err("FAIL: uloc_getLanguage(%s)==\t\"%s\"\t expected \"%s\"\n",
1690 locale, buff, tests[i].lang);
1691 }
1692 else
1693 {
1694 log_verbose(" uloc_getLanguage(%s)==\t%s\n", locale, buff);
1695 }
1696 }
1697 if(strcmp(tests[i].lang3,uloc_getISO3Language(locale)))
1698 {
1699 log_err("FAIL: uloc_getISO3Language(%s)==\t\"%s\",\t expected \"%s\"\n",
1700 locale, uloc_getISO3Language(locale), tests[i].lang3);
1701 }
1702 else
1703 {
1704 log_verbose(" uloc_getISO3Language()==\t\"%s\"\n",
1705 uloc_getISO3Language(locale) );
1706 }
1707
1708 if(strcmp(tests[i].ctry3,uloc_getISO3Country(locale)))
1709 {
1710 log_err("FAIL: uloc_getISO3Country(%s)==\t\"%s\",\t expected \"%s\"\n",
1711 locale, uloc_getISO3Country(locale), tests[i].ctry3);
1712 }
1713 else
1714 {
1715 log_verbose(" uloc_getISO3Country()==\t\"%s\"\n",
1716 uloc_getISO3Country(locale) );
1717 }
1718
1719 status = U_ZERO_ERROR;
1720 uloc_getCountry(locale, buff, 256, &status);
1721 if(U_FAILURE(status))
1722 {
1723 log_err("FAIL: error getting country from %s\n", locale);
1724 }
1725 else
1726 {
1727 if(strcmp(buff,tests[i].ctry))
1728 {
1729 log_err("FAIL: uloc_getCountry(%s)==\t\"%s\"\t expected \"%s\"\n",
1730 locale, buff, tests[i].ctry);
1731 }
1732 else
1733 {
1734 log_verbose(" uloc_getCountry(%s)==\t%s\n", locale, buff);
1735 }
1736 }
1737 }
1738
1739 if (uloc_getLCID("iw_IL") != uloc_getLCID("he_IL")) {
1740 log_err("he,iw LCID mismatch: %X versus %X\n", uloc_getLCID("iw_IL"), uloc_getLCID("he_IL"));
1741 }
1742
1743 if (uloc_getLCID("iw") != uloc_getLCID("he")) {
1744 log_err("he,iw LCID mismatch: %X versus %X\n", uloc_getLCID("iw"), uloc_getLCID("he"));
1745 }
1746
1747 #if 0
1748
1749 i = uloc_getLanguage("kok",NULL,0,&icu_err);
1750 if(U_FAILURE(icu_err))
1751 {
1752 log_err("FAIL: Got %s trying to do uloc_getLanguage(kok)\n", u_errorName(icu_err));
1753 }
1754
1755 icu_err = U_ZERO_ERROR;
1756 uloc_getLanguage("kok",r1_buff,12,&icu_err);
1757 if(U_FAILURE(icu_err))
1758 {
1759 log_err("FAIL: Got %s trying to do uloc_getLanguage(kok, buff)\n", u_errorName(icu_err));
1760 }
1761
1762 r1_addr = (char *)uloc_getISO3Language("kok");
1763
1764 icu_err = U_ZERO_ERROR;
1765 if (strcmp(r1_buff,"kok") != 0)
1766 {
1767 log_err("FAIL: uloc_getLanguage(kok)==%s not kok\n",r1_buff);
1768 line--;
1769 }
1770 r1_addr = (char *)uloc_getISO3Language("in");
1771 i = uloc_getLanguage(r1_addr,r1_buff,12,&icu_err);
1772 if (strcmp(r1_buff,"id") != 0)
1773 {
1774 printf("uloc_getLanguage error (%s)\n",r1_buff);
1775 line--;
1776 }
1777 r1_addr = (char *)uloc_getISO3Language("sh");
1778 i = uloc_getLanguage(r1_addr,r1_buff,12,&icu_err);
1779 if (strcmp(r1_buff,"sr") != 0)
1780 {
1781 printf("uloc_getLanguage error (%s)\n",r1_buff);
1782 line--;
1783 }
1784
1785 r1_addr = (char *)uloc_getISO3Country("zz_ZR");
1786 strcpy(p1_buff,"zz_");
1787 strcat(p1_buff,r1_addr);
1788 i = uloc_getCountry(p1_buff,r1_buff,12,&icu_err);
1789 if (strcmp(r1_buff,"ZR") != 0)
1790 {
1791 printf("uloc_getCountry error (%s)\n",r1_buff);
1792 line--;
1793 }
1794 r1_addr = (char *)uloc_getISO3Country("zz_FX");
1795 strcpy(p1_buff,"zz_");
1796 strcat(p1_buff,r1_addr);
1797 i = uloc_getCountry(p1_buff,r1_buff,12,&icu_err);
1798 if (strcmp(r1_buff,"FX") != 0)
1799 {
1800 printf("uloc_getCountry error (%s)\n",r1_buff);
1801 line--;
1802 }
1803
1804 #endif
1805
1806 }
1807
1808 static void TestKeywordVariants(void)
1809 {
1810 static const struct {
1811 const char *localeID;
1812 const char *expectedLocaleID; /* uloc_getName */
1813 const char *expectedLocaleIDNoKeywords; /* uloc_getBaseName */
1814 const char *expectedCanonicalID; /* uloc_canonicalize */
1815 const char *expectedKeywords[10];
1816 int32_t numKeywords;
1817 UErrorCode expectedStatus; /* from uloc_openKeywords */
1818 } testCases[] = {
1819 {
1820 "de_DE@ currency = euro; C o ll A t i o n = Phonebook ; C alen dar = buddhist ",
1821 "de_DE@calendar=buddhist;collation=Phonebook;currency=euro",
1822 "de_DE",
1823 "de_DE@calendar=buddhist;collation=Phonebook;currency=euro",
1824 {"calendar", "collation", "currency"},
1825 3,
1826 U_ZERO_ERROR
1827 },
1828 {
1829 "de_DE@euro",
1830 "de_DE@euro",
1831 "de_DE@euro", /* we probably should strip off the POSIX style variant @euro see #11690 */
1832 "de_DE_EURO",
1833 {"","","","","","",""},
1834 0,
1835 U_INVALID_FORMAT_ERROR /* must have '=' after '@' */
1836 },
1837 {
1838 "de_DE@euro;collation=phonebook", /* The POSIX style variant @euro cannot be combined with key=value? */
1839 "de_DE", /* getName returns de_DE - should be INVALID_FORMAT_ERROR? */
1840 "de_DE", /* getBaseName returns de_DE - should be INVALID_FORMAT_ERROR? see #11690 */
1841 "de_DE", /* canonicalize returns de_DE - should be INVALID_FORMAT_ERROR? */
1842 {"","","","","","",""},
1843 0,
1844 U_INVALID_FORMAT_ERROR
1845 },
1846 {
1847 "de_DE@collation=",
1848 0, /* expected getName to fail */
1849 "de_DE", /* getBaseName returns de_DE - should be INVALID_FORMAT_ERROR? see #11690 */
1850 0, /* expected canonicalize to fail */
1851 {"","","","","","",""},
1852 0,
1853 U_INVALID_FORMAT_ERROR /* must have '=' after '@' */
1854 }
1855 };
1856 UErrorCode status = U_ZERO_ERROR;
1857
1858 int32_t i = 0, j = 0;
1859 int32_t resultLen = 0;
1860 char buffer[256];
1861 UEnumeration *keywords;
1862 int32_t keyCount = 0;
1863 const char *keyword = NULL;
1864 int32_t keywordLen = 0;
1865
1866 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
1867 status = U_ZERO_ERROR;
1868 *buffer = 0;
1869 keywords = uloc_openKeywords(testCases[i].localeID, &status);
1870
1871 if(status != testCases[i].expectedStatus) {
1872 log_err("Expected to uloc_openKeywords(\"%s\") => status %s. Got %s instead\n",
1873 testCases[i].localeID,
1874 u_errorName(testCases[i].expectedStatus), u_errorName(status));
1875 }
1876 status = U_ZERO_ERROR;
1877 if(keywords) {
1878 if((keyCount = uenum_count(keywords, &status)) != testCases[i].numKeywords) {
1879 log_err("Expected to get %i keywords, got %i\n", testCases[i].numKeywords, keyCount);
1880 }
1881 if(keyCount) {
1882 j = 0;
1883 while((keyword = uenum_next(keywords, &keywordLen, &status))) {
1884 if(strcmp(keyword, testCases[i].expectedKeywords[j]) != 0) {
1885 log_err("Expected to get keyword value %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
1886 }
1887 j++;
1888 }
1889 j = 0;
1890 uenum_reset(keywords, &status);
1891 while((keyword = uenum_next(keywords, &keywordLen, &status))) {
1892 if(strcmp(keyword, testCases[i].expectedKeywords[j]) != 0) {
1893 log_err("Expected to get keyword value %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
1894 }
1895 j++;
1896 }
1897 }
1898 uenum_close(keywords);
1899 }
1900
1901 status = U_ZERO_ERROR;
1902 resultLen = uloc_getName(testCases[i].localeID, buffer, 256, &status);
1903 (void)resultLen;
1904 U_ASSERT(resultLen < 256);
1905 if (U_SUCCESS(status)) {
1906 if (testCases[i].expectedLocaleID == 0) {
1907 log_err("Expected uloc_getName(\"%s\") to fail; got \"%s\"\n",
1908 testCases[i].localeID, buffer);
1909 } else if (uprv_strcmp(testCases[i].expectedLocaleID, buffer) != 0) {
1910 log_err("Expected uloc_getName(\"%s\") => \"%s\"; got \"%s\"\n",
1911 testCases[i].localeID, testCases[i].expectedLocaleID, buffer);
1912 }
1913 } else {
1914 if (testCases[i].expectedLocaleID != 0) {
1915 log_err("Expected uloc_getName(\"%s\") => \"%s\"; but returned error: %s\n",
1916 testCases[i].localeID, testCases[i].expectedLocaleID, buffer, u_errorName(status));
1917 }
1918 }
1919
1920 status = U_ZERO_ERROR;
1921 resultLen = uloc_getBaseName(testCases[i].localeID, buffer, 256, &status);
1922 U_ASSERT(resultLen < 256);
1923 if (U_SUCCESS(status)) {
1924 if (testCases[i].expectedLocaleIDNoKeywords == 0) {
1925 log_err("Expected uloc_getBaseName(\"%s\") to fail; got \"%s\"\n",
1926 testCases[i].localeID, buffer);
1927 } else if (uprv_strcmp(testCases[i].expectedLocaleIDNoKeywords, buffer) != 0) {
1928 log_err("Expected uloc_getBaseName(\"%s\") => \"%s\"; got \"%s\"\n",
1929 testCases[i].localeID, testCases[i].expectedLocaleIDNoKeywords, buffer);
1930 }
1931 } else {
1932 if (testCases[i].expectedLocaleIDNoKeywords != 0) {
1933 log_err("Expected uloc_getBaseName(\"%s\") => \"%s\"; but returned error: %s\n",
1934 testCases[i].localeID, testCases[i].expectedLocaleIDNoKeywords, buffer, u_errorName(status));
1935 }
1936 }
1937
1938 status = U_ZERO_ERROR;
1939 resultLen = uloc_canonicalize(testCases[i].localeID, buffer, 256, &status);
1940 U_ASSERT(resultLen < 256);
1941 if (U_SUCCESS(status)) {
1942 if (testCases[i].expectedCanonicalID == 0) {
1943 log_err("Expected uloc_canonicalize(\"%s\") to fail; got \"%s\"\n",
1944 testCases[i].localeID, buffer);
1945 } else if (uprv_strcmp(testCases[i].expectedCanonicalID, buffer) != 0) {
1946 log_err("Expected uloc_canonicalize(\"%s\") => \"%s\"; got \"%s\"\n",
1947 testCases[i].localeID, testCases[i].expectedCanonicalID, buffer);
1948 }
1949 } else {
1950 if (testCases[i].expectedCanonicalID != 0) {
1951 log_err("Expected uloc_canonicalize(\"%s\") => \"%s\"; but returned error: %s\n",
1952 testCases[i].localeID, testCases[i].expectedCanonicalID, buffer, u_errorName(status));
1953 }
1954 }
1955 }
1956 }
1957
1958 static void TestKeywordVariantParsing(void)
1959 {
1960 static const struct {
1961 const char *localeID;
1962 const char *keyword;
1963 const char *expectedValue; /* NULL if failure is expected */
1964 } testCases[] = {
1965 { "de_DE@ C o ll A t i o n = Phonebook ", "c o ll a t i o n", NULL }, /* malformed key name */
1966 { "de_DE", "collation", ""},
1967 { "de_DE@collation=PHONEBOOK", "collation", "PHONEBOOK" },
1968 { "de_DE@currency = euro; CoLLaTion = PHONEBOOk", "collatiON", "PHONEBOOk" },
1969 };
1970
1971 UErrorCode status;
1972 int32_t i = 0;
1973 int32_t resultLen = 0;
1974 char buffer[256];
1975
1976 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
1977 *buffer = 0;
1978 status = U_ZERO_ERROR;
1979 resultLen = uloc_getKeywordValue(testCases[i].localeID, testCases[i].keyword, buffer, 256, &status);
1980 (void)resultLen; /* Suppress set but not used warning. */
1981 if (testCases[i].expectedValue) {
1982 /* expect success */
1983 if (U_FAILURE(status)) {
1984 log_err("Expected to extract \"%s\" from \"%s\" for keyword \"%s\". Instead got status %s\n",
1985 testCases[i].expectedValue, testCases[i].localeID, testCases[i].keyword, u_errorName(status));
1986 } else if (uprv_strcmp(testCases[i].expectedValue, buffer) != 0) {
1987 log_err("Expected to extract \"%s\" from \"%s\" for keyword \"%s\". Instead got \"%s\"\n",
1988 testCases[i].expectedValue, testCases[i].localeID, testCases[i].keyword, buffer);
1989 }
1990 } else if (U_SUCCESS(status)) {
1991 /* expect failure */
1992 log_err("Expected failure but got success from \"%s\" for keyword \"%s\". Got \"%s\"\n",
1993 testCases[i].localeID, testCases[i].keyword, buffer);
1994
1995 }
1996 }
1997 }
1998
1999 static const struct {
2000 const char *l; /* locale */
2001 const char *k; /* kw */
2002 const char *v; /* value */
2003 const char *x; /* expected */
2004 } kwSetTestCases[] = {
2005 #if 1
2006 { "en_US", "calendar", "japanese", "en_US@calendar=japanese" },
2007 { "en_US@", "calendar", "japanese", "en_US@calendar=japanese" },
2008 { "en_US@calendar=islamic", "calendar", "japanese", "en_US@calendar=japanese" },
2009 { "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 */
2010 { "en_US@calendar=gregorian", "calendar", "japanese", "en_US@calendar=japanese" },
2011 { "de", "Currency", "CHF", "de@currency=CHF" },
2012 { "de", "Currency", "CHF", "de@currency=CHF" },
2013
2014 { "en_US@collation=phonebook", "calendar", "japanese", "en_US@calendar=japanese;collation=phonebook" },
2015 { "en_US@calendar=japanese", "collation", "phonebook", "en_US@calendar=japanese;collation=phonebook" },
2016 { "de@collation=phonebook", "Currency", "CHF", "de@collation=phonebook;currency=CHF" },
2017 { "en_US@calendar=gregorian;collation=phonebook", "calendar", "japanese", "en_US@calendar=japanese;collation=phonebook" },
2018 { "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 */
2019 { "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 */
2020 { "en_US@calendar=islamic;collation=phonebook", "calendar", "japanese", "en_US@calendar=japanese;collation=phonebook" },
2021 { "de@collation=phonebook", "Currency", "CHF", "de@collation=phonebook;currency=CHF" },
2022 #endif
2023 #if 1
2024 { "mt@a=0;b=1;c=2;d=3", "c","j", "mt@a=0;b=1;c=j;d=3" },
2025 { "mt@a=0;b=1;c=2;d=3", "x","j", "mt@a=0;b=1;c=2;d=3;x=j" },
2026 { "mt@a=0;b=1;c=2;d=3", "a","f", "mt@a=f;b=1;c=2;d=3" },
2027 { "mt@a=0;aa=1;aaa=3", "a","x", "mt@a=x;aa=1;aaa=3" },
2028 { "mt@a=0;aa=1;aaa=3", "aa","x", "mt@a=0;aa=x;aaa=3" },
2029 { "mt@a=0;aa=1;aaa=3", "aaa","x", "mt@a=0;aa=1;aaa=x" },
2030 { "mt@a=0;aa=1;aaa=3", "a","yy", "mt@a=yy;aa=1;aaa=3" },
2031 { "mt@a=0;aa=1;aaa=3", "aa","yy", "mt@a=0;aa=yy;aaa=3" },
2032 { "mt@a=0;aa=1;aaa=3", "aaa","yy", "mt@a=0;aa=1;aaa=yy" },
2033 #endif
2034 #if 1
2035 /* removal tests */
2036 /* 1. removal of item at end */
2037 { "de@collation=phonebook;currency=CHF", "currency", "", "de@collation=phonebook" },
2038 { "de@collation=phonebook;currency=CHF", "currency", NULL, "de@collation=phonebook" },
2039 /* 2. removal of item at beginning */
2040 { "de@collation=phonebook;currency=CHF", "collation", "", "de@currency=CHF" },
2041 { "de@collation=phonebook;currency=CHF", "collation", NULL, "de@currency=CHF" },
2042 /* 3. removal of an item not there */
2043 { "de@collation=phonebook;currency=CHF", "calendar", NULL, "de@collation=phonebook;currency=CHF" },
2044 /* 4. removal of only item */
2045 { "de@collation=phonebook", "collation", NULL, "de" },
2046 #endif
2047 { "de@collation=phonebook", "Currency", "CHF", "de@collation=phonebook;currency=CHF" },
2048 /* cases with legal extra spacing */
2049 /*31*/{ "en_US@ calendar = islamic", "calendar", "japanese", "en_US@calendar=japanese" },
2050 /*32*/{ "en_US@ calendar = gregorian ; collation = phonebook", "calendar", "japanese", "en_US@calendar=japanese;collation=phonebook" },
2051 /*33*/{ "en_US@ calendar = islamic", "currency", "CHF", "en_US@calendar=islamic;currency=CHF" },
2052 /*34*/{ "en_US@ currency = CHF", "calendar", "japanese", "en_US@calendar=japanese;currency=CHF" },
2053 /* cases in which setKeywordValue expected to fail (implied by NULL for expected); locale need not be canonical */
2054 /*35*/{ "en_US@calendar=gregorian;", "calendar", "japanese", NULL },
2055 /*36*/{ "en_US@calendar=gregorian;=", "calendar", "japanese", NULL },
2056 /*37*/{ "en_US@calendar=gregorian;currency=", "calendar", "japanese", NULL },
2057 /*38*/{ "en_US@=", "calendar", "japanese", NULL },
2058 /*39*/{ "en_US@=;", "calendar", "japanese", NULL },
2059 /*40*/{ "en_US@= ", "calendar", "japanese", NULL },
2060 /*41*/{ "en_US@ =", "calendar", "japanese", NULL },
2061 /*42*/{ "en_US@ = ", "calendar", "japanese", NULL },
2062 /*43*/{ "en_US@=;calendar=gregorian", "calendar", "japanese", NULL },
2063 /*44*/{ "en_US@= calen dar = gregorian", "calendar", "japanese", NULL },
2064 /*45*/{ "en_US@= calendar = greg orian", "calendar", "japanese", NULL },
2065 /*46*/{ "en_US@=;cal...endar=gregorian", "calendar", "japanese", NULL },
2066 /*47*/{ "en_US@=;calendar=greg...orian", "calendar", "japanese", NULL },
2067 /*48*/{ "en_US@calendar=gregorian", "cale ndar", "japanese", NULL },
2068 /*49*/{ "en_US@calendar=gregorian", "calendar", "japa..nese", NULL },
2069 /* cases in which getKeywordValue and setKeyword expected to fail (implied by NULL for value and expected) */
2070 /*50*/{ "en_US@=", "calendar", NULL, NULL },
2071 /*51*/{ "en_US@=;", "calendar", NULL, NULL },
2072 /*52*/{ "en_US@= ", "calendar", NULL, NULL },
2073 /*53*/{ "en_US@ =", "calendar", NULL, NULL },
2074 /*54*/{ "en_US@ = ", "calendar", NULL, NULL },
2075 /*55*/{ "en_US@=;calendar=gregorian", "calendar", NULL, NULL },
2076 /*56*/{ "en_US@= calen dar = gregorian", "calendar", NULL, NULL },
2077 /*57*/{ "en_US@= calendar = greg orian", "calendar", NULL, NULL },
2078 /*58*/{ "en_US@=;cal...endar=gregorian", "calendar", NULL, NULL },
2079 /*59*/{ "en_US@=;calendar=greg...orian", "calendar", NULL, NULL },
2080 /*60*/{ "en_US@calendar=gregorian", "cale ndar", NULL, NULL },
2081 };
2082
2083
2084 static void TestKeywordSet(void)
2085 {
2086 int32_t i = 0;
2087 int32_t resultLen = 0;
2088 char buffer[1024];
2089
2090 char cbuffer[1024];
2091
2092 for(i = 0; i < UPRV_LENGTHOF(kwSetTestCases); i++) {
2093 UErrorCode status = U_ZERO_ERROR;
2094 memset(buffer,'%',1023);
2095 strcpy(buffer, kwSetTestCases[i].l);
2096
2097 if (kwSetTestCases[i].x != NULL) {
2098 uloc_canonicalize(kwSetTestCases[i].l, cbuffer, 1023, &status);
2099 if(strcmp(buffer,cbuffer)) {
2100 log_verbose("note: [%d] wasn't canonical, should be: '%s' not '%s'. Won't check for canonicity in output.\n", i, cbuffer, buffer);
2101 }
2102 /* sanity check test case results for canonicity */
2103 uloc_canonicalize(kwSetTestCases[i].x, cbuffer, 1023, &status);
2104 if(strcmp(kwSetTestCases[i].x,cbuffer)) {
2105 log_err("%s:%d: ERROR: kwSetTestCases[%d].x = '%s', should be %s (must be canonical)\n", __FILE__, __LINE__, i, kwSetTestCases[i].x, cbuffer);
2106 }
2107
2108 status = U_ZERO_ERROR;
2109 resultLen = uloc_setKeywordValue(kwSetTestCases[i].k, kwSetTestCases[i].v, buffer, 1023, &status);
2110 if(U_FAILURE(status)) {
2111 log_err("Err on test case %d for setKeywordValue: got error %s\n", i, u_errorName(status));
2112 } else if(strcmp(buffer,kwSetTestCases[i].x) || ((int32_t)strlen(buffer)!=resultLen)) {
2113 log_err("FAIL: #%d setKeywordValue: %s + [%s=%s] -> %s (%d) expected %s (%d)\n", i, kwSetTestCases[i].l, kwSetTestCases[i].k,
2114 kwSetTestCases[i].v, buffer, resultLen, kwSetTestCases[i].x, strlen(buffer));
2115 } else {
2116 log_verbose("pass: #%d: %s + [%s=%s] -> %s\n", i, kwSetTestCases[i].l, kwSetTestCases[i].k, kwSetTestCases[i].v,buffer);
2117 }
2118
2119 if (kwSetTestCases[i].v != NULL && kwSetTestCases[i].v[0] != 0) {
2120 status = U_ZERO_ERROR;
2121 resultLen = uloc_getKeywordValue(kwSetTestCases[i].x, kwSetTestCases[i].k, buffer, 1023, &status);
2122 if(U_FAILURE(status)) {
2123 log_err("Err on test case %d for getKeywordValue: got error %s\n", i, u_errorName(status));
2124 } else if (resultLen != (int32_t)uprv_strlen(kwSetTestCases[i].v) || uprv_strcmp(buffer, kwSetTestCases[i].v) != 0) {
2125 log_err("FAIL: #%d getKeywordValue: got %s (%d) expected %s (%d)\n", i, buffer, resultLen,
2126 kwSetTestCases[i].v, uprv_strlen(kwSetTestCases[i].v));
2127 }
2128 }
2129 } else {
2130 /* test cases expected to result in error */
2131 status = U_ZERO_ERROR;
2132 resultLen = uloc_setKeywordValue(kwSetTestCases[i].k, kwSetTestCases[i].v, buffer, 1023, &status);
2133 if(U_SUCCESS(status)) {
2134 log_err("Err on test case %d for setKeywordValue: expected to fail but succeeded, got %s (%d)\n", i, buffer, resultLen);
2135 }
2136
2137 if (kwSetTestCases[i].v == NULL) {
2138 status = U_ZERO_ERROR;
2139 strcpy(cbuffer, kwSetTestCases[i].l);
2140 resultLen = uloc_getKeywordValue(cbuffer, kwSetTestCases[i].k, buffer, 1023, &status);
2141 if(U_SUCCESS(status)) {
2142 log_err("Err on test case %d for getKeywordValue: expected to fail but succeeded\n", i);
2143 }
2144 }
2145 }
2146 }
2147 }
2148
2149 static void TestKeywordSetError(void)
2150 {
2151 char buffer[1024];
2152 UErrorCode status;
2153 int32_t res;
2154 int32_t i;
2155 int32_t blen;
2156
2157 /* 0-test whether an error condition modifies the buffer at all */
2158 blen=0;
2159 i=0;
2160 memset(buffer,'%',1023);
2161 status = U_ZERO_ERROR;
2162 res = uloc_setKeywordValue(kwSetTestCases[i].k, kwSetTestCases[i].v, buffer, blen, &status);
2163 if(status != U_ILLEGAL_ARGUMENT_ERROR) {
2164 log_err("expected illegal err got %s\n", u_errorName(status));
2165 return;
2166 }
2167 /* if(res!=strlen(kwSetTestCases[i].x)) {
2168 log_err("expected result %d got %d\n", strlen(kwSetTestCases[i].x), res);
2169 return;
2170 } */
2171 if(buffer[blen]!='%') {
2172 log_err("Buffer byte %d was modified: now %c\n", blen, buffer[blen]);
2173 return;
2174 }
2175 log_verbose("0-buffer modify OK\n");
2176
2177 for(i=0;i<=2;i++) {
2178 /* 1- test a short buffer with growing text */
2179 blen=(int32_t)strlen(kwSetTestCases[i].l)+1;
2180 memset(buffer,'%',1023);
2181 strcpy(buffer,kwSetTestCases[i].l);
2182 status = U_ZERO_ERROR;
2183 res = uloc_setKeywordValue(kwSetTestCases[i].k, kwSetTestCases[i].v, buffer, blen, &status);
2184 if(status != U_BUFFER_OVERFLOW_ERROR) {
2185 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);
2186 return;
2187 }
2188 if(res!=(int32_t)strlen(kwSetTestCases[i].x)) {
2189 log_err("expected result %d got %d\n", strlen(kwSetTestCases[i].x), res);
2190 return;
2191 }
2192 if(buffer[blen]!='%') {
2193 log_err("Buffer byte %d was modified: now %c\n", blen, buffer[blen]);
2194 return;
2195 }
2196 log_verbose("1/%d-buffer modify OK\n",i);
2197 }
2198
2199 for(i=3;i<=4;i++) {
2200 /* 2- test a short buffer - text the same size or shrinking */
2201 blen=(int32_t)strlen(kwSetTestCases[i].l)+1;
2202 memset(buffer,'%',1023);
2203 strcpy(buffer,kwSetTestCases[i].l);
2204 status = U_ZERO_ERROR;
2205 res = uloc_setKeywordValue(kwSetTestCases[i].k, kwSetTestCases[i].v, buffer, blen, &status);
2206 if(status != U_ZERO_ERROR) {
2207 log_err("expected zero error got %s\n", u_errorName(status));
2208 return;
2209 }
2210 if(buffer[blen+1]!='%') {
2211 log_err("Buffer byte %d was modified: now %c\n", blen+1, buffer[blen+1]);
2212 return;
2213 }
2214 if(res!=(int32_t)strlen(kwSetTestCases[i].x)) {
2215 log_err("expected result %d got %d\n", strlen(kwSetTestCases[i].x), res);
2216 return;
2217 }
2218 if(strcmp(buffer,kwSetTestCases[i].x) || ((int32_t)strlen(buffer)!=res)) {
2219 log_err("FAIL: #%d: %s + [%s=%s] -> %s (%d) expected %s (%d)\n", i, kwSetTestCases[i].l, kwSetTestCases[i].k,
2220 kwSetTestCases[i].v, buffer, res, kwSetTestCases[i].x, strlen(buffer));
2221 } else {
2222 log_verbose("pass: #%d: %s + [%s=%s] -> %s\n", i, kwSetTestCases[i].l, kwSetTestCases[i].k, kwSetTestCases[i].v,
2223 buffer);
2224 }
2225 log_verbose("2/%d-buffer modify OK\n",i);
2226 }
2227 }
2228
2229 static int32_t _canonicalize(int32_t selector, /* 0==getName, 1==canonicalize */
2230 const char* localeID,
2231 char* result,
2232 int32_t resultCapacity,
2233 UErrorCode* ec) {
2234 /* YOU can change this to use function pointers if you like */
2235 switch (selector) {
2236 case 0:
2237 return uloc_getName(localeID, result, resultCapacity, ec);
2238 case 1:
2239 return uloc_canonicalize(localeID, result, resultCapacity, ec);
2240 default:
2241 return -1;
2242 }
2243 }
2244
2245 static void TestCanonicalization(void)
2246 {
2247 static const struct {
2248 const char *localeID; /* input */
2249 const char *getNameID; /* expected getName() result */
2250 const char *canonicalID; /* expected canonicalize() result */
2251 } testCases[] = {
2252 { "ca_ES-with-extra-stuff-that really doesn't make any sense-unless-you're trying to increase code coverage",
2253 "ca_ES_WITH_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_YOU'RE TRYING TO INCREASE CODE COVERAGE",
2254 "ca_ES_WITH_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_YOU'RE TRYING TO INCREASE CODE COVERAGE"},
2255 { "zh@collation=pinyin", "zh@collation=pinyin", "zh@collation=pinyin" },
2256 { "zh_CN@collation=pinyin", "zh_CN@collation=pinyin", "zh_CN@collation=pinyin" },
2257 { "zh_CN_CA@collation=pinyin", "zh_CN_CA@collation=pinyin", "zh_CN_CA@collation=pinyin" },
2258 { "en_US_POSIX", "en_US_POSIX", "en_US_POSIX" },
2259 { "hy_AM_REVISED", "hy_AM_REVISED", "hy_AM_REVISED" },
2260 { "no_NO_NY", "no_NO_NY", "no_NO_NY" /* not: "nn_NO" [alan ICU3.0] */ },
2261 { "no@ny", "no@ny", "no__NY" /* not: "nn" [alan ICU3.0] */ }, /* POSIX ID */
2262 { "no-no.utf32@B", "no_NO.utf32@B", "no_NO_B" /* not: "nb_NO_B" [alan ICU3.0] */ }, /* POSIX ID */
2263 { "qz-qz@Euro", "qz_QZ@Euro", "qz_QZ_EURO" }, /* qz-qz uses private use iso codes */
2264 { "en-BOONT", "en__BOONT", "en__BOONT" }, /* registered name */
2265 { "de-1901", "de__1901", "de__1901" }, /* registered name */
2266 { "de-1906", "de__1906", "de__1906" }, /* registered name */
2267
2268 /* posix behavior that used to be performed by getName */
2269 { "mr.utf8", "mr.utf8", "mr" },
2270 { "de-tv.koi8r", "de_TV.koi8r", "de_TV" },
2271 { "x-piglatin_ML.MBE", "x-piglatin_ML.MBE", "x-piglatin_ML" },
2272 { "i-cherokee_US.utf7", "i-cherokee_US.utf7", "i-cherokee_US" },
2273 { "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA" },
2274 { "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 */
2275
2276 /* fleshing out canonicalization */
2277 /* trim space and sort keywords, ';' is separator so not present at end in canonical form */
2278 { "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" },
2279 /* already-canonical ids are not changed */
2280 { "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" },
2281 /* norwegian is just too weird, if we handle things in their full generality */
2282 { "no-Hant-GB_NY@currency=$$$", "no_Hant_GB_NY@currency=$$$", "no_Hant_GB_NY@currency=$$$" /* not: "nn_Hant_GB@currency=$$$" [alan ICU3.0] */ },
2283
2284 /* test cases reflecting internal resource bundle usage */
2285 { "root@kw=foo", "root@kw=foo", "root@kw=foo" },
2286 { "@calendar=gregorian", "@calendar=gregorian", "@calendar=gregorian" },
2287 { "ja_JP@calendar=Japanese", "ja_JP@calendar=Japanese", "ja_JP@calendar=Japanese" },
2288 { "ja_JP", "ja_JP", "ja_JP" },
2289
2290 /* test case for "i-default" */
2291 { "i-default", "en@x=i-default", "en@x=i-default" },
2292
2293 // Before ICU 64, ICU locale canonicalization had some additional mappings.
2294 // They were removed for ICU-20187 "drop support for long-obsolete locale ID variants".
2295 // The following now use standard canonicalization.
2296 { "ca_ES_PREEURO", "ca_ES_PREEURO", "ca_ES_PREEURO" },
2297 { "de_AT_PREEURO", "de_AT_PREEURO", "de_AT_PREEURO" },
2298 { "de_DE_PREEURO", "de_DE_PREEURO", "de_DE_PREEURO" },
2299 { "de_LU_PREEURO", "de_LU_PREEURO", "de_LU_PREEURO" },
2300 { "el_GR_PREEURO", "el_GR_PREEURO", "el_GR_PREEURO" },
2301 { "en_BE_PREEURO", "en_BE_PREEURO", "en_BE_PREEURO" },
2302 { "en_IE_PREEURO", "en_IE_PREEURO", "en_IE_PREEURO" },
2303 { "es_ES_PREEURO", "es_ES_PREEURO", "es_ES_PREEURO" },
2304 { "eu_ES_PREEURO", "eu_ES_PREEURO", "eu_ES_PREEURO" },
2305 { "fi_FI_PREEURO", "fi_FI_PREEURO", "fi_FI_PREEURO" },
2306 { "fr_BE_PREEURO", "fr_BE_PREEURO", "fr_BE_PREEURO" },
2307 { "fr_FR_PREEURO", "fr_FR_PREEURO", "fr_FR_PREEURO" },
2308 { "fr_LU_PREEURO", "fr_LU_PREEURO", "fr_LU_PREEURO" },
2309 { "ga_IE_PREEURO", "ga_IE_PREEURO", "ga_IE_PREEURO" },
2310 { "gl_ES_PREEURO", "gl_ES_PREEURO", "gl_ES_PREEURO" },
2311 { "it_IT_PREEURO", "it_IT_PREEURO", "it_IT_PREEURO" },
2312 { "nl_BE_PREEURO", "nl_BE_PREEURO", "nl_BE_PREEURO" },
2313 { "nl_NL_PREEURO", "nl_NL_PREEURO", "nl_NL_PREEURO" },
2314 { "pt_PT_PREEURO", "pt_PT_PREEURO", "pt_PT_PREEURO" },
2315 { "de__PHONEBOOK", "de__PHONEBOOK", "de__PHONEBOOK" },
2316 { "en_GB_EURO", "en_GB_EURO", "en_GB_EURO" },
2317 { "en_GB@EURO", "en_GB@EURO", "en_GB_EURO" }, /* POSIX ID */
2318 { "es__TRADITIONAL", "es__TRADITIONAL", "es__TRADITIONAL" },
2319 { "hi__DIRECT", "hi__DIRECT", "hi__DIRECT" },
2320 { "ja_JP_TRADITIONAL", "ja_JP_TRADITIONAL", "ja_JP_TRADITIONAL" },
2321 { "th_TH_TRADITIONAL", "th_TH_TRADITIONAL", "th_TH_TRADITIONAL" },
2322 { "zh_TW_STROKE", "zh_TW_STROKE", "zh_TW_STROKE" },
2323 { "zh__PINYIN", "zh__PINYIN", "zh__PINYIN" },
2324 { "zh_CN_STROKE", "zh_CN_STROKE", "zh_CN_STROKE" },
2325 { "sr-SP-Cyrl", "sr_SP_CYRL", "sr_SP_CYRL" }, /* .NET name */
2326 { "sr-SP-Latn", "sr_SP_LATN", "sr_SP_LATN" }, /* .NET name */
2327 { "sr_YU_CYRILLIC", "sr_YU_CYRILLIC", "sr_YU_CYRILLIC" }, /* Linux name */
2328 { "uz-UZ-Cyrl", "uz_UZ_CYRL", "uz_UZ_CYRL" }, /* .NET name */
2329 { "uz-UZ-Latn", "uz_UZ_LATN", "uz_UZ_LATN" }, /* .NET name */
2330 { "zh-CHS", "zh_CHS", "zh_CHS" }, /* .NET name */
2331 { "zh-CHT", "zh_CHT", "zh_CHT" }, /* .NET name This may change back to zh_Hant */
2332 /* PRE_EURO and EURO conversions don't affect other keywords */
2333 { "es_ES_PREEURO@CALendar=Japanese", "es_ES_PREEURO@calendar=Japanese", "es_ES_PREEURO@calendar=Japanese" },
2334 { "es_ES_EURO@SHOUT=zipeedeedoodah", "es_ES_EURO@shout=zipeedeedoodah", "es_ES_EURO@shout=zipeedeedoodah" },
2335 /* currency keyword overrides PRE_EURO and EURO currency */
2336 { "es_ES_PREEURO@currency=EUR", "es_ES_PREEURO@currency=EUR", "es_ES_PREEURO@currency=EUR" },
2337 { "es_ES_EURO@currency=ESP", "es_ES_EURO@currency=ESP", "es_ES_EURO@currency=ESP" },
2338 };
2339
2340 static const char* label[] = { "getName", "canonicalize" };
2341
2342 UErrorCode status = U_ZERO_ERROR;
2343 int32_t i, j, resultLen = 0, origResultLen;
2344 char buffer[256];
2345
2346 for (i=0; i < UPRV_LENGTHOF(testCases); i++) {
2347 for (j=0; j<2; ++j) {
2348 const char* expected = (j==0) ? testCases[i].getNameID : testCases[i].canonicalID;
2349 *buffer = 0;
2350 status = U_ZERO_ERROR;
2351
2352 if (expected == NULL) {
2353 expected = uloc_getDefault();
2354 }
2355
2356 /* log_verbose("testing %s -> %s\n", testCases[i], testCases[i].canonicalID); */
2357 origResultLen = _canonicalize(j, testCases[i].localeID, NULL, 0, &status);
2358 if (status != U_BUFFER_OVERFLOW_ERROR) {
2359 log_err("FAIL: uloc_%s(%s) => %s, expected U_BUFFER_OVERFLOW_ERROR\n",
2360 label[j], testCases[i].localeID, u_errorName(status));
2361 continue;
2362 }
2363 status = U_ZERO_ERROR;
2364 resultLen = _canonicalize(j, testCases[i].localeID, buffer, sizeof(buffer), &status);
2365 if (U_FAILURE(status)) {
2366 log_err("FAIL: uloc_%s(%s) => %s, expected U_ZERO_ERROR\n",
2367 label[j], testCases[i].localeID, u_errorName(status));
2368 continue;
2369 }
2370 if(uprv_strcmp(expected, buffer) != 0) {
2371 log_err("FAIL: uloc_%s(%s) => \"%s\", expected \"%s\"\n",
2372 label[j], testCases[i].localeID, buffer, expected);
2373 } else {
2374 log_verbose("Ok: uloc_%s(%s) => \"%s\"\n",
2375 label[j], testCases[i].localeID, buffer);
2376 }
2377 if (resultLen != (int32_t)strlen(buffer)) {
2378 log_err("FAIL: uloc_%s(%s) => len %d, expected len %d\n",
2379 label[j], testCases[i].localeID, resultLen, strlen(buffer));
2380 }
2381 if (origResultLen != resultLen) {
2382 log_err("FAIL: uloc_%s(%s) => preflight len %d != actual len %d\n",
2383 label[j], testCases[i].localeID, origResultLen, resultLen);
2384 }
2385 }
2386 }
2387 }
2388
2389 static void TestCanonicalizationBuffer(void)
2390 {
2391 UErrorCode status = U_ZERO_ERROR;
2392 char buffer[256];
2393
2394 // ULOC_FULLNAME_CAPACITY == 157 (uloc.h)
2395 static const char name[] =
2396 "zh@x"
2397 "=foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
2398 "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
2399 "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
2400 "-foo-barz"
2401 ;
2402 static const size_t len = sizeof(name) - 1; // Without NUL terminator.
2403
2404 int32_t reslen = uloc_canonicalize(name, buffer, (int32_t)len, &status);
2405
2406 if (U_FAILURE(status)) {
2407 log_err("FAIL: uloc_canonicalize(%s) => %s, expected !U_FAILURE()\n",
2408 name, u_errorName(status));
2409 return;
2410 }
2411
2412 if (reslen != len) {
2413 log_err("FAIL: uloc_canonicalize(%s) => \"%i\", expected \"%u\"\n",
2414 name, reslen, len);
2415 return;
2416 }
2417
2418 if (uprv_strncmp(name, buffer, len) != 0) {
2419 log_err("FAIL: uloc_canonicalize(%s) => \"%.*s\", expected \"%s\"\n",
2420 name, reslen, buffer, name);
2421 return;
2422 }
2423 }
2424
2425 static void TestDisplayKeywords(void)
2426 {
2427 int32_t i;
2428
2429 static const struct {
2430 const char *localeID;
2431 const char *displayLocale;
2432 UChar displayKeyword[200];
2433 } testCases[] = {
2434 { "ca_ES@currency=ESP", "de_AT",
2435 {0x0057, 0x00e4, 0x0068, 0x0072, 0x0075, 0x006e, 0x0067, 0x0000},
2436 },
2437 { "ja_JP@calendar=japanese", "de",
2438 { 0x004b, 0x0061, 0x006c, 0x0065, 0x006e, 0x0064, 0x0065, 0x0072, 0x0000}
2439 },
2440 { "de_DE@collation=traditional", "de_DE",
2441 {0x0053, 0x006f, 0x0072, 0x0074, 0x0069, 0x0065, 0x0072, 0x0075, 0x006e, 0x0067, 0x0000}
2442 },
2443 };
2444 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
2445 UErrorCode status = U_ZERO_ERROR;
2446 const char* keyword =NULL;
2447 int32_t keywordLen = 0;
2448 int32_t keywordCount = 0;
2449 UChar *displayKeyword=NULL;
2450 int32_t displayKeywordLen = 0;
2451 UEnumeration* keywordEnum = uloc_openKeywords(testCases[i].localeID, &status);
2452 for(keywordCount = uenum_count(keywordEnum, &status); keywordCount > 0 ; keywordCount--){
2453 if(U_FAILURE(status)){
2454 log_err("uloc_getKeywords failed for locale id: %s with error : %s \n", testCases[i].localeID, u_errorName(status));
2455 break;
2456 }
2457 /* the uenum_next returns NUL terminated string */
2458 keyword = uenum_next(keywordEnum, &keywordLen, &status);
2459 /* fetch the displayKeyword */
2460 displayKeywordLen = uloc_getDisplayKeyword(keyword, testCases[i].displayLocale, displayKeyword, displayKeywordLen, &status);
2461 if(status==U_BUFFER_OVERFLOW_ERROR){
2462 status = U_ZERO_ERROR;
2463 displayKeywordLen++; /* for null termination */
2464 displayKeyword = (UChar*) malloc(displayKeywordLen * U_SIZEOF_UCHAR);
2465 displayKeywordLen = uloc_getDisplayKeyword(keyword, testCases[i].displayLocale, displayKeyword, displayKeywordLen, &status);
2466 if(U_FAILURE(status)){
2467 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));
2468 free(displayKeyword);
2469 break;
2470 }
2471 if(u_strncmp(displayKeyword, testCases[i].displayKeyword, displayKeywordLen)!=0){
2472 if (status == U_USING_DEFAULT_WARNING) {
2473 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));
2474 } else {
2475 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);
2476 }
2477 free(displayKeyword);
2478 break;
2479 }
2480 }else{
2481 log_err("uloc_getDisplayKeyword did not return the expected error. Error: %s\n", u_errorName(status));
2482 }
2483
2484 free(displayKeyword);
2485
2486 }
2487 uenum_close(keywordEnum);
2488 }
2489 }
2490
2491 static void TestDisplayKeywordValues(void){
2492 int32_t i;
2493
2494 static const struct {
2495 const char *localeID;
2496 const char *displayLocale;
2497 UChar displayKeywordValue[500];
2498 } testCases[] = {
2499 { "ca_ES@currency=ESP", "de_AT",
2500 {0x0053, 0x0070, 0x0061, 0x006e, 0x0069, 0x0073, 0x0063, 0x0068, 0x0065, 0x0020, 0x0050, 0x0065, 0x0073, 0x0065, 0x0074, 0x0061, 0x0000}
2501 },
2502 { "de_AT@currency=ATS", "fr_FR",
2503 {0x0073, 0x0063, 0x0068, 0x0069, 0x006c, 0x006c, 0x0069, 0x006e, 0x0067, 0x0020, 0x0061, 0x0075, 0x0074, 0x0072, 0x0069, 0x0063, 0x0068, 0x0069, 0x0065, 0x006e, 0x0000}
2504 },
2505 { "de_DE@currency=DEM", "it",
2506 {0x006d, 0x0061, 0x0072, 0x0063, 0x006f, 0x0020, 0x0074, 0x0065, 0x0064, 0x0065, 0x0073, 0x0063, 0x006f, 0x0000}
2507 },
2508 { "el_GR@currency=GRD", "en",
2509 {0x0047, 0x0072, 0x0065, 0x0065, 0x006b, 0x0020, 0x0044, 0x0072, 0x0061, 0x0063, 0x0068, 0x006d, 0x0061, 0x0000}
2510 },
2511 { "eu_ES@currency=ESP", "it_IT",
2512 {0x0070, 0x0065, 0x0073, 0x0065, 0x0074, 0x0061, 0x0020, 0x0073, 0x0070, 0x0061, 0x0067, 0x006e, 0x006f, 0x006c, 0x0061, 0x0000}
2513 },
2514 { "de@collation=phonebook", "es",
2515 {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}
2516 },
2517
2518 { "de_DE@collation=phonebook", "es",
2519 {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}
2520 },
2521 { "es_ES@collation=traditional","de",
2522 {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}
2523 },
2524 { "ja_JP@calendar=japanese", "de",
2525 {0x004a, 0x0061, 0x0070, 0x0061, 0x006e, 0x0069, 0x0073, 0x0063, 0x0068, 0x0065, 0x0072, 0x0020, 0x004b, 0x0061, 0x006c, 0x0065, 0x006e, 0x0064, 0x0065, 0x0072, 0x0000}
2526 },
2527 };
2528 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
2529 UErrorCode status = U_ZERO_ERROR;
2530 const char* keyword =NULL;
2531 int32_t keywordLen = 0;
2532 int32_t keywordCount = 0;
2533 UChar *displayKeywordValue = NULL;
2534 int32_t displayKeywordValueLen = 0;
2535 UEnumeration* keywordEnum = uloc_openKeywords(testCases[i].localeID, &status);
2536 for(keywordCount = uenum_count(keywordEnum, &status); keywordCount > 0 ; keywordCount--){
2537 if(U_FAILURE(status)){
2538 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));
2539 break;
2540 }
2541 /* the uenum_next returns NUL terminated string */
2542 keyword = uenum_next(keywordEnum, &keywordLen, &status);
2543
2544 /* fetch the displayKeywordValue */
2545 displayKeywordValueLen = uloc_getDisplayKeywordValue(testCases[i].localeID, keyword, testCases[i].displayLocale, displayKeywordValue, displayKeywordValueLen, &status);
2546 if(status==U_BUFFER_OVERFLOW_ERROR){
2547 status = U_ZERO_ERROR;
2548 displayKeywordValueLen++; /* for null termination */
2549 displayKeywordValue = (UChar*)malloc(displayKeywordValueLen * U_SIZEOF_UCHAR);
2550 displayKeywordValueLen = uloc_getDisplayKeywordValue(testCases[i].localeID, keyword, testCases[i].displayLocale, displayKeywordValue, displayKeywordValueLen, &status);
2551 if(U_FAILURE(status)){
2552 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));
2553 free(displayKeywordValue);
2554 break;
2555 }
2556 if(u_strncmp(displayKeywordValue, testCases[i].displayKeywordValue, displayKeywordValueLen)!=0){
2557 if (status == U_USING_DEFAULT_WARNING) {
2558 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));
2559 } else {
2560 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));
2561 }
2562 free(displayKeywordValue);
2563 break;
2564 }
2565 }else{
2566 log_err("uloc_getDisplayKeywordValue did not return the expected error. Error: %s\n", u_errorName(status));
2567 }
2568 free(displayKeywordValue);
2569 }
2570 uenum_close(keywordEnum);
2571 }
2572 {
2573 /* test a multiple keywords */
2574 UErrorCode status = U_ZERO_ERROR;
2575 const char* keyword =NULL;
2576 int32_t keywordLen = 0;
2577 int32_t keywordCount = 0;
2578 const char* localeID = "es@collation=phonebook;calendar=buddhist;currency=DEM";
2579 const char* displayLocale = "de";
2580 static const UChar expected[][50] = {
2581 {0x0042, 0x0075, 0x0064, 0x0064, 0x0068, 0x0069, 0x0073, 0x0074, 0x0069, 0x0073, 0x0063, 0x0068, 0x0065, 0x0072, 0x0020, 0x004b, 0x0061, 0x006c, 0x0065, 0x006e, 0x0064, 0x0065, 0x0072, 0x0000},
2582
2583 {0x0054, 0x0065, 0x006c, 0x0065, 0x0066, 0x006f, 0x006e, 0x0062, 0x0075, 0x0063, 0x0068, 0x002d, 0x0053, 0x006f, 0x0072, 0x0074, 0x0069, 0x0065, 0x0072, 0x0075, 0x006e, 0x0067, 0x0000},
2584 {0x0044, 0x0065, 0x0075, 0x0074, 0x0073, 0x0063, 0x0068, 0x0065, 0x0020, 0x004d, 0x0061, 0x0072, 0x006b, 0x0000},
2585 };
2586
2587 UEnumeration* keywordEnum = uloc_openKeywords(localeID, &status);
2588
2589 for(keywordCount = 0; keywordCount < uenum_count(keywordEnum, &status) ; keywordCount++){
2590 UChar *displayKeywordValue = NULL;
2591 int32_t displayKeywordValueLen = 0;
2592 if(U_FAILURE(status)){
2593 log_err("uloc_getKeywords failed for locale id: %s in display locale: % with error : %s \n", localeID, displayLocale, u_errorName(status));
2594 break;
2595 }
2596 /* the uenum_next returns NUL terminated string */
2597 keyword = uenum_next(keywordEnum, &keywordLen, &status);
2598
2599 /* fetch the displayKeywordValue */
2600 displayKeywordValueLen = uloc_getDisplayKeywordValue(localeID, keyword, displayLocale, displayKeywordValue, displayKeywordValueLen, &status);
2601 if(status==U_BUFFER_OVERFLOW_ERROR){
2602 status = U_ZERO_ERROR;
2603 displayKeywordValueLen++; /* for null termination */
2604 displayKeywordValue = (UChar*)malloc(displayKeywordValueLen * U_SIZEOF_UCHAR);
2605 displayKeywordValueLen = uloc_getDisplayKeywordValue(localeID, keyword, displayLocale, displayKeywordValue, displayKeywordValueLen, &status);
2606 if(U_FAILURE(status)){
2607 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));
2608 free(displayKeywordValue);
2609 break;
2610 }
2611 if(u_strncmp(displayKeywordValue, expected[keywordCount], displayKeywordValueLen)!=0){
2612 if (status == U_USING_DEFAULT_WARNING) {
2613 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));
2614 } else {
2615 log_err("uloc_getDisplayKeywordValue did not return the expected value keyword : %s in locale id: %s for display locale: %s \n", localeID, keyword, displayLocale);
2616 }
2617 free(displayKeywordValue);
2618 break;
2619 }
2620 }else{
2621 log_err("uloc_getDisplayKeywordValue did not return the expected error. Error: %s\n", u_errorName(status));
2622 }
2623 free(displayKeywordValue);
2624 }
2625 uenum_close(keywordEnum);
2626
2627 }
2628 {
2629 /* Test non existent keywords */
2630 UErrorCode status = U_ZERO_ERROR;
2631 const char* localeID = "es";
2632 const char* displayLocale = "de";
2633 UChar *displayKeywordValue = NULL;
2634 int32_t displayKeywordValueLen = 0;
2635
2636 /* fetch the displayKeywordValue */
2637 displayKeywordValueLen = uloc_getDisplayKeywordValue(localeID, "calendar", displayLocale, displayKeywordValue, displayKeywordValueLen, &status);
2638 if(U_FAILURE(status)) {
2639 log_err("uloc_getDisplaykeywordValue returned error status %s\n", u_errorName(status));
2640 } else if(displayKeywordValueLen != 0) {
2641 log_err("uloc_getDisplaykeywordValue returned %d should be 0 \n", displayKeywordValueLen);
2642 }
2643 }
2644 }
2645
2646
2647 static void TestGetBaseName(void) {
2648 static const struct {
2649 const char *localeID;
2650 const char *baseName;
2651 } testCases[] = {
2652 { "de_DE@ C o ll A t i o n = Phonebook ", "de_DE" },
2653 { "de@currency = euro; CoLLaTion = PHONEBOOk", "de" },
2654 { "ja@calendar = buddhist", "ja" }
2655 };
2656
2657 int32_t i = 0, baseNameLen = 0;
2658 char baseName[256];
2659 UErrorCode status = U_ZERO_ERROR;
2660
2661 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
2662 baseNameLen = uloc_getBaseName(testCases[i].localeID, baseName, 256, &status);
2663 (void)baseNameLen; /* Suppress set but not used warning. */
2664 if(strcmp(testCases[i].baseName, baseName)) {
2665 log_err("For locale \"%s\" expected baseName \"%s\", but got \"%s\"\n",
2666 testCases[i].localeID, testCases[i].baseName, baseName);
2667 return;
2668 }
2669 }
2670 }
2671
2672 static void TestTrailingNull(void) {
2673 const char* localeId = "zh_Hans";
2674 UChar buffer[128]; /* sufficient for this test */
2675 int32_t len;
2676 UErrorCode status = U_ZERO_ERROR;
2677 int i;
2678
2679 len = uloc_getDisplayName(localeId, localeId, buffer, 128, &status);
2680 if (len > 128) {
2681 log_err("buffer too small");
2682 return;
2683 }
2684
2685 for (i = 0; i < len; ++i) {
2686 if (buffer[i] == 0) {
2687 log_err("name contained null");
2688 return;
2689 }
2690 }
2691 }
2692
2693 /* Jitterbug 4115 */
2694 static void TestDisplayNameWarning(void) {
2695 UChar name[256];
2696 int32_t size;
2697 UErrorCode status = U_ZERO_ERROR;
2698
2699 size = uloc_getDisplayLanguage("qqq", "kl", name, UPRV_LENGTHOF(name), &status);
2700 (void)size; /* Suppress set but not used warning. */
2701 if (status != U_USING_DEFAULT_WARNING) {
2702 log_err("For language \"qqq\" in locale \"kl\", expecting U_USING_DEFAULT_WARNING, but got %s\n",
2703 u_errorName(status));
2704 }
2705 }
2706
2707
2708 /**
2709 * Compare two locale IDs. If they are equal, return 0. If `string'
2710 * starts with `prefix' plus an additional element, that is, string ==
2711 * prefix + '_' + x, then return 1. Otherwise return a value < 0.
2712 */
2713 static UBool _loccmp(const char* string, const char* prefix) {
2714 int32_t slen = (int32_t)uprv_strlen(string),
2715 plen = (int32_t)uprv_strlen(prefix);
2716 int32_t c = uprv_strncmp(string, prefix, plen);
2717 /* 'root' is less than everything */
2718 if (uprv_strcmp(prefix, "root") == 0) {
2719 return (uprv_strcmp(string, "root") == 0) ? 0 : 1;
2720 }
2721 if (c) return -1; /* mismatch */
2722 if (slen == plen) return 0;
2723 if (string[plen] == '_') return 1;
2724 return -2; /* false match, e.g. "en_USX" cmp "en_US" */
2725 }
2726
2727 static void _checklocs(const char* label,
2728 const char* req,
2729 const char* valid,
2730 const char* actual) {
2731 /* We want the valid to be strictly > the bogus requested locale,
2732 and the valid to be >= the actual. */
2733 if (_loccmp(req, valid) > 0 &&
2734 _loccmp(valid, actual) >= 0) {
2735 log_verbose("%s; req=%s, valid=%s, actual=%s\n",
2736 label, req, valid, actual);
2737 } else {
2738 log_err("FAIL: %s; req=%s, valid=%s, actual=%s\n",
2739 label, req, valid, actual);
2740 }
2741 }
2742
2743 static void TestGetLocale(void) {
2744 UErrorCode ec = U_ZERO_ERROR;
2745 UParseError pe;
2746 UChar EMPTY[1] = {0};
2747
2748 /* === udat === */
2749 #if !UCONFIG_NO_FORMATTING
2750 {
2751 UDateFormat *obj;
2752 const char *req = "en_US_REDWOODSHORES", *valid, *actual;
2753 obj = udat_open(UDAT_DEFAULT, UDAT_DEFAULT,
2754 req,
2755 NULL, 0,
2756 NULL, 0, &ec);
2757 if (U_FAILURE(ec)) {
2758 log_data_err("udat_open failed.Error %s\n", u_errorName(ec));
2759 return;
2760 }
2761 valid = udat_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec);
2762 actual = udat_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec);
2763 if (U_FAILURE(ec)) {
2764 log_err("udat_getLocaleByType() failed\n");
2765 return;
2766 }
2767 _checklocs("udat", req, valid, actual);
2768 udat_close(obj);
2769 }
2770 #endif
2771
2772 /* === ucal === */
2773 #if !UCONFIG_NO_FORMATTING
2774 {
2775 UCalendar *obj;
2776 const char *req = "fr_FR_PROVENCAL", *valid, *actual;
2777 obj = ucal_open(NULL, 0,
2778 req,
2779 UCAL_GREGORIAN,
2780 &ec);
2781 if (U_FAILURE(ec)) {
2782 log_err("ucal_open failed with error: %s\n", u_errorName(ec));
2783 return;
2784 }
2785 valid = ucal_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec);
2786 actual = ucal_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec);
2787 if (U_FAILURE(ec)) {
2788 log_err("ucal_getLocaleByType() failed\n");
2789 return;
2790 }
2791 _checklocs("ucal", req, valid, actual);
2792 ucal_close(obj);
2793 }
2794 #endif
2795
2796 /* === unum === */
2797 #if !UCONFIG_NO_FORMATTING
2798 {
2799 UNumberFormat *obj;
2800 const char *req = "zh_Hant_TW_TAINAN", *valid, *actual;
2801 obj = unum_open(UNUM_DECIMAL,
2802 NULL, 0,
2803 req,
2804 &pe, &ec);
2805 if (U_FAILURE(ec)) {
2806 log_err("unum_open failed\n");
2807 return;
2808 }
2809 valid = unum_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec);
2810 actual = unum_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec);
2811 if (U_FAILURE(ec)) {
2812 log_err("unum_getLocaleByType() failed\n");
2813 return;
2814 }
2815 _checklocs("unum", req, valid, actual);
2816 unum_close(obj);
2817 }
2818 #endif
2819
2820 /* === umsg === */
2821 #if 0
2822 /* commented out by weiv 01/12/2005. umsg_getLocaleByType is to be removed */
2823 #if !UCONFIG_NO_FORMATTING
2824 {
2825 UMessageFormat *obj;
2826 const char *req = "ja_JP_TAKAYAMA", *valid, *actual;
2827 UBool test;
2828 obj = umsg_open(EMPTY, 0,
2829 req,
2830 &pe, &ec);
2831 if (U_FAILURE(ec)) {
2832 log_err("umsg_open failed\n");
2833 return;
2834 }
2835 valid = umsg_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec);
2836 actual = umsg_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec);
2837 if (U_FAILURE(ec)) {
2838 log_err("umsg_getLocaleByType() failed\n");
2839 return;
2840 }
2841 /* We want the valid to be strictly > the bogus requested locale,
2842 and the valid to be >= the actual. */
2843 /* TODO MessageFormat is currently just storing the locale it is given.
2844 As a result, it will return whatever it was given, even if the
2845 locale is invalid. */
2846 test = (_cmpversion("3.2") <= 0) ?
2847 /* Here is the weakened test for 3.0: */
2848 (_loccmp(req, valid) >= 0) :
2849 /* Here is what the test line SHOULD be: */
2850 (_loccmp(req, valid) > 0);
2851
2852 if (test &&
2853 _loccmp(valid, actual) >= 0) {
2854 log_verbose("umsg; req=%s, valid=%s, actual=%s\n", req, valid, actual);
2855 } else {
2856 log_err("FAIL: umsg; req=%s, valid=%s, actual=%s\n", req, valid, actual);
2857 }
2858 umsg_close(obj);
2859 }
2860 #endif
2861 #endif
2862
2863 /* === ubrk === */
2864 #if !UCONFIG_NO_BREAK_ITERATION
2865 {
2866 UBreakIterator *obj;
2867 const char *req = "ar_KW_ABDALI", *valid, *actual;
2868 obj = ubrk_open(UBRK_WORD,
2869 req,
2870 EMPTY,
2871 0,
2872 &ec);
2873 if (U_FAILURE(ec)) {
2874 log_err("ubrk_open failed. Error: %s \n", u_errorName(ec));
2875 return;
2876 }
2877 valid = ubrk_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec);
2878 actual = ubrk_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec);
2879 if (U_FAILURE(ec)) {
2880 log_err("ubrk_getLocaleByType() failed\n");
2881 return;
2882 }
2883 _checklocs("ubrk", req, valid, actual);
2884 ubrk_close(obj);
2885 }
2886 #endif
2887
2888 /* === ucol === */
2889 #if !UCONFIG_NO_COLLATION
2890 {
2891 UCollator *obj;
2892 const char *req = "es_AR_BUENOSAIRES", *valid, *actual;
2893 obj = ucol_open(req, &ec);
2894 if (U_FAILURE(ec)) {
2895 log_err("ucol_open failed - %s\n", u_errorName(ec));
2896 return;
2897 }
2898 valid = ucol_getLocaleByType(obj, ULOC_VALID_LOCALE, &ec);
2899 actual = ucol_getLocaleByType(obj, ULOC_ACTUAL_LOCALE, &ec);
2900 if (U_FAILURE(ec)) {
2901 log_err("ucol_getLocaleByType() failed\n");
2902 return;
2903 }
2904 _checklocs("ucol", req, valid, actual);
2905 ucol_close(obj);
2906 }
2907 #endif
2908 }
2909 static void TestEnglishExemplarCharacters(void) {
2910 UErrorCode status = U_ZERO_ERROR;
2911 int i;
2912 USet *exSet = NULL;
2913 UChar testChars[] = {
2914 0x61, /* standard */
2915 0xE1, /* auxiliary */
2916 0x41, /* index */
2917 0x2D /* punctuation */
2918 };
2919 ULocaleData *uld = ulocdata_open("en", &status);
2920 if (U_FAILURE(status)) {
2921 log_data_err("ulocdata_open() failed : %s - (Are you missing data?)\n", u_errorName(status));
2922 return;
2923 }
2924
2925 for (i = 0; i < ULOCDATA_ES_COUNT; i++) {
2926 exSet = ulocdata_getExemplarSet(uld, exSet, 0, (ULocaleDataExemplarSetType)i, &status);
2927 if (U_FAILURE(status)) {
2928 log_err_status(status, "ulocdata_getExemplarSet() for type %d failed\n", i);
2929 status = U_ZERO_ERROR;
2930 continue;
2931 }
2932 if (!uset_contains(exSet, (UChar32)testChars[i])) {
2933 log_err("Character U+%04X is not included in exemplar type %d\n", testChars[i], i);
2934 }
2935 }
2936
2937 uset_close(exSet);
2938 ulocdata_close(uld);
2939 }
2940
2941 static void TestNonexistentLanguageExemplars(void) {
2942 /* JB 4068 - Nonexistent language */
2943 UErrorCode ec = U_ZERO_ERROR;
2944 ULocaleData *uld = ulocdata_open("qqq",&ec);
2945 if (ec != U_USING_DEFAULT_WARNING) {
2946 log_err_status(ec, "Exemplar set for \"qqq\", expecting U_USING_DEFAULT_WARNING, but got %s\n",
2947 u_errorName(ec));
2948 }
2949 uset_close(ulocdata_getExemplarSet(uld, NULL, 0, ULOCDATA_ES_STANDARD, &ec));
2950 ulocdata_close(uld);
2951 }
2952
2953 static void TestLocDataErrorCodeChaining(void) {
2954 UErrorCode ec = U_USELESS_COLLATOR_ERROR;
2955 ulocdata_open(NULL, &ec);
2956 ulocdata_getExemplarSet(NULL, NULL, 0, ULOCDATA_ES_STANDARD, &ec);
2957 ulocdata_getDelimiter(NULL, ULOCDATA_DELIMITER_COUNT, NULL, -1, &ec);
2958 ulocdata_getMeasurementSystem(NULL, &ec);
2959 ulocdata_getPaperSize(NULL, NULL, NULL, &ec);
2960 if (ec != U_USELESS_COLLATOR_ERROR) {
2961 log_err("ulocdata API changed the error code to %s\n", u_errorName(ec));
2962 }
2963 }
2964
2965 typedef struct {
2966 const char* locale;
2967 UMeasurementSystem measureSys;
2968 } LocToMeasureSys;
2969
2970 static const LocToMeasureSys locToMeasures[] = {
2971 { "fr_FR", UMS_SI },
2972 { "en", UMS_US },
2973 { "en_GB", UMS_UK },
2974 { "fr_FR@rg=GBZZZZ", UMS_UK },
2975 { "en@rg=frzzzz", UMS_SI },
2976 { "en_GB@rg=USZZZZ", UMS_US },
2977 { NULL, (UMeasurementSystem)0 } /* terminator */
2978 };
2979
2980 static void TestLocDataWithRgTag(void) {
2981 const LocToMeasureSys* locToMeasurePtr = locToMeasures;
2982 for (; locToMeasurePtr->locale != NULL; locToMeasurePtr++) {
2983 UErrorCode status = U_ZERO_ERROR;
2984 UMeasurementSystem measureSys = ulocdata_getMeasurementSystem(locToMeasurePtr->locale, &status);
2985 if (U_FAILURE(status)) {
2986 log_data_err("ulocdata_getMeasurementSystem(\"%s\", ...) failed: %s - Are you missing data?\n",
2987 locToMeasurePtr->locale, u_errorName(status));
2988 } else if (measureSys != locToMeasurePtr->measureSys) {
2989 log_err("ulocdata_getMeasurementSystem(\"%s\", ...), expected %d, got %d\n",
2990 locToMeasurePtr->locale, (int) locToMeasurePtr->measureSys, (int)measureSys);
2991 }
2992 }
2993 }
2994
2995 static void TestLanguageExemplarsFallbacks(void) {
2996 /* Test that en_US fallsback, but en doesn't fallback. */
2997 UErrorCode ec = U_ZERO_ERROR;
2998 ULocaleData *uld = ulocdata_open("en_US",&ec);
2999 uset_close(ulocdata_getExemplarSet(uld, NULL, 0, ULOCDATA_ES_STANDARD, &ec));
3000 if (ec != U_USING_FALLBACK_WARNING) {
3001 log_err_status(ec, "Exemplar set for \"en_US\", expecting U_USING_FALLBACK_WARNING, but got %s\n",
3002 u_errorName(ec));
3003 }
3004 ulocdata_close(uld);
3005 ec = U_ZERO_ERROR;
3006 uld = ulocdata_open("en",&ec);
3007 uset_close(ulocdata_getExemplarSet(uld, NULL, 0, ULOCDATA_ES_STANDARD, &ec));
3008 if (ec != U_ZERO_ERROR) {
3009 log_err_status(ec, "Exemplar set for \"en\", expecting U_ZERO_ERROR, but got %s\n",
3010 u_errorName(ec));
3011 }
3012 ulocdata_close(uld);
3013 }
3014
3015 static const char *acceptResult(UAcceptResult uar) {
3016 return udbg_enumName(UDBG_UAcceptResult, uar);
3017 }
3018
3019 static void TestAcceptLanguage(void) {
3020 UErrorCode status = U_ZERO_ERROR;
3021 UAcceptResult outResult;
3022 UEnumeration *available;
3023 char tmp[200];
3024 int i;
3025 int32_t rc = 0;
3026
3027 struct {
3028 int32_t httpSet; /**< Which of http[] should be used? */
3029 const char *icuSet; /**< ? */
3030 const char *expect; /**< The expected locale result */
3031 UAcceptResult res; /**< The expected error code */
3032 UErrorCode expectStatus; /**< expected status */
3033 } tests[] = {
3034 /*0*/{ 0, NULL, "mt_MT", ULOC_ACCEPT_VALID, U_ZERO_ERROR},
3035 /*1*/{ 1, NULL, "en", ULOC_ACCEPT_VALID, U_ZERO_ERROR},
3036 /*2*/{ 2, NULL, "en", ULOC_ACCEPT_FALLBACK, U_ZERO_ERROR},
3037 /*3*/{ 3, NULL, "", ULOC_ACCEPT_FAILED, U_ZERO_ERROR},
3038 /*4*/{ 4, NULL, "es", ULOC_ACCEPT_VALID, U_ZERO_ERROR},
3039 /*5*/{ 5, NULL, "en", ULOC_ACCEPT_VALID, U_ZERO_ERROR}, /* XF */
3040 /*6*/{ 6, NULL, "ja", ULOC_ACCEPT_FALLBACK, U_ZERO_ERROR}, /* XF */
3041 /*7*/{ 7, NULL, "zh", ULOC_ACCEPT_FALLBACK, U_ZERO_ERROR}, /* XF */
3042 /*8*/{ 8, NULL, "", ULOC_ACCEPT_FAILED, U_ZERO_ERROR }, /* */
3043 /*9*/{ 9, NULL, "", ULOC_ACCEPT_FAILED, U_ZERO_ERROR }, /* */
3044 /*10*/{10, NULL, "", ULOC_ACCEPT_FAILED, U_BUFFER_OVERFLOW_ERROR }, /* */
3045 /*11*/{11, NULL, "", ULOC_ACCEPT_FAILED, U_BUFFER_OVERFLOW_ERROR }, /* */
3046 };
3047 const int32_t numTests = UPRV_LENGTHOF(tests);
3048 static const char *http[] = {
3049 /*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",
3050 /*1*/ "ja;q=0.5, en;q=0.8, tlh",
3051 /*2*/ "en-wf, de-lx;q=0.8",
3052 /*3*/ "mga-ie;q=0.9, tlh",
3053 /*4*/ "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
3054 "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
3055 "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
3056 "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
3057 "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
3058 "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
3059 "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xx-yy;q=.1, "
3060 "es",
3061 /*5*/ "zh-xx;q=0.9, en;q=0.6",
3062 /*6*/ "ja-JA",
3063 /*7*/ "zh-xx;q=0.9",
3064 /*08*/ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3065 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3066 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3067 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", // 156
3068 /*09*/ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3069 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3070 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3071 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB", // 157 (this hits U_STRING_NOT_TERMINATED_WARNING )
3072 /*10*/ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3073 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3074 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3075 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABC", // 158
3076 /*11*/ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3077 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3078 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3079 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", // 163 bytes
3080 };
3081
3082 for(i=0;i<numTests;i++) {
3083 outResult = -3;
3084 status=U_ZERO_ERROR;
3085 log_verbose("test #%d: http[%s], ICU[%s], expect %s, %s\n",
3086 i, http[tests[i].httpSet], tests[i].icuSet, tests[i].expect, acceptResult(tests[i].res));
3087
3088 available = ures_openAvailableLocales(tests[i].icuSet, &status);
3089 tmp[0]=0;
3090 rc = uloc_acceptLanguageFromHTTP(tmp, 199, &outResult, http[tests[i].httpSet], available, &status);
3091 (void)rc; /* Suppress set but not used warning. */
3092 uenum_close(available);
3093 log_verbose(" got %s, %s [%s]\n", tmp[0]?tmp:"(EMPTY)", acceptResult(outResult), u_errorName(status));
3094 if(status != tests[i].expectStatus) {
3095 log_err_status(status, "FAIL: expected status %s but got %s\n", u_errorName(tests[i].expectStatus), u_errorName(status));
3096 } else if(U_SUCCESS(tests[i].expectStatus)) {
3097 /* don't check content if expected failure */
3098 if(outResult != tests[i].res) {
3099 log_err_status(status, "FAIL: #%d: expected outResult of %s but got %s\n", i,
3100 acceptResult( tests[i].res),
3101 acceptResult( outResult));
3102 log_info("test #%d: http[%s], ICU[%s], expect %s, %s\n",
3103 i, http[tests[i].httpSet], tests[i].icuSet, tests[i].expect,acceptResult(tests[i].res));
3104 }
3105 if((outResult>0)&&uprv_strcmp(tmp, tests[i].expect)) {
3106 log_err_status(status, "FAIL: #%d: expected %s but got %s\n", i, tests[i].expect, tmp);
3107 log_info("test #%d: http[%s], ICU[%s], expect %s, %s\n",
3108 i, http[tests[i].httpSet], tests[i].icuSet, tests[i].expect, acceptResult(tests[i].res));
3109 }
3110 }
3111 }
3112 }
3113
3114 static const char* LOCALE_ALIAS[][2] = {
3115 {"in", "id"},
3116 {"in_ID", "id_ID"},
3117 {"iw", "he"},
3118 {"iw_IL", "he_IL"},
3119 {"ji", "yi"},
3120 {"en_BU", "en_MM"},
3121 {"en_DY", "en_BJ"},
3122 {"en_HV", "en_BF"},
3123 {"en_NH", "en_VU"},
3124 {"en_RH", "en_ZW"},
3125 {"en_TP", "en_TL"},
3126 {"en_ZR", "en_CD"}
3127 };
3128 static UBool isLocaleAvailable(UResourceBundle* resIndex, const char* loc){
3129 UErrorCode status = U_ZERO_ERROR;
3130 int32_t len = 0;
3131 ures_getStringByKey(resIndex, loc,&len, &status);
3132 if(U_FAILURE(status)){
3133 return FALSE;
3134 }
3135 return TRUE;
3136 }
3137
3138 static void TestCalendar() {
3139 #if !UCONFIG_NO_FORMATTING
3140 int i;
3141 UErrorCode status = U_ZERO_ERROR;
3142 UResourceBundle *resIndex = ures_open(NULL,"res_index", &status);
3143 if(U_FAILURE(status)){
3144 log_err_status(status, "Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
3145 return;
3146 }
3147 for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
3148 const char* oldLoc = LOCALE_ALIAS[i][0];
3149 const char* newLoc = LOCALE_ALIAS[i][1];
3150 UCalendar* c1 = NULL;
3151 UCalendar* c2 = NULL;
3152
3153 /*Test function "getLocale(ULocale.VALID_LOCALE)"*/
3154 const char* l1 = ucal_getLocaleByType(c1, ULOC_VALID_LOCALE, &status);
3155 const char* l2 = ucal_getLocaleByType(c2, ULOC_VALID_LOCALE, &status);
3156
3157 if(!isLocaleAvailable(resIndex, newLoc)){
3158 continue;
3159 }
3160 c1 = ucal_open(NULL, -1, oldLoc, UCAL_GREGORIAN, &status);
3161 c2 = ucal_open(NULL, -1, newLoc, UCAL_GREGORIAN, &status);
3162
3163 if (strcmp(newLoc,l1)!=0 || strcmp(l1,l2)!=0 || status!=U_ZERO_ERROR) {
3164 log_err("The locales are not equal!.Old: %s, New: %s \n", oldLoc, newLoc);
3165 }
3166 log_verbose("ucal_getLocaleByType old:%s new:%s\n", l1, l2);
3167 ucal_close(c1);
3168 ucal_close(c2);
3169 }
3170 ures_close(resIndex);
3171 #endif
3172 }
3173
3174 static void TestDateFormat() {
3175 #if !UCONFIG_NO_FORMATTING
3176 int i;
3177 UErrorCode status = U_ZERO_ERROR;
3178 UResourceBundle *resIndex = ures_open(NULL,"res_index", &status);
3179 if(U_FAILURE(status)){
3180 log_err_status(status, "Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
3181 return;
3182 }
3183 for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
3184 const char* oldLoc = LOCALE_ALIAS[i][0];
3185 const char* newLoc = LOCALE_ALIAS[i][1];
3186 UDateFormat* df1 = NULL;
3187 UDateFormat* df2 = NULL;
3188 const char* l1 = NULL;
3189 const char* l2 = NULL;
3190
3191 if(!isLocaleAvailable(resIndex, newLoc)){
3192 continue;
3193 }
3194 df1 = udat_open(UDAT_FULL, UDAT_FULL,oldLoc, NULL, 0, NULL, -1, &status);
3195 df2 = udat_open(UDAT_FULL, UDAT_FULL,newLoc, NULL, 0, NULL, -1, &status);
3196 if(U_FAILURE(status)){
3197 log_err("Creation of date format failed %s\n", u_errorName(status));
3198 return;
3199 }
3200 /*Test function "getLocale"*/
3201 l1 = udat_getLocaleByType(df1, ULOC_VALID_LOCALE, &status);
3202 l2 = udat_getLocaleByType(df2, ULOC_VALID_LOCALE, &status);
3203 if(U_FAILURE(status)){
3204 log_err("Fetching the locale by type failed. %s\n", u_errorName(status));
3205 }
3206 if (strcmp(newLoc,l1)!=0 || strcmp(l1,l2)!=0) {
3207 log_err("The locales are not equal!.Old: %s, New: %s \n", oldLoc, newLoc);
3208 }
3209 log_verbose("udat_getLocaleByType old:%s new:%s\n", l1, l2);
3210 udat_close(df1);
3211 udat_close(df2);
3212 }
3213 ures_close(resIndex);
3214 #endif
3215 }
3216
3217 static void TestCollation() {
3218 #if !UCONFIG_NO_COLLATION
3219 int i;
3220 UErrorCode status = U_ZERO_ERROR;
3221 UResourceBundle *resIndex = ures_open(NULL,"res_index", &status);
3222 if(U_FAILURE(status)){
3223 log_err_status(status, "Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
3224 return;
3225 }
3226 for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
3227 const char* oldLoc = LOCALE_ALIAS[i][0];
3228 const char* newLoc = LOCALE_ALIAS[i][1];
3229 UCollator* c1 = NULL;
3230 UCollator* c2 = NULL;
3231 const char* l1 = NULL;
3232 const char* l2 = NULL;
3233
3234 status = U_ZERO_ERROR;
3235 if(!isLocaleAvailable(resIndex, newLoc)){
3236 continue;
3237 }
3238 if(U_FAILURE(status)){
3239 log_err("Creation of collators failed %s\n", u_errorName(status));
3240 return;
3241 }
3242 c1 = ucol_open(oldLoc, &status);
3243 c2 = ucol_open(newLoc, &status);
3244 l1 = ucol_getLocaleByType(c1, ULOC_VALID_LOCALE, &status);
3245 l2 = ucol_getLocaleByType(c2, ULOC_VALID_LOCALE, &status);
3246 if(U_FAILURE(status)){
3247 log_err("Fetching the locale names failed failed %s\n", u_errorName(status));
3248 }
3249 if (strcmp(newLoc,l1)!=0 || strcmp(l1,l2)!=0) {
3250 log_err("The locales are not equal!.Old: %s, New: %s \n", oldLoc, newLoc);
3251 }
3252 log_verbose("ucol_getLocaleByType old:%s new:%s\n", l1, l2);
3253 ucol_close(c1);
3254 ucol_close(c2);
3255 }
3256 ures_close(resIndex);
3257 #endif
3258 }
3259
3260 typedef struct OrientationStructTag {
3261 const char* localeId;
3262 ULayoutType character;
3263 ULayoutType line;
3264 } OrientationStruct;
3265
3266 static const char* ULayoutTypeToString(ULayoutType type)
3267 {
3268 switch(type)
3269 {
3270 case ULOC_LAYOUT_LTR:
3271 return "ULOC_LAYOUT_LTR";
3272 break;
3273 case ULOC_LAYOUT_RTL:
3274 return "ULOC_LAYOUT_RTL";
3275 break;
3276 case ULOC_LAYOUT_TTB:
3277 return "ULOC_LAYOUT_TTB";
3278 break;
3279 case ULOC_LAYOUT_BTT:
3280 return "ULOC_LAYOUT_BTT";
3281 break;
3282 case ULOC_LAYOUT_UNKNOWN:
3283 break;
3284 }
3285
3286 return "Unknown enum value for ULayoutType!";
3287 }
3288
3289 static void TestOrientation()
3290 {
3291 static const OrientationStruct toTest [] = {
3292 { "ar", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3293 { "aR", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3294 { "ar_Arab", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3295 { "fa", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3296 { "Fa", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3297 { "he", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3298 { "ps", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3299 { "ur", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3300 { "UR", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3301 { "en", ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB },
3302 // Additional Apple tests for rdar://51447187
3303 { "sd", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3304 { "sd_Arab", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3305 { "sd_Deva", ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB },
3306 { "mni_Beng", ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB },
3307 { "mni_Mtei", ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB },
3308 { "sat_Deva", ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB },
3309 { "sat_Olck", ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB },
3310 { "ks", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3311 { "ks_Arab", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3312 { "ks_Aran", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3313 { "ks_Deva", ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB },
3314 { "pa", ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB },
3315 { "pa_Guru", ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB },
3316 { "pa_Arab", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3317 { "pa_Aran", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3318 { "ur", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3319 { "ur_Arab", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3320 { "ur_Aran", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3321 };
3322
3323 size_t i = 0;
3324 for (; i < UPRV_LENGTHOF(toTest); ++i) {
3325 UErrorCode statusCO = U_ZERO_ERROR;
3326 UErrorCode statusLO = U_ZERO_ERROR;
3327 const char* const localeId = toTest[i].localeId;
3328 const ULayoutType co = uloc_getCharacterOrientation(localeId, &statusCO);
3329 const ULayoutType expectedCO = toTest[i].character;
3330 const ULayoutType lo = uloc_getLineOrientation(localeId, &statusLO);
3331 const ULayoutType expectedLO = toTest[i].line;
3332 if (U_FAILURE(statusCO)) {
3333 log_err_status(statusCO,
3334 " unexpected failure for uloc_getCharacterOrientation(), with localId \"%s\" and status %s\n",
3335 localeId,
3336 u_errorName(statusCO));
3337 }
3338 else if (co != expectedCO) {
3339 log_err(
3340 " unexpected result for uloc_getCharacterOrientation(), with localeId \"%s\". Expected %s but got result %s\n",
3341 localeId,
3342 ULayoutTypeToString(expectedCO),
3343 ULayoutTypeToString(co));
3344 }
3345 if (U_FAILURE(statusLO)) {
3346 log_err_status(statusLO,
3347 " unexpected failure for uloc_getLineOrientation(), with localId \"%s\" and status %s\n",
3348 localeId,
3349 u_errorName(statusLO));
3350 }
3351 else if (lo != expectedLO) {
3352 log_err(
3353 " unexpected result for uloc_getLineOrientation(), with localeId \"%s\". Expected %s but got result %s\n",
3354 localeId,
3355 ULayoutTypeToString(expectedLO),
3356 ULayoutTypeToString(lo));
3357 }
3358 }
3359 }
3360
3361 static void TestULocale() {
3362 int i;
3363 UErrorCode status = U_ZERO_ERROR;
3364 UResourceBundle *resIndex = ures_open(NULL,"res_index", &status);
3365 if(U_FAILURE(status)){
3366 log_err_status(status, "Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
3367 return;
3368 }
3369 for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
3370 const char* oldLoc = LOCALE_ALIAS[i][0];
3371 const char* newLoc = LOCALE_ALIAS[i][1];
3372 UChar name1[256], name2[256];
3373 char names1[256], names2[256];
3374 int32_t capacity = 256;
3375
3376 status = U_ZERO_ERROR;
3377 if(!isLocaleAvailable(resIndex, newLoc)){
3378 continue;
3379 }
3380 uloc_getDisplayName(oldLoc, ULOC_US, name1, capacity, &status);
3381 if(U_FAILURE(status)){
3382 log_err("uloc_getDisplayName(%s) failed %s\n", oldLoc, u_errorName(status));
3383 }
3384
3385 uloc_getDisplayName(newLoc, ULOC_US, name2, capacity, &status);
3386 if(U_FAILURE(status)){
3387 log_err("uloc_getDisplayName(%s) failed %s\n", newLoc, u_errorName(status));
3388 }
3389
3390 if (u_strcmp(name1, name2)!=0) {
3391 log_err("The locales are not equal!.Old: %s, New: %s \n", oldLoc, newLoc);
3392 }
3393 u_austrcpy(names1, name1);
3394 u_austrcpy(names2, name2);
3395 log_verbose("uloc_getDisplayName old:%s new:%s\n", names1, names2);
3396 }
3397 ures_close(resIndex);
3398
3399 }
3400
3401 static void TestUResourceBundle() {
3402 const char* us1;
3403 const char* us2;
3404
3405 UResourceBundle* rb1 = NULL;
3406 UResourceBundle* rb2 = NULL;
3407 UErrorCode status = U_ZERO_ERROR;
3408 int i;
3409 UResourceBundle *resIndex = NULL;
3410 if(U_FAILURE(status)){
3411 log_err("Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
3412 return;
3413 }
3414 resIndex = ures_open(NULL,"res_index", &status);
3415 for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
3416
3417 const char* oldLoc = LOCALE_ALIAS[i][0];
3418 const char* newLoc = LOCALE_ALIAS[i][1];
3419 if(!isLocaleAvailable(resIndex, newLoc)){
3420 continue;
3421 }
3422 rb1 = ures_open(NULL, oldLoc, &status);
3423 if (U_FAILURE(status)) {
3424 log_err("ures_open(%s) failed %s\n", oldLoc, u_errorName(status));
3425 }
3426
3427 us1 = ures_getLocaleByType(rb1, ULOC_ACTUAL_LOCALE, &status);
3428
3429 status = U_ZERO_ERROR;
3430 rb2 = ures_open(NULL, newLoc, &status);
3431 if (U_FAILURE(status)) {
3432 log_err("ures_open(%s) failed %s\n", oldLoc, u_errorName(status));
3433 }
3434 us2 = ures_getLocaleByType(rb2, ULOC_ACTUAL_LOCALE, &status);
3435
3436 if (strcmp(us1,newLoc)!=0 || strcmp(us1,us2)!=0 ) {
3437 log_err("The locales are not equal!.Old: %s, New: %s \n", oldLoc, newLoc);
3438 }
3439
3440 log_verbose("ures_getStringByKey old:%s new:%s\n", us1, us2);
3441 ures_close(rb1);
3442 rb1 = NULL;
3443 ures_close(rb2);
3444 rb2 = NULL;
3445 }
3446 ures_close(resIndex);
3447 }
3448
3449 static void TestDisplayName() {
3450
3451 UChar oldCountry[256] = {'\0'};
3452 UChar newCountry[256] = {'\0'};
3453 UChar oldLang[256] = {'\0'};
3454 UChar newLang[256] = {'\0'};
3455 char country[256] ={'\0'};
3456 char language[256] ={'\0'};
3457 int32_t capacity = 256;
3458 int i =0;
3459 int j=0;
3460 for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
3461 const char* oldLoc = LOCALE_ALIAS[i][0];
3462 const char* newLoc = LOCALE_ALIAS[i][1];
3463 UErrorCode status = U_ZERO_ERROR;
3464 int32_t available = uloc_countAvailable();
3465
3466 for(j=0; j<available; j++){
3467
3468 const char* dispLoc = uloc_getAvailable(j);
3469 int32_t oldCountryLen = uloc_getDisplayCountry(oldLoc,dispLoc, oldCountry, capacity, &status);
3470 int32_t newCountryLen = uloc_getDisplayCountry(newLoc, dispLoc, newCountry, capacity, &status);
3471 int32_t oldLangLen = uloc_getDisplayLanguage(oldLoc, dispLoc, oldLang, capacity, &status);
3472 int32_t newLangLen = uloc_getDisplayLanguage(newLoc, dispLoc, newLang, capacity, &status );
3473
3474 int32_t countryLen = uloc_getCountry(newLoc, country, capacity, &status);
3475 int32_t langLen = uloc_getLanguage(newLoc, language, capacity, &status);
3476 /* there is a display name for the current country ID */
3477 if(countryLen != newCountryLen ){
3478 if(u_strncmp(oldCountry,newCountry,oldCountryLen)!=0){
3479 log_err("uloc_getDisplayCountry() failed for %s in display locale %s \n", oldLoc, dispLoc);
3480 }
3481 }
3482 /* there is a display name for the current lang ID */
3483 if(langLen!=newLangLen){
3484 if(u_strncmp(oldLang,newLang,oldLangLen)){
3485 log_err("uloc_getDisplayLanguage() failed for %s in display locale %s \n", oldLoc, dispLoc); }
3486 }
3487 }
3488 }
3489 }
3490
3491 static void TestGetLocaleForLCID() {
3492 int32_t i, length, lengthPre;
3493 const char* testLocale = 0;
3494 UErrorCode status = U_ZERO_ERROR;
3495 char temp2[40], temp3[40];
3496 uint32_t lcid;
3497
3498 lcid = uloc_getLCID("en_US");
3499 if (lcid != 0x0409) {
3500 log_err(" uloc_getLCID(\"en_US\") = %d, expected 0x0409\n", lcid);
3501 }
3502
3503 lengthPre = uloc_getLocaleForLCID(lcid, temp2, 4, &status);
3504 if (status != U_BUFFER_OVERFLOW_ERROR) {
3505 log_err(" unexpected result from uloc_getLocaleForLCID with small buffer: %s\n", u_errorName(status));
3506 }
3507 else {
3508 status = U_ZERO_ERROR;
3509 }
3510
3511 length = uloc_getLocaleForLCID(lcid, temp2, UPRV_LENGTHOF(temp2), &status);
3512 if (U_FAILURE(status)) {
3513 log_err(" unexpected result from uloc_getLocaleForLCID(0x0409): %s\n", u_errorName(status));
3514 status = U_ZERO_ERROR;
3515 }
3516
3517 if (length != lengthPre) {
3518 log_err(" uloc_getLocaleForLCID(0x0409): returned length %d does not match preflight length %d\n", length, lengthPre);
3519 }
3520
3521 length = uloc_getLocaleForLCID(0x12345, temp2, UPRV_LENGTHOF(temp2), &status);
3522 if (U_SUCCESS(status)) {
3523 log_err(" unexpected result from uloc_getLocaleForLCID(0x12345): %s, status %s\n", temp2, u_errorName(status));
3524 }
3525 status = U_ZERO_ERROR;
3526
3527 log_verbose("Testing getLocaleForLCID vs. locale data\n");
3528 for (i = 0; i < LOCALE_SIZE; i++) {
3529
3530 testLocale=rawData2[NAME][i];
3531
3532 log_verbose("Testing %s ......\n", testLocale);
3533
3534 sscanf(rawData2[LCID][i], "%x", &lcid);
3535 length = uloc_getLocaleForLCID(lcid, temp2, UPRV_LENGTHOF(temp2), &status);
3536 if (U_FAILURE(status)) {
3537 log_err(" unexpected failure of uloc_getLocaleForLCID(%#04x), status %s\n", lcid, u_errorName(status));
3538 status = U_ZERO_ERROR;
3539 continue;
3540 }
3541
3542 if (length != (int32_t)uprv_strlen(temp2)) {
3543 log_err(" returned length %d not correct for uloc_getLocaleForLCID(%#04x), expected %d\n", length, lcid, uprv_strlen(temp2));
3544 }
3545
3546 /* Compare language, country, script */
3547 length = uloc_getLanguage(temp2, temp3, UPRV_LENGTHOF(temp3), &status);
3548 if (U_FAILURE(status)) {
3549 log_err(" couldn't get language in uloc_getLocaleForLCID(%#04x) = %s, status %s\n", lcid, temp2, u_errorName(status));
3550 status = U_ZERO_ERROR;
3551 }
3552 else if (uprv_strcmp(temp3, rawData2[LANG][i]) && !(uprv_strcmp(temp3, "nn") == 0 && uprv_strcmp(rawData2[VAR][i], "NY") == 0)) {
3553 log_err(" language doesn't match expected %s in in uloc_getLocaleForLCID(%#04x) = %s\n", rawData2[LANG][i], lcid, temp2);
3554 }
3555
3556 length = uloc_getScript(temp2, temp3, UPRV_LENGTHOF(temp3), &status);
3557 if (U_FAILURE(status)) {
3558 log_err(" couldn't get script in uloc_getLocaleForLCID(%#04x) = %s, status %s\n", lcid, temp2, u_errorName(status));
3559 status = U_ZERO_ERROR;
3560 }
3561 else if (uprv_strcmp(temp3, rawData2[SCRIPT][i])) {
3562 log_err(" script doesn't match expected %s in in uloc_getLocaleForLCID(%#04x) = %s\n", rawData2[SCRIPT][i], lcid, temp2);
3563 }
3564
3565 length = uloc_getCountry(temp2, temp3, UPRV_LENGTHOF(temp3), &status);
3566 if (U_FAILURE(status)) {
3567 log_err(" couldn't get country in uloc_getLocaleForLCID(%#04x) = %s, status %s\n", lcid, temp2, u_errorName(status));
3568 status = U_ZERO_ERROR;
3569 }
3570 else if (uprv_strlen(rawData2[CTRY][i]) && uprv_strcmp(temp3, rawData2[CTRY][i])) {
3571 log_err(" country doesn't match expected %s in in uloc_getLocaleForLCID(%#04x) = %s\n", rawData2[CTRY][i], lcid, temp2);
3572 }
3573 }
3574
3575 }
3576
3577 const char* const basic_maximize_data[][2] = {
3578 {
3579 "zu_Zzzz_Zz",
3580 "zu_Latn_ZA",
3581 }, {
3582 "ZU_Zz",
3583 "zu_Latn_ZA"
3584 }, {
3585 "zu_LATN",
3586 "zu_Latn_ZA"
3587 }, {
3588 "en_Zz",
3589 "en_Latn_US"
3590 }, {
3591 "en_us",
3592 "en_Latn_US"
3593 }, {
3594 "en_Kore",
3595 "en_Kore_US"
3596 }, {
3597 "en_Kore_Zz",
3598 "en_Kore_US"
3599 }, {
3600 "en_Kore_ZA",
3601 "en_Kore_ZA"
3602 }, {
3603 "en_Kore_ZA_POSIX",
3604 "en_Kore_ZA_POSIX"
3605 }, {
3606 "en_Gujr",
3607 "en_Gujr_US"
3608 }, {
3609 "en_ZA",
3610 "en_Latn_ZA"
3611 }, {
3612 "en_Gujr_Zz",
3613 "en_Gujr_US"
3614 }, {
3615 "en_Gujr_ZA",
3616 "en_Gujr_ZA"
3617 }, {
3618 "en_Gujr_ZA_POSIX",
3619 "en_Gujr_ZA_POSIX"
3620 }, {
3621 "en_US_POSIX_1901",
3622 "en_Latn_US_POSIX_1901"
3623 }, {
3624 "en_Latn__POSIX_1901",
3625 "en_Latn_US_POSIX_1901"
3626 }, {
3627 "en__POSIX_1901",
3628 "en_Latn_US_POSIX_1901"
3629 }, {
3630 "de__POSIX_1901",
3631 "de_Latn_DE_POSIX_1901"
3632 }, {
3633 "en_US_BOSTON",
3634 "en_Latn_US_BOSTON"
3635 }, {
3636 "th@calendar=buddhist",
3637 "th_Thai_TH@calendar=buddhist"
3638 }, {
3639 "ar_ZZ",
3640 "ar_Arab_EG"
3641 }, {
3642 "zh",
3643 "zh_Hans_CN"
3644 }, {
3645 "zh_TW",
3646 "zh_Hant_TW"
3647 }, {
3648 "zh_HK",
3649 "zh_Hant_HK"
3650 }, {
3651 "zh_Hant",
3652 "zh_Hant_TW"
3653 }, {
3654 "zh_Zzzz_CN",
3655 "zh_Hans_CN"
3656 }, {
3657 "und_US",
3658 "en_Latn_US"
3659 }, {
3660 "und_HK",
3661 "zh_Hant_HK"
3662 }, {
3663 "zzz",
3664 ""
3665 }, {
3666 "de_u_co_phonebk",
3667 "de_Latn_DE_U_CO_PHONEBK"
3668 }, {
3669 "de_Latn_u_co_phonebk",
3670 "de_Latn_DE_U_CO_PHONEBK"
3671 }, {
3672 "de_Latn_DE_u_co_phonebk",
3673 "de_Latn_DE_U_CO_PHONEBK"
3674 }, {
3675 "_Arab@em=emoji",
3676 "ar_Arab_EG@em=emoji"
3677 }, {
3678 "_Latn@em=emoji",
3679 "en_Latn_US@em=emoji"
3680 }, {
3681 "_Latn_DE@em=emoji",
3682 "de_Latn_DE@em=emoji"
3683 }, {
3684 "_Zzzz_DE@em=emoji",
3685 "de_Latn_DE@em=emoji"
3686 }, {
3687 "_DE@em=emoji",
3688 "de_Latn_DE@em=emoji"
3689 }, { // start Apple tests for <rdar://problem/47494884>
3690 "ur",
3691 "ur_Aran_PK"
3692 }, {
3693 "ks",
3694 "ks_Aran_IN"
3695 }, {
3696 "und_Aran_PK",
3697 "ur_Aran_PK"
3698 }, {
3699 "und_Aran_IN",
3700 "ks_Aran_IN"
3701 }, {
3702 "ur_PK",
3703 "ur_Aran_PK"
3704 }, {
3705 "ks_IN",
3706 "ks_Aran_IN"
3707 }, {
3708 "ur_Arab",
3709 "ur_Arab_PK"
3710 }, {
3711 "ks_Arab",
3712 "ks_Arab_IN"
3713 }, { // start Apple tests for <rdar://problem/54153189>
3714 "mni",
3715 "mni_Beng_IN"
3716 }, {
3717 "mni_Beng",
3718 "mni_Beng_IN"
3719 }, {
3720 "mni_Mtei",
3721 "mni_Mtei_IN"
3722 }, {
3723 "sat",
3724 "sat_Olck_IN"
3725 }, {
3726 "sat_Olck",
3727 "sat_Olck_IN"
3728 }, {
3729 "sat_Deva",
3730 "sat_Deva_IN"
3731 }
3732 };
3733
3734 const char* const basic_minimize_data[][2] = {
3735 {
3736 "en_Latn_US",
3737 "en"
3738 }, {
3739 "en_Latn_US_POSIX_1901",
3740 "en__POSIX_1901"
3741 }, {
3742 "EN_Latn_US_POSIX_1901",
3743 "en__POSIX_1901"
3744 }, {
3745 "en_Zzzz_US_POSIX_1901",
3746 "en__POSIX_1901"
3747 }, {
3748 "de_Latn_DE_POSIX_1901",
3749 "de__POSIX_1901"
3750 }, {
3751 "und",
3752 ""
3753 }, {
3754 "en_Latn_US@calendar=gregorian",
3755 "en@calendar=gregorian"
3756 }
3757 };
3758
3759 const char* const full_data[][3] = {
3760 {
3761 /* "FROM", */
3762 /* "ADD-LIKELY", */
3763 /* "REMOVE-LIKELY" */
3764 /* }, { */
3765 "aa",
3766 "aa_Latn_ET",
3767 "aa"
3768 }, {
3769 "af",
3770 "af_Latn_ZA",
3771 "af"
3772 }, {
3773 "ak",
3774 "ak_Latn_GH",
3775 "ak"
3776 }, {
3777 "am",
3778 "am_Ethi_ET",
3779 "am"
3780 }, {
3781 "ar",
3782 "ar_Arab_EG",
3783 "ar"
3784 }, {
3785 "as",
3786 "as_Beng_IN",
3787 "as"
3788 }, {
3789 "az",
3790 "az_Latn_AZ",
3791 "az"
3792 }, {
3793 "be",
3794 "be_Cyrl_BY",
3795 "be"
3796 }, {
3797 "bg",
3798 "bg_Cyrl_BG",
3799 "bg"
3800 }, {
3801 "bn",
3802 "bn_Beng_BD",
3803 "bn"
3804 }, {
3805 "bo",
3806 "bo_Tibt_CN",
3807 "bo"
3808 }, {
3809 "bs",
3810 "bs_Latn_BA",
3811 "bs"
3812 }, {
3813 "ca",
3814 "ca_Latn_ES",
3815 "ca"
3816 }, {
3817 "ch",
3818 "ch_Latn_GU",
3819 "ch"
3820 }, {
3821 "chk",
3822 "chk_Latn_FM",
3823 "chk"
3824 }, {
3825 "cs",
3826 "cs_Latn_CZ",
3827 "cs"
3828 }, {
3829 "cy",
3830 "cy_Latn_GB",
3831 "cy"
3832 }, {
3833 "da",
3834 "da_Latn_DK",
3835 "da"
3836 }, {
3837 "de",
3838 "de_Latn_DE",
3839 "de"
3840 }, {
3841 "dv",
3842 "dv_Thaa_MV",
3843 "dv"
3844 }, {
3845 "dz",
3846 "dz_Tibt_BT",
3847 "dz"
3848 }, {
3849 "ee",
3850 "ee_Latn_GH",
3851 "ee"
3852 }, {
3853 "el",
3854 "el_Grek_GR",
3855 "el"
3856 }, {
3857 "en",
3858 "en_Latn_US",
3859 "en"
3860 }, {
3861 "es",
3862 "es_Latn_ES",
3863 "es"
3864 }, {
3865 "et",
3866 "et_Latn_EE",
3867 "et"
3868 }, {
3869 "eu",
3870 "eu_Latn_ES",
3871 "eu"
3872 }, {
3873 "fa",
3874 "fa_Arab_IR",
3875 "fa"
3876 }, {
3877 "fi",
3878 "fi_Latn_FI",
3879 "fi"
3880 }, {
3881 "fil",
3882 "fil_Latn_PH",
3883 "fil"
3884 }, {
3885 "fo",
3886 "fo_Latn_FO",
3887 "fo"
3888 }, {
3889 "fr",
3890 "fr_Latn_FR",
3891 "fr"
3892 }, {
3893 "fur",
3894 "fur_Latn_IT",
3895 "fur"
3896 }, {
3897 "ga",
3898 "ga_Latn_IE",
3899 "ga"
3900 }, {
3901 "gaa",
3902 "gaa_Latn_GH",
3903 "gaa"
3904 }, {
3905 "gl",
3906 "gl_Latn_ES",
3907 "gl"
3908 }, {
3909 "gn",
3910 "gn_Latn_PY",
3911 "gn"
3912 }, {
3913 "gu",
3914 "gu_Gujr_IN",
3915 "gu"
3916 }, {
3917 "ha",
3918 "ha_Latn_NG",
3919 "ha"
3920 }, {
3921 "haw",
3922 "haw_Latn_US",
3923 "haw"
3924 }, {
3925 "he",
3926 "he_Hebr_IL",
3927 "he"
3928 }, {
3929 "hi",
3930 "hi_Deva_IN",
3931 "hi"
3932 }, {
3933 "hr",
3934 "hr_Latn_HR",
3935 "hr"
3936 }, {
3937 "ht",
3938 "ht_Latn_HT",
3939 "ht"
3940 }, {
3941 "hu",
3942 "hu_Latn_HU",
3943 "hu"
3944 }, {
3945 "hy",
3946 "hy_Armn_AM",
3947 "hy"
3948 }, {
3949 "id",
3950 "id_Latn_ID",
3951 "id"
3952 }, {
3953 "ig",
3954 "ig_Latn_NG",
3955 "ig"
3956 }, {
3957 "ii",
3958 "ii_Yiii_CN",
3959 "ii"
3960 }, {
3961 "is",
3962 "is_Latn_IS",
3963 "is"
3964 }, {
3965 "it",
3966 "it_Latn_IT",
3967 "it"
3968 }, {
3969 "ja",
3970 "ja_Jpan_JP",
3971 "ja"
3972 }, {
3973 "ka",
3974 "ka_Geor_GE",
3975 "ka"
3976 }, {
3977 "kaj",
3978 "kaj_Latn_NG",
3979 "kaj"
3980 }, {
3981 "kam",
3982 "kam_Latn_KE",
3983 "kam"
3984 }, {
3985 "kk",
3986 "kk_Cyrl_KZ",
3987 "kk"
3988 }, {
3989 "kl",
3990 "kl_Latn_GL",
3991 "kl"
3992 }, {
3993 "km",
3994 "km_Khmr_KH",
3995 "km"
3996 }, {
3997 "kn",
3998 "kn_Knda_IN",
3999 "kn"
4000 }, {
4001 "ko",
4002 "ko_Kore_KR",
4003 "ko"
4004 }, {
4005 "kok",
4006 "kok_Deva_IN",
4007 "kok"
4008 }, {
4009 "kpe",
4010 "kpe_Latn_LR",
4011 "kpe"
4012 }, {
4013 "ku",
4014 "ku_Latn_TR",
4015 "ku"
4016 }, {
4017 "ky",
4018 "ky_Cyrl_KG",
4019 "ky"
4020 }, {
4021 "la",
4022 "la_Latn_VA",
4023 "la"
4024 }, {
4025 "ln",
4026 "ln_Latn_CD",
4027 "ln"
4028 }, {
4029 "lo",
4030 "lo_Laoo_LA",
4031 "lo"
4032 }, {
4033 "lt",
4034 "lt_Latn_LT",
4035 "lt"
4036 }, {
4037 "lv",
4038 "lv_Latn_LV",
4039 "lv"
4040 }, {
4041 "mg",
4042 "mg_Latn_MG",
4043 "mg"
4044 }, {
4045 "mh",
4046 "mh_Latn_MH",
4047 "mh"
4048 }, {
4049 "mk",
4050 "mk_Cyrl_MK",
4051 "mk"
4052 }, {
4053 "ml",
4054 "ml_Mlym_IN",
4055 "ml"
4056 }, {
4057 "mn",
4058 "mn_Cyrl_MN",
4059 "mn"
4060 }, {
4061 "mr",
4062 "mr_Deva_IN",
4063 "mr"
4064 }, {
4065 "ms",
4066 "ms_Latn_MY",
4067 "ms"
4068 }, { // <rdar://problem/27943264>
4069 "ms_ID",
4070 "ms_Latn_ID",
4071 "ms_ID"
4072 }, { // <rdar://problem/27943264>
4073 "ms_Arab",
4074 "ms_Arab_MY",
4075 "ms_Arab"
4076 }, {
4077 "mt",
4078 "mt_Latn_MT",
4079 "mt"
4080 }, {
4081 "my",
4082 "my_Mymr_MM",
4083 "my"
4084 }, {
4085 "na",
4086 "na_Latn_NR",
4087 "na"
4088 }, {
4089 "ne",
4090 "ne_Deva_NP",
4091 "ne"
4092 }, {
4093 "niu",
4094 "niu_Latn_NU",
4095 "niu"
4096 }, {
4097 "nl",
4098 "nl_Latn_NL",
4099 "nl"
4100 }, {
4101 "nn",
4102 "nn_Latn_NO",
4103 "nn"
4104 }, {
4105 "nr",
4106 "nr_Latn_ZA",
4107 "nr"
4108 }, {
4109 "nso",
4110 "nso_Latn_ZA",
4111 "nso"
4112 }, {
4113 "ny",
4114 "ny_Latn_MW",
4115 "ny"
4116 }, {
4117 "om",
4118 "om_Latn_ET",
4119 "om"
4120 }, {
4121 "or",
4122 "or_Orya_IN",
4123 "or"
4124 }, {
4125 "pa",
4126 "pa_Guru_IN",
4127 "pa"
4128 }, {
4129 "pa_Arab",
4130 "pa_Arab_PK",
4131 "pa_Arab"
4132 }, {
4133 "pa_Aran",
4134 "pa_Aran_PK",
4135 "pa_PK"
4136 }, {
4137 "pa_PK",
4138 "pa_Aran_PK", // <rdar://problem/50687287>
4139 "pa_PK"
4140 }, {
4141 "pap",
4142 "pap_Latn_AW",
4143 "pap"
4144 }, {
4145 "pau",
4146 "pau_Latn_PW",
4147 "pau"
4148 }, {
4149 "pl",
4150 "pl_Latn_PL",
4151 "pl"
4152 }, {
4153 "ps",
4154 "ps_Arab_AF",
4155 "ps"
4156 }, {
4157 "pt",
4158 "pt_Latn_BR",
4159 "pt"
4160 }, {
4161 "rn",
4162 "rn_Latn_BI",
4163 "rn"
4164 }, {
4165 "ro",
4166 "ro_Latn_RO",
4167 "ro"
4168 }, {
4169 "ru",
4170 "ru_Cyrl_RU",
4171 "ru"
4172 }, {
4173 "rw",
4174 "rw_Latn_RW",
4175 "rw"
4176 }, {
4177 "sa",
4178 "sa_Deva_IN",
4179 "sa"
4180 }, {
4181 "se",
4182 "se_Latn_NO",
4183 "se"
4184 }, {
4185 "sg",
4186 "sg_Latn_CF",
4187 "sg"
4188 }, {
4189 "si",
4190 "si_Sinh_LK",
4191 "si"
4192 }, {
4193 "sid",
4194 "sid_Latn_ET",
4195 "sid"
4196 }, {
4197 "sk",
4198 "sk_Latn_SK",
4199 "sk"
4200 }, {
4201 "sl",
4202 "sl_Latn_SI",
4203 "sl"
4204 }, {
4205 "sm",
4206 "sm_Latn_WS",
4207 "sm"
4208 }, {
4209 "so",
4210 "so_Latn_SO",
4211 "so"
4212 }, {
4213 "sq",
4214 "sq_Latn_AL",
4215 "sq"
4216 }, {
4217 "sr",
4218 "sr_Cyrl_RS",
4219 "sr"
4220 }, {
4221 "ss",
4222 "ss_Latn_ZA",
4223 "ss"
4224 }, {
4225 "st",
4226 "st_Latn_ZA",
4227 "st"
4228 }, {
4229 "sv",
4230 "sv_Latn_SE",
4231 "sv"
4232 }, {
4233 "sw",
4234 "sw_Latn_TZ",
4235 "sw"
4236 }, {
4237 "ta",
4238 "ta_Taml_IN",
4239 "ta"
4240 }, {
4241 "te",
4242 "te_Telu_IN",
4243 "te"
4244 }, {
4245 "tet",
4246 "tet_Latn_TL",
4247 "tet"
4248 }, {
4249 "tg",
4250 "tg_Cyrl_TJ",
4251 "tg"
4252 }, {
4253 "th",
4254 "th_Thai_TH",
4255 "th"
4256 }, {
4257 "ti",
4258 "ti_Ethi_ET",
4259 "ti"
4260 }, {
4261 "tig",
4262 "tig_Ethi_ER",
4263 "tig"
4264 }, {
4265 "tk",
4266 "tk_Latn_TM",
4267 "tk"
4268 }, {
4269 "tkl",
4270 "tkl_Latn_TK",
4271 "tkl"
4272 }, {
4273 "tn",
4274 "tn_Latn_ZA",
4275 "tn"
4276 }, {
4277 "to",
4278 "to_Latn_TO",
4279 "to"
4280 }, {
4281 "tpi",
4282 "tpi_Latn_PG",
4283 "tpi"
4284 }, {
4285 "tr",
4286 "tr_Latn_TR",
4287 "tr"
4288 }, {
4289 "ts",
4290 "ts_Latn_ZA",
4291 "ts"
4292 }, {
4293 "tt",
4294 "tt_Cyrl_RU",
4295 "tt"
4296 }, {
4297 "tvl",
4298 "tvl_Latn_TV",
4299 "tvl"
4300 }, {
4301 "ty",
4302 "ty_Latn_PF",
4303 "ty"
4304 }, {
4305 "uk",
4306 "uk_Cyrl_UA",
4307 "uk"
4308 }, {
4309 "und",
4310 "en_Latn_US",
4311 "en"
4312 }, {
4313 "und_AD",
4314 "ca_Latn_AD",
4315 "ca_AD"
4316 }, {
4317 "und_AE",
4318 "ar_Arab_AE",
4319 "ar_AE"
4320 }, {
4321 "und_AF",
4322 "fa_Arab_AF",
4323 "fa_AF"
4324 }, {
4325 "und_AL",
4326 "sq_Latn_AL",
4327 "sq"
4328 }, {
4329 "und_AM",
4330 "hy_Armn_AM",
4331 "hy"
4332 }, {
4333 "und_AO",
4334 "pt_Latn_AO",
4335 "pt_AO"
4336 }, {
4337 "und_AR",
4338 "es_Latn_AR",
4339 "es_AR"
4340 }, {
4341 "und_AS",
4342 "sm_Latn_AS",
4343 "sm_AS"
4344 }, {
4345 "und_AT",
4346 "de_Latn_AT",
4347 "de_AT"
4348 }, {
4349 "und_AW",
4350 "nl_Latn_AW",
4351 "nl_AW"
4352 }, {
4353 "und_AX",
4354 "sv_Latn_AX",
4355 "sv_AX"
4356 }, {
4357 "und_AZ",
4358 "az_Latn_AZ",
4359 "az"
4360 }, {
4361 "und_Arab",
4362 "ar_Arab_EG",
4363 "ar"
4364 }, {
4365 "und_Arab_IN",
4366 "ur_Arab_IN",
4367 "ur_Arab_IN" // Apple <rdar://problem/47494884>
4368 }, {
4369 "und_Arab_PK",
4370 "ur_Arab_PK",
4371 "ur_Arab", // Apple <rdar://problem/47494884>
4372 }, {
4373 "und_Arab_SN",
4374 "ar_Arab_SN",
4375 "ar_SN"
4376 }, {
4377 "und_Armn",
4378 "hy_Armn_AM",
4379 "hy"
4380 }, {
4381 "und_BA",
4382 "bs_Latn_BA",
4383 "bs"
4384 }, {
4385 "und_BD",
4386 "bn_Beng_BD",
4387 "bn"
4388 }, {
4389 "und_BE",
4390 "nl_Latn_BE",
4391 "nl_BE"
4392 }, {
4393 "und_BF",
4394 "fr_Latn_BF",
4395 "fr_BF"
4396 }, {
4397 "und_BG",
4398 "bg_Cyrl_BG",
4399 "bg"
4400 }, {
4401 "und_BH",
4402 "ar_Arab_BH",
4403 "ar_BH"
4404 }, {
4405 "und_BI",
4406 "rn_Latn_BI",
4407 "rn"
4408 }, {
4409 "und_BJ",
4410 "fr_Latn_BJ",
4411 "fr_BJ"
4412 }, {
4413 "und_BN",
4414 "ms_Latn_BN",
4415 "ms_BN"
4416 }, {
4417 "und_BO",
4418 "es_Latn_BO",
4419 "es_BO"
4420 }, {
4421 "und_BR",
4422 "pt_Latn_BR",
4423 "pt"
4424 }, {
4425 "und_BT",
4426 "dz_Tibt_BT",
4427 "dz"
4428 }, {
4429 "und_BY",
4430 "be_Cyrl_BY",
4431 "be"
4432 }, {
4433 "und_Beng",
4434 "bn_Beng_BD",
4435 "bn"
4436 }, {
4437 "und_Beng_IN",
4438 "bn_Beng_IN",
4439 "bn_IN"
4440 }, {
4441 "und_CD",
4442 "sw_Latn_CD",
4443 "sw_CD"
4444 }, {
4445 "und_CF",
4446 "fr_Latn_CF",
4447 "fr_CF"
4448 }, {
4449 "und_CG",
4450 "fr_Latn_CG",
4451 "fr_CG"
4452 }, {
4453 "und_CH",
4454 "de_Latn_CH",
4455 "de_CH"
4456 }, {
4457 "und_CI",
4458 "fr_Latn_CI",
4459 "fr_CI"
4460 }, {
4461 "und_CL",
4462 "es_Latn_CL",
4463 "es_CL"
4464 }, {
4465 "und_CM",
4466 "fr_Latn_CM",
4467 "fr_CM"
4468 }, {
4469 "und_CN",
4470 "zh_Hans_CN",
4471 "zh"
4472 }, {
4473 "und_CO",
4474 "es_Latn_CO",
4475 "es_CO"
4476 }, {
4477 "und_CR",
4478 "es_Latn_CR",
4479 "es_CR"
4480 }, {
4481 "und_CU",
4482 "es_Latn_CU",
4483 "es_CU"
4484 }, {
4485 "und_CV",
4486 "pt_Latn_CV",
4487 "pt_CV"
4488 }, {
4489 "und_CY",
4490 "el_Grek_CY",
4491 "el_CY"
4492 }, {
4493 "und_CZ",
4494 "cs_Latn_CZ",
4495 "cs"
4496 }, {
4497 "und_Cher",
4498 "chr_Cher_US",
4499 "chr"
4500 }, {
4501 "und_Cyrl",
4502 "ru_Cyrl_RU",
4503 "ru"
4504 }, {
4505 "und_Cyrl_KZ",
4506 "ru_Cyrl_KZ",
4507 "ru_KZ"
4508 }, {
4509 "und_DE",
4510 "de_Latn_DE",
4511 "de"
4512 }, {
4513 "und_DJ",
4514 "aa_Latn_DJ",
4515 "aa_DJ"
4516 }, {
4517 "und_DK",
4518 "da_Latn_DK",
4519 "da"
4520 }, {
4521 "und_DO",
4522 "es_Latn_DO",
4523 "es_DO"
4524 }, {
4525 "und_DZ",
4526 "ar_Arab_DZ",
4527 "ar_DZ"
4528 }, {
4529 "und_Deva",
4530 "hi_Deva_IN",
4531 "hi"
4532 }, {
4533 "und_EC",
4534 "es_Latn_EC",
4535 "es_EC"
4536 }, {
4537 "und_EE",
4538 "et_Latn_EE",
4539 "et"
4540 }, {
4541 "und_EG",
4542 "ar_Arab_EG",
4543 "ar"
4544 }, {
4545 "und_EH",
4546 "ar_Arab_EH",
4547 "ar_EH"
4548 }, {
4549 "und_ER",
4550 "ti_Ethi_ER",
4551 "ti_ER"
4552 }, {
4553 "und_ES",
4554 "es_Latn_ES",
4555 "es"
4556 }, {
4557 "und_ET",
4558 "am_Ethi_ET",
4559 "am"
4560 }, {
4561 "und_Ethi",
4562 "am_Ethi_ET",
4563 "am"
4564 }, {
4565 "und_Ethi_ER",
4566 "am_Ethi_ER",
4567 "am_ER"
4568 }, {
4569 "und_FI",
4570 "fi_Latn_FI",
4571 "fi"
4572 }, {
4573 "und_FM",
4574 "en_Latn_FM",
4575 "en_FM"
4576 }, {
4577 "und_FO",
4578 "fo_Latn_FO",
4579 "fo"
4580 }, {
4581 "und_FR",
4582 "fr_Latn_FR",
4583 "fr"
4584 }, {
4585 "und_GA",
4586 "fr_Latn_GA",
4587 "fr_GA"
4588 }, {
4589 "und_GE",
4590 "ka_Geor_GE",
4591 "ka"
4592 }, {
4593 "und_GF",
4594 "fr_Latn_GF",
4595 "fr_GF"
4596 }, {
4597 "und_GL",
4598 "kl_Latn_GL",
4599 "kl"
4600 }, {
4601 "und_GN",
4602 "fr_Latn_GN",
4603 "fr_GN"
4604 }, {
4605 "und_GP",
4606 "fr_Latn_GP",
4607 "fr_GP"
4608 }, {
4609 "und_GQ",
4610 "es_Latn_GQ",
4611 "es_GQ"
4612 }, {
4613 "und_GR",
4614 "el_Grek_GR",
4615 "el"
4616 }, {
4617 "und_GT",
4618 "es_Latn_GT",
4619 "es_GT"
4620 }, {
4621 "und_GU",
4622 "en_Latn_GU",
4623 "en_GU"
4624 }, {
4625 "und_GW",
4626 "pt_Latn_GW",
4627 "pt_GW"
4628 }, {
4629 "und_Geor",
4630 "ka_Geor_GE",
4631 "ka"
4632 }, {
4633 "und_Grek",
4634 "el_Grek_GR",
4635 "el"
4636 }, {
4637 "und_Gujr",
4638 "gu_Gujr_IN",
4639 "gu"
4640 }, {
4641 "und_Guru",
4642 "pa_Guru_IN",
4643 "pa"
4644 }, {
4645 "und_HK",
4646 "zh_Hant_HK",
4647 "zh_HK"
4648 }, {
4649 "und_HN",
4650 "es_Latn_HN",
4651 "es_HN"
4652 }, {
4653 "und_HR",
4654 "hr_Latn_HR",
4655 "hr"
4656 }, {
4657 "und_HT",
4658 "ht_Latn_HT",
4659 "ht"
4660 }, {
4661 "und_HU",
4662 "hu_Latn_HU",
4663 "hu"
4664 }, {
4665 "und_Hani",
4666 "zh_Hani_CN",
4667 "zh_Hani"
4668 }, {
4669 "und_Hans",
4670 "zh_Hans_CN",
4671 "zh"
4672 }, {
4673 "und_Hant",
4674 "zh_Hant_TW",
4675 "zh_TW"
4676 }, {
4677 "und_Hebr",
4678 "he_Hebr_IL",
4679 "he"
4680 }, {
4681 "und_IL",
4682 "he_Hebr_IL",
4683 "he"
4684 }, {
4685 "und_IN",
4686 "hi_Deva_IN",
4687 "hi"
4688 }, {
4689 "und_IQ",
4690 "ar_Arab_IQ",
4691 "ar_IQ"
4692 }, {
4693 "und_IR",
4694 "fa_Arab_IR",
4695 "fa"
4696 }, {
4697 "und_IS",
4698 "is_Latn_IS",
4699 "is"
4700 }, {
4701 "und_IT",
4702 "it_Latn_IT",
4703 "it"
4704 }, {
4705 "und_JO",
4706 "ar_Arab_JO",
4707 "ar_JO"
4708 }, {
4709 "und_JP",
4710 "ja_Jpan_JP",
4711 "ja"
4712 }, {
4713 "und_Jpan",
4714 "ja_Jpan_JP",
4715 "ja"
4716 }, {
4717 "und_KG",
4718 "ky_Cyrl_KG",
4719 "ky"
4720 }, {
4721 "und_KH",
4722 "km_Khmr_KH",
4723 "km"
4724 }, {
4725 "und_KM",
4726 "ar_Arab_KM",
4727 "ar_KM"
4728 }, {
4729 "und_KP",
4730 "ko_Kore_KP",
4731 "ko_KP"
4732 }, {
4733 "und_KR",
4734 "ko_Kore_KR",
4735 "ko"
4736 }, {
4737 "und_KW",
4738 "ar_Arab_KW",
4739 "ar_KW"
4740 }, {
4741 "und_KZ",
4742 "ru_Cyrl_KZ",
4743 "ru_KZ"
4744 }, {
4745 "und_Khmr",
4746 "km_Khmr_KH",
4747 "km"
4748 }, {
4749 "und_Knda",
4750 "kn_Knda_IN",
4751 "kn"
4752 }, {
4753 "und_Kore",
4754 "ko_Kore_KR",
4755 "ko"
4756 }, {
4757 "und_LA",
4758 "lo_Laoo_LA",
4759 "lo"
4760 }, {
4761 "und_LB",
4762 "ar_Arab_LB",
4763 "ar_LB"
4764 }, {
4765 "und_LI",
4766 "de_Latn_LI",
4767 "de_LI"
4768 }, {
4769 "und_LK",
4770 "si_Sinh_LK",
4771 "si"
4772 }, {
4773 "und_LS",
4774 "st_Latn_LS",
4775 "st_LS"
4776 }, {
4777 "und_LT",
4778 "lt_Latn_LT",
4779 "lt"
4780 }, {
4781 "und_LU",
4782 "fr_Latn_LU",
4783 "fr_LU"
4784 }, {
4785 "und_LV",
4786 "lv_Latn_LV",
4787 "lv"
4788 }, {
4789 "und_LY",
4790 "ar_Arab_LY",
4791 "ar_LY"
4792 }, {
4793 "und_Laoo",
4794 "lo_Laoo_LA",
4795 "lo"
4796 }, {
4797 "und_Latn_ES",
4798 "es_Latn_ES",
4799 "es"
4800 }, {
4801 "und_Latn_ET",
4802 "en_Latn_ET",
4803 "en_ET"
4804 }, {
4805 "und_Latn_GB",
4806 "en_Latn_GB",
4807 "en_GB"
4808 }, {
4809 "und_Latn_GH",
4810 "ak_Latn_GH",
4811 "ak"
4812 }, {
4813 "und_Latn_ID",
4814 "id_Latn_ID",
4815 "id"
4816 }, {
4817 "und_Latn_IT",
4818 "it_Latn_IT",
4819 "it"
4820 }, {
4821 "und_Latn_NG",
4822 "en_Latn_NG",
4823 "en_NG"
4824 }, {
4825 "und_Latn_TR",
4826 "tr_Latn_TR",
4827 "tr"
4828 }, {
4829 "und_Latn_ZA",
4830 "en_Latn_ZA",
4831 "en_ZA"
4832 }, {
4833 "und_MA",
4834 "ar_Arab_MA",
4835 "ar_MA"
4836 }, {
4837 "und_MC",
4838 "fr_Latn_MC",
4839 "fr_MC"
4840 }, {
4841 "und_MD",
4842 "ro_Latn_MD",
4843 "ro_MD"
4844 }, {
4845 "und_ME",
4846 "sr_Latn_ME",
4847 "sr_ME"
4848 }, {
4849 "und_MG",
4850 "mg_Latn_MG",
4851 "mg"
4852 }, {
4853 "und_MH",
4854 "en_Latn_MH",
4855 "en_MH"
4856 }, {
4857 "und_MK",
4858 "mk_Cyrl_MK",
4859 "mk"
4860 }, {
4861 "und_ML",
4862 "bm_Latn_ML",
4863 "bm"
4864 }, {
4865 "und_MM",
4866 "my_Mymr_MM",
4867 "my"
4868 }, {
4869 "und_MN",
4870 "mn_Cyrl_MN",
4871 "mn"
4872 }, {
4873 "und_MO",
4874 "zh_Hant_MO",
4875 "zh_MO"
4876 }, {
4877 "und_MQ",
4878 "fr_Latn_MQ",
4879 "fr_MQ"
4880 }, {
4881 "und_MR",
4882 "ar_Arab_MR",
4883 "ar_MR"
4884 }, {
4885 "und_MT",
4886 "mt_Latn_MT",
4887 "mt"
4888 }, {
4889 "und_MV",
4890 "dv_Thaa_MV",
4891 "dv"
4892 }, {
4893 "und_MW",
4894 "en_Latn_MW",
4895 "en_MW"
4896 }, {
4897 "und_MX",
4898 "es_Latn_MX",
4899 "es_MX"
4900 }, {
4901 "und_MY",
4902 "ms_Latn_MY",
4903 "ms"
4904 }, {
4905 "und_MZ",
4906 "pt_Latn_MZ",
4907 "pt_MZ"
4908 }, {
4909 "und_Mlym",
4910 "ml_Mlym_IN",
4911 "ml"
4912 }, {
4913 "und_Mymr",
4914 "my_Mymr_MM",
4915 "my"
4916 }, {
4917 "und_NC",
4918 "fr_Latn_NC",
4919 "fr_NC"
4920 }, {
4921 "und_NE",
4922 "ha_Latn_NE",
4923 "ha_NE"
4924 }, {
4925 "und_NG",
4926 "en_Latn_NG",
4927 "en_NG"
4928 }, {
4929 "und_NI",
4930 "es_Latn_NI",
4931 "es_NI"
4932 }, {
4933 "und_NL",
4934 "nl_Latn_NL",
4935 "nl"
4936 }, {
4937 "und_NO",
4938 "nb_Latn_NO",
4939 "nb"
4940 }, {
4941 "und_NP",
4942 "ne_Deva_NP",
4943 "ne"
4944 }, {
4945 "und_NR",
4946 "en_Latn_NR",
4947 "en_NR"
4948 }, {
4949 "und_NU",
4950 "en_Latn_NU",
4951 "en_NU"
4952 }, {
4953 "und_OM",
4954 "ar_Arab_OM",
4955 "ar_OM"
4956 }, {
4957 "und_Orya",
4958 "or_Orya_IN",
4959 "or"
4960 }, {
4961 "und_PA",
4962 "es_Latn_PA",
4963 "es_PA"
4964 }, {
4965 "und_PE",
4966 "es_Latn_PE",
4967 "es_PE"
4968 }, {
4969 "und_PF",
4970 "fr_Latn_PF",
4971 "fr_PF"
4972 }, {
4973 "und_PG",
4974 "tpi_Latn_PG",
4975 "tpi"
4976 }, {
4977 "und_PH",
4978 "fil_Latn_PH",
4979 "fil"
4980 }, {
4981 "und_PL",
4982 "pl_Latn_PL",
4983 "pl"
4984 }, {
4985 "und_PM",
4986 "fr_Latn_PM",
4987 "fr_PM"
4988 }, {
4989 "und_PR",
4990 "es_Latn_PR",
4991 "es_PR"
4992 }, {
4993 "und_PS",
4994 "ar_Arab_PS",
4995 "ar_PS"
4996 }, {
4997 "und_PT",
4998 "pt_Latn_PT",
4999 "pt_PT"
5000 }, {
5001 "und_PW",
5002 "pau_Latn_PW",
5003 "pau"
5004 }, {
5005 "und_PY",
5006 "gn_Latn_PY",
5007 "gn"
5008 }, {
5009 "und_QA",
5010 "ar_Arab_QA",
5011 "ar_QA"
5012 }, {
5013 "und_RE",
5014 "fr_Latn_RE",
5015 "fr_RE"
5016 }, {
5017 "und_RO",
5018 "ro_Latn_RO",
5019 "ro"
5020 }, {
5021 "und_RS",
5022 "sr_Cyrl_RS",
5023 "sr"
5024 }, {
5025 "und_RU",
5026 "ru_Cyrl_RU",
5027 "ru"
5028 }, {
5029 "und_RW",
5030 "rw_Latn_RW",
5031 "rw"
5032 }, {
5033 "und_SA",
5034 "ar_Arab_SA",
5035 "ar_SA"
5036 }, {
5037 "und_SD",
5038 "ar_Arab_SD",
5039 "ar_SD"
5040 }, {
5041 "und_SE",
5042 "sv_Latn_SE",
5043 "sv"
5044 }, {
5045 "und_SG",
5046 "en_Latn_SG",
5047 "en_SG"
5048 }, {
5049 "und_SI",
5050 "sl_Latn_SI",
5051 "sl"
5052 }, {
5053 "und_SJ",
5054 "nb_Latn_SJ",
5055 "nb_SJ"
5056 }, {
5057 "und_SK",
5058 "sk_Latn_SK",
5059 "sk"
5060 }, {
5061 "und_SM",
5062 "it_Latn_SM",
5063 "it_SM"
5064 }, {
5065 "und_SN",
5066 "fr_Latn_SN",
5067 "fr_SN"
5068 }, {
5069 "und_SO",
5070 "so_Latn_SO",
5071 "so"
5072 }, {
5073 "und_SR",
5074 "nl_Latn_SR",
5075 "nl_SR"
5076 }, {
5077 "und_ST",
5078 "pt_Latn_ST",
5079 "pt_ST"
5080 }, {
5081 "und_SV",
5082 "es_Latn_SV",
5083 "es_SV"
5084 }, {
5085 "und_SY",
5086 "ar_Arab_SY",
5087 "ar_SY"
5088 }, {
5089 "und_Sinh",
5090 "si_Sinh_LK",
5091 "si"
5092 }, {
5093 "und_TD",
5094 "fr_Latn_TD",
5095 "fr_TD"
5096 }, {
5097 "und_TG",
5098 "fr_Latn_TG",
5099 "fr_TG"
5100 }, {
5101 "und_TH",
5102 "th_Thai_TH",
5103 "th"
5104 }, {
5105 "und_TJ",
5106 "tg_Cyrl_TJ",
5107 "tg"
5108 }, {
5109 "und_TK",
5110 "tkl_Latn_TK",
5111 "tkl"
5112 }, {
5113 "und_TL",
5114 "pt_Latn_TL",
5115 "pt_TL"
5116 }, {
5117 "und_TM",
5118 "tk_Latn_TM",
5119 "tk"
5120 }, {
5121 "und_TN",
5122 "ar_Arab_TN",
5123 "ar_TN"
5124 }, {
5125 "und_TO",
5126 "to_Latn_TO",
5127 "to"
5128 }, {
5129 "und_TR",
5130 "tr_Latn_TR",
5131 "tr"
5132 }, {
5133 "und_TV",
5134 "tvl_Latn_TV",
5135 "tvl"
5136 }, {
5137 "und_TW",
5138 "zh_Hant_TW",
5139 "zh_TW"
5140 }, {
5141 "und_Taml",
5142 "ta_Taml_IN",
5143 "ta"
5144 }, {
5145 "und_Telu",
5146 "te_Telu_IN",
5147 "te"
5148 }, {
5149 "und_Thaa",
5150 "dv_Thaa_MV",
5151 "dv"
5152 }, {
5153 "und_Thai",
5154 "th_Thai_TH",
5155 "th"
5156 }, {
5157 "und_Tibt",
5158 "bo_Tibt_CN",
5159 "bo"
5160 }, {
5161 "und_UA",
5162 "uk_Cyrl_UA",
5163 "uk"
5164 }, {
5165 "und_UY",
5166 "es_Latn_UY",
5167 "es_UY"
5168 }, {
5169 "und_UZ",
5170 "uz_Latn_UZ",
5171 "uz"
5172 }, {
5173 "und_VA",
5174 "it_Latn_VA",
5175 "it_VA"
5176 }, {
5177 "und_VE",
5178 "es_Latn_VE",
5179 "es_VE"
5180 }, {
5181 "und_VN",
5182 "vi_Latn_VN",
5183 "vi"
5184 }, {
5185 "und_VU",
5186 "bi_Latn_VU",
5187 "bi"
5188 }, {
5189 "und_WF",
5190 "fr_Latn_WF",
5191 "fr_WF"
5192 }, {
5193 "und_WS",
5194 "sm_Latn_WS",
5195 "sm"
5196 }, {
5197 "und_YE",
5198 "ar_Arab_YE",
5199 "ar_YE"
5200 }, {
5201 "und_YT",
5202 "fr_Latn_YT",
5203 "fr_YT"
5204 }, {
5205 "und_Yiii",
5206 "ii_Yiii_CN",
5207 "ii"
5208 }, {
5209 "ur",
5210 "ur_Aran_PK", // Apple <rdar://problem/47494884>
5211 "ur"
5212 }, {
5213 "uz",
5214 "uz_Latn_UZ",
5215 "uz"
5216 }, {
5217 "uz_AF",
5218 "uz_Arab_AF",
5219 "uz_AF"
5220 }, {
5221 "uz_Arab",
5222 "uz_Arab_AF",
5223 "uz_AF"
5224 }, {
5225 "ve",
5226 "ve_Latn_ZA",
5227 "ve"
5228 }, {
5229 "vi",
5230 "vi_Latn_VN",
5231 "vi"
5232 }, {
5233 "wal",
5234 "wal_Ethi_ET",
5235 "wal"
5236 }, {
5237 "wo",
5238 "wo_Latn_SN",
5239 "wo"
5240 }, {
5241 "xh",
5242 "xh_Latn_ZA",
5243 "xh"
5244 }, {
5245 "yo",
5246 "yo_Latn_NG",
5247 "yo"
5248 }, {
5249 "zh",
5250 "zh_Hans_CN",
5251 "zh"
5252 }, {
5253 "zh_HK",
5254 "zh_Hant_HK",
5255 "zh_HK"
5256 }, {
5257 "zh_Hani",
5258 "zh_Hani_CN", /* changed due to cldrbug 6204, may be an error */
5259 "zh_Hani", /* changed due to cldrbug 6204, may be an error */
5260 }, {
5261 "zh_Hant",
5262 "zh_Hant_TW",
5263 "zh_TW"
5264 }, {
5265 "zh_MO",
5266 "zh_Hant_MO",
5267 "zh_MO"
5268 }, {
5269 "zh_TW",
5270 "zh_Hant_TW",
5271 "zh_TW"
5272 }, {
5273 "zu",
5274 "zu_Latn_ZA",
5275 "zu"
5276 }, {
5277 "und",
5278 "en_Latn_US",
5279 "en"
5280 }, {
5281 "und_ZZ",
5282 "en_Latn_US",
5283 "en"
5284 }, {
5285 "und_CN",
5286 "zh_Hans_CN",
5287 "zh"
5288 }, {
5289 "und_TW",
5290 "zh_Hant_TW",
5291 "zh_TW"
5292 }, {
5293 "und_HK",
5294 "zh_Hant_HK",
5295 "zh_HK"
5296 }, {
5297 "und_AQ",
5298 "und_Latn_AQ",
5299 "und_AQ"
5300 }, {
5301 "und_Zzzz",
5302 "en_Latn_US",
5303 "en"
5304 }, {
5305 "und_Zzzz_ZZ",
5306 "en_Latn_US",
5307 "en"
5308 }, {
5309 "und_Zzzz_CN",
5310 "zh_Hans_CN",
5311 "zh"
5312 }, {
5313 "und_Zzzz_TW",
5314 "zh_Hant_TW",
5315 "zh_TW"
5316 }, {
5317 "und_Zzzz_HK",
5318 "zh_Hant_HK",
5319 "zh_HK"
5320 }, {
5321 "und_Zzzz_AQ",
5322 "und_Latn_AQ",
5323 "und_AQ"
5324 }, {
5325 "und_Latn",
5326 "en_Latn_US",
5327 "en"
5328 }, {
5329 "und_Latn_ZZ",
5330 "en_Latn_US",
5331 "en"
5332 }, {
5333 "und_Latn_CN",
5334 "za_Latn_CN",
5335 "za"
5336 }, {
5337 "und_Latn_TW",
5338 "trv_Latn_TW",
5339 "trv"
5340 }, {
5341 "und_Latn_HK",
5342 "zh_Latn_HK",
5343 "zh_Latn_HK"
5344 }, {
5345 "und_Latn_AQ",
5346 "und_Latn_AQ",
5347 "und_AQ"
5348 }, {
5349 "und_Hans",
5350 "zh_Hans_CN",
5351 "zh"
5352 }, {
5353 "und_Hans_ZZ",
5354 "zh_Hans_CN",
5355 "zh"
5356 }, {
5357 "und_Hans_CN",
5358 "zh_Hans_CN",
5359 "zh"
5360 }, {
5361 "und_Hans_TW",
5362 "zh_Hans_TW",
5363 "zh_Hans_TW"
5364 }, {
5365 "und_Hans_HK",
5366 "zh_Hans_HK",
5367 "zh_Hans_HK"
5368 }, {
5369 "und_Hans_AQ",
5370 "zh_Hans_AQ",
5371 "zh_AQ"
5372 }, {
5373 "und_Hant",
5374 "zh_Hant_TW",
5375 "zh_TW"
5376 }, {
5377 "und_Hant_ZZ",
5378 "zh_Hant_TW",
5379 "zh_TW"
5380 }, {
5381 "und_Hant_CN",
5382 "zh_Hant_CN",
5383 "zh_Hant_CN"
5384 }, {
5385 "und_Hant_TW",
5386 "zh_Hant_TW",
5387 "zh_TW"
5388 }, {
5389 "und_Hant_HK",
5390 "zh_Hant_HK",
5391 "zh_HK"
5392 }, {
5393 "und_Hant_AQ",
5394 "zh_Hant_AQ",
5395 "zh_Hant_AQ"
5396 }, {
5397 "und_Moon",
5398 "en_Moon_US",
5399 "en_Moon"
5400 }, {
5401 "und_Moon_ZZ",
5402 "en_Moon_US",
5403 "en_Moon"
5404 }, {
5405 "und_Moon_CN",
5406 "zh_Moon_CN",
5407 "zh_Moon"
5408 }, {
5409 "und_Moon_TW",
5410 "zh_Moon_TW",
5411 "zh_Moon_TW"
5412 }, {
5413 "und_Moon_HK",
5414 "zh_Moon_HK",
5415 "zh_Moon_HK"
5416 }, {
5417 "und_Moon_AQ",
5418 "und_Moon_AQ",
5419 "und_Moon_AQ"
5420 }, {
5421 "es",
5422 "es_Latn_ES",
5423 "es"
5424 }, {
5425 "es_ZZ",
5426 "es_Latn_ES",
5427 "es"
5428 }, {
5429 "es_CN",
5430 "es_Latn_CN",
5431 "es_CN"
5432 }, {
5433 "es_TW",
5434 "es_Latn_TW",
5435 "es_TW"
5436 }, {
5437 "es_HK",
5438 "es_Latn_HK",
5439 "es_HK"
5440 }, {
5441 "es_AQ",
5442 "es_Latn_AQ",
5443 "es_AQ"
5444 }, {
5445 "es_Zzzz",
5446 "es_Latn_ES",
5447 "es"
5448 }, {
5449 "es_Zzzz_ZZ",
5450 "es_Latn_ES",
5451 "es"
5452 }, {
5453 "es_Zzzz_CN",
5454 "es_Latn_CN",
5455 "es_CN"
5456 }, {
5457 "es_Zzzz_TW",
5458 "es_Latn_TW",
5459 "es_TW"
5460 }, {
5461 "es_Zzzz_HK",
5462 "es_Latn_HK",
5463 "es_HK"
5464 }, {
5465 "es_Zzzz_AQ",
5466 "es_Latn_AQ",
5467 "es_AQ"
5468 }, {
5469 "es_Latn",
5470 "es_Latn_ES",
5471 "es"
5472 }, {
5473 "es_Latn_ZZ",
5474 "es_Latn_ES",
5475 "es"
5476 }, {
5477 "es_Latn_CN",
5478 "es_Latn_CN",
5479 "es_CN"
5480 }, {
5481 "es_Latn_TW",
5482 "es_Latn_TW",
5483 "es_TW"
5484 }, {
5485 "es_Latn_HK",
5486 "es_Latn_HK",
5487 "es_HK"
5488 }, {
5489 "es_Latn_AQ",
5490 "es_Latn_AQ",
5491 "es_AQ"
5492 }, {
5493 "es_Hans",
5494 "es_Hans_ES",
5495 "es_Hans"
5496 }, {
5497 "es_Hans_ZZ",
5498 "es_Hans_ES",
5499 "es_Hans"
5500 }, {
5501 "es_Hans_CN",
5502 "es_Hans_CN",
5503 "es_Hans_CN"
5504 }, {
5505 "es_Hans_TW",
5506 "es_Hans_TW",
5507 "es_Hans_TW"
5508 }, {
5509 "es_Hans_HK",
5510 "es_Hans_HK",
5511 "es_Hans_HK"
5512 }, {
5513 "es_Hans_AQ",
5514 "es_Hans_AQ",
5515 "es_Hans_AQ"
5516 }, {
5517 "es_Hant",
5518 "es_Hant_ES",
5519 "es_Hant"
5520 }, {
5521 "es_Hant_ZZ",
5522 "es_Hant_ES",
5523 "es_Hant"
5524 }, {
5525 "es_Hant_CN",
5526 "es_Hant_CN",
5527 "es_Hant_CN"
5528 }, {
5529 "es_Hant_TW",
5530 "es_Hant_TW",
5531 "es_Hant_TW"
5532 }, {
5533 "es_Hant_HK",
5534 "es_Hant_HK",
5535 "es_Hant_HK"
5536 }, {
5537 "es_Hant_AQ",
5538 "es_Hant_AQ",
5539 "es_Hant_AQ"
5540 }, {
5541 "es_Moon",
5542 "es_Moon_ES",
5543 "es_Moon"
5544 }, {
5545 "es_Moon_ZZ",
5546 "es_Moon_ES",
5547 "es_Moon"
5548 }, {
5549 "es_Moon_CN",
5550 "es_Moon_CN",
5551 "es_Moon_CN"
5552 }, {
5553 "es_Moon_TW",
5554 "es_Moon_TW",
5555 "es_Moon_TW"
5556 }, {
5557 "es_Moon_HK",
5558 "es_Moon_HK",
5559 "es_Moon_HK"
5560 }, {
5561 "es_Moon_AQ",
5562 "es_Moon_AQ",
5563 "es_Moon_AQ"
5564 }, {
5565 "zh",
5566 "zh_Hans_CN",
5567 "zh"
5568 }, {
5569 "zh_ZZ",
5570 "zh_Hans_CN",
5571 "zh"
5572 }, {
5573 "zh_CN",
5574 "zh_Hans_CN",
5575 "zh"
5576 }, {
5577 "zh_TW",
5578 "zh_Hant_TW",
5579 "zh_TW"
5580 }, {
5581 "zh_HK",
5582 "zh_Hant_HK",
5583 "zh_HK"
5584 }, {
5585 "zh_AQ",
5586 "zh_Hans_AQ",
5587 "zh_AQ"
5588 }, {
5589 "zh_MY",
5590 "zh_Hans_MY",
5591 "zh_MY"
5592 }, {
5593 "zh_Zzzz",
5594 "zh_Hans_CN",
5595 "zh"
5596 }, {
5597 "zh_Zzzz_ZZ",
5598 "zh_Hans_CN",
5599 "zh"
5600 }, {
5601 "zh_Zzzz_CN",
5602 "zh_Hans_CN",
5603 "zh"
5604 }, {
5605 "zh_Zzzz_TW",
5606 "zh_Hant_TW",
5607 "zh_TW"
5608 }, {
5609 "zh_Zzzz_HK",
5610 "zh_Hant_HK",
5611 "zh_HK"
5612 }, {
5613 "zh_Zzzz_AQ",
5614 "zh_Hans_AQ",
5615 "zh_AQ"
5616 }, {
5617 "zh_Latn",
5618 "zh_Latn_CN",
5619 "zh_Latn"
5620 }, {
5621 "zh_Latn_ZZ",
5622 "zh_Latn_CN",
5623 "zh_Latn"
5624 }, {
5625 "zh_Latn_CN",
5626 "zh_Latn_CN",
5627 "zh_Latn"
5628 }, {
5629 "zh_Latn_TW",
5630 "zh_Latn_TW",
5631 "zh_Latn_TW"
5632 }, {
5633 "zh_Latn_HK",
5634 "zh_Latn_HK",
5635 "zh_Latn_HK"
5636 }, {
5637 "zh_Latn_AQ",
5638 "zh_Latn_AQ",
5639 "zh_Latn_AQ"
5640 }, {
5641 "zh_Hans",
5642 "zh_Hans_CN",
5643 "zh"
5644 }, {
5645 "zh_Hans_ZZ",
5646 "zh_Hans_CN",
5647 "zh"
5648 }, {
5649 "zh_Hans_TW",
5650 "zh_Hans_TW",
5651 "zh_Hans_TW"
5652 }, {
5653 "zh_Hans_HK",
5654 "zh_Hans_HK",
5655 "zh_Hans_HK"
5656 }, {
5657 "zh_Hans_AQ",
5658 "zh_Hans_AQ",
5659 "zh_AQ"
5660 }, {
5661 "zh_Hant",
5662 "zh_Hant_TW",
5663 "zh_TW"
5664 }, {
5665 "zh_Hant_ZZ",
5666 "zh_Hant_TW",
5667 "zh_TW"
5668 }, {
5669 "zh_Hant_CN",
5670 "zh_Hant_CN",
5671 "zh_Hant_CN"
5672 }, {
5673 "zh_Hant_AQ",
5674 "zh_Hant_AQ",
5675 "zh_Hant_AQ"
5676 }, {
5677 "zh_Moon",
5678 "zh_Moon_CN",
5679 "zh_Moon"
5680 }, {
5681 "zh_Moon_ZZ",
5682 "zh_Moon_CN",
5683 "zh_Moon"
5684 }, {
5685 "zh_Moon_CN",
5686 "zh_Moon_CN",
5687 "zh_Moon"
5688 }, {
5689 "zh_Moon_TW",
5690 "zh_Moon_TW",
5691 "zh_Moon_TW"
5692 }, {
5693 "zh_Moon_HK",
5694 "zh_Moon_HK",
5695 "zh_Moon_HK"
5696 }, {
5697 "zh_Moon_AQ",
5698 "zh_Moon_AQ",
5699 "zh_Moon_AQ"
5700 }, {
5701 "art",
5702 "",
5703 ""
5704 }, {
5705 "art_ZZ",
5706 "",
5707 ""
5708 }, {
5709 "art_CN",
5710 "",
5711 ""
5712 }, {
5713 "art_TW",
5714 "",
5715 ""
5716 }, {
5717 "art_HK",
5718 "",
5719 ""
5720 }, {
5721 "art_AQ",
5722 "",
5723 ""
5724 }, {
5725 "art_Zzzz",
5726 "",
5727 ""
5728 }, {
5729 "art_Zzzz_ZZ",
5730 "",
5731 ""
5732 }, {
5733 "art_Zzzz_CN",
5734 "",
5735 ""
5736 }, {
5737 "art_Zzzz_TW",
5738 "",
5739 ""
5740 }, {
5741 "art_Zzzz_HK",
5742 "",
5743 ""
5744 }, {
5745 "art_Zzzz_AQ",
5746 "",
5747 ""
5748 }, {
5749 "art_Latn",
5750 "",
5751 ""
5752 }, {
5753 "art_Latn_ZZ",
5754 "",
5755 ""
5756 }, {
5757 "art_Latn_CN",
5758 "",
5759 ""
5760 }, {
5761 "art_Latn_TW",
5762 "",
5763 ""
5764 }, {
5765 "art_Latn_HK",
5766 "",
5767 ""
5768 }, {
5769 "art_Latn_AQ",
5770 "",
5771 ""
5772 }, {
5773 "art_Hans",
5774 "",
5775 ""
5776 }, {
5777 "art_Hans_ZZ",
5778 "",
5779 ""
5780 }, {
5781 "art_Hans_CN",
5782 "",
5783 ""
5784 }, {
5785 "art_Hans_TW",
5786 "",
5787 ""
5788 }, {
5789 "art_Hans_HK",
5790 "",
5791 ""
5792 }, {
5793 "art_Hans_AQ",
5794 "",
5795 ""
5796 }, {
5797 "art_Hant",
5798 "",
5799 ""
5800 }, {
5801 "art_Hant_ZZ",
5802 "",
5803 ""
5804 }, {
5805 "art_Hant_CN",
5806 "",
5807 ""
5808 }, {
5809 "art_Hant_TW",
5810 "",
5811 ""
5812 }, {
5813 "art_Hant_HK",
5814 "",
5815 ""
5816 }, {
5817 "art_Hant_AQ",
5818 "",
5819 ""
5820 }, {
5821 "art_Moon",
5822 "",
5823 ""
5824 }, {
5825 "art_Moon_ZZ",
5826 "",
5827 ""
5828 }, {
5829 "art_Moon_CN",
5830 "",
5831 ""
5832 }, {
5833 "art_Moon_TW",
5834 "",
5835 ""
5836 }, {
5837 "art_Moon_HK",
5838 "",
5839 ""
5840 }, {
5841 "art_Moon_AQ",
5842 "",
5843 ""
5844 }, {
5845 "de@collation=phonebook",
5846 "de_Latn_DE@collation=phonebook",
5847 "de@collation=phonebook"
5848 }
5849 };
5850
5851 typedef struct errorDataTag {
5852 const char* tag;
5853 const char* expected;
5854 UErrorCode uerror;
5855 int32_t bufferSize;
5856 } errorData;
5857
5858 const errorData maximizeErrors[] = {
5859 {
5860 "enfueiujhytdf",
5861 NULL,
5862 U_ILLEGAL_ARGUMENT_ERROR,
5863 -1
5864 },
5865 {
5866 "en_THUJIOGIURJHGJFURYHFJGURYYYHHGJURHG",
5867 NULL,
5868 U_ILLEGAL_ARGUMENT_ERROR,
5869 -1
5870 },
5871 {
5872 "en_THUJIOGIURJHGJFURYHFJGURYYYHHGJURHG",
5873 NULL,
5874 U_ILLEGAL_ARGUMENT_ERROR,
5875 -1
5876 },
5877 {
5878 "en_Latn_US_POSIX@currency=EURO",
5879 "en_Latn_US_POSIX@currency=EURO",
5880 U_BUFFER_OVERFLOW_ERROR,
5881 29
5882 },
5883 {
5884 "en_Latn_US_POSIX@currency=EURO",
5885 "en_Latn_US_POSIX@currency=EURO",
5886 U_STRING_NOT_TERMINATED_WARNING,
5887 30
5888 }
5889 };
5890
5891 const errorData minimizeErrors[] = {
5892 {
5893 "enfueiujhytdf",
5894 NULL,
5895 U_ILLEGAL_ARGUMENT_ERROR,
5896 -1
5897 },
5898 {
5899 "en_THUJIOGIURJHGJFURYHFJGURYYYHHGJURHG",
5900 NULL,
5901 U_ILLEGAL_ARGUMENT_ERROR,
5902 -1
5903 },
5904 {
5905 "en_Latn_US_POSIX@currency=EURO",
5906 "en__POSIX@currency=EURO",
5907 U_BUFFER_OVERFLOW_ERROR,
5908 22
5909 },
5910 {
5911 "en_Latn_US_POSIX@currency=EURO",
5912 "en__POSIX@currency=EURO",
5913 U_STRING_NOT_TERMINATED_WARNING,
5914 23
5915 }
5916 };
5917
5918 static int32_t getExpectedReturnValue(const errorData* data)
5919 {
5920 if (data->uerror == U_BUFFER_OVERFLOW_ERROR ||
5921 data->uerror == U_STRING_NOT_TERMINATED_WARNING)
5922 {
5923 return (int32_t)strlen(data->expected);
5924 }
5925 else
5926 {
5927 return -1;
5928 }
5929 }
5930
5931 static int32_t getBufferSize(const errorData* data, int32_t actualSize)
5932 {
5933 if (data->expected == NULL)
5934 {
5935 return actualSize;
5936 }
5937 else if (data->bufferSize < 0)
5938 {
5939 return (int32_t)strlen(data->expected) + 1;
5940 }
5941 else
5942 {
5943 return data->bufferSize;
5944 }
5945 }
5946
5947 static void TestLikelySubtags()
5948 {
5949 char buffer[ULOC_FULLNAME_CAPACITY + ULOC_KEYWORD_AND_VALUES_CAPACITY + 1];
5950 int32_t i = 0;
5951
5952 for (; i < UPRV_LENGTHOF(basic_maximize_data); ++i)
5953 {
5954 UErrorCode status = U_ZERO_ERROR;
5955 const char* const minimal = basic_maximize_data[i][0];
5956 const char* const maximal = basic_maximize_data[i][1];
5957
5958 /* const int32_t length = */
5959 uloc_addLikelySubtags(
5960 minimal,
5961 buffer,
5962 sizeof(buffer),
5963 &status);
5964 if (U_FAILURE(status)) {
5965 log_err_status(status, " unexpected failure of uloc_addLikelySubtags(), minimal \"%s\" status %s\n", minimal, u_errorName(status));
5966 status = U_ZERO_ERROR;
5967 }
5968 else if (uprv_strlen(maximal) == 0) {
5969 if (uprv_stricmp(minimal, buffer) != 0) {
5970 log_err(" unexpected maximal value \"%s\" in uloc_addLikelySubtags(), minimal \"%s\" = \"%s\"\n", maximal, minimal, buffer);
5971 }
5972 }
5973 else if (uprv_stricmp(maximal, buffer) != 0) {
5974 log_err(" maximal doesn't match expected %s in uloc_addLikelySubtags(), minimal \"%s\" = %s\n", maximal, minimal, buffer);
5975 }
5976 }
5977
5978 for (i = 0; i < UPRV_LENGTHOF(basic_minimize_data); ++i) {
5979
5980 UErrorCode status = U_ZERO_ERROR;
5981 const char* const maximal = basic_minimize_data[i][0];
5982 const char* const minimal = basic_minimize_data[i][1];
5983
5984 /* const int32_t length = */
5985 uloc_minimizeSubtags(
5986 maximal,
5987 buffer,
5988 sizeof(buffer),
5989 &status);
5990
5991 if (U_FAILURE(status)) {
5992 log_err_status(status, " unexpected failure of uloc_MinimizeSubtags(), maximal \"%s\" status %s\n", maximal, u_errorName(status));
5993 status = U_ZERO_ERROR;
5994 }
5995 else if (uprv_strlen(minimal) == 0) {
5996 if (uprv_stricmp(maximal, buffer) != 0) {
5997 log_err(" unexpected minimal value \"%s\" in uloc_minimizeSubtags(), maximal \"%s\" = \"%s\"\n", minimal, maximal, buffer);
5998 }
5999 }
6000 else if (uprv_stricmp(minimal, buffer) != 0) {
6001 log_err(" minimal doesn't match expected %s in uloc_MinimizeSubtags(), maximal \"%s\" = %s\n", minimal, maximal, buffer);
6002 }
6003 }
6004
6005 for (i = 0; i < UPRV_LENGTHOF(full_data); ++i) {
6006
6007 UErrorCode status = U_ZERO_ERROR;
6008 const char* const minimal = full_data[i][0];
6009 const char* const maximal = full_data[i][1];
6010
6011 /* const int32_t length = */
6012 uloc_addLikelySubtags(
6013 minimal,
6014 buffer,
6015 sizeof(buffer),
6016 &status);
6017 if (U_FAILURE(status)) {
6018 log_err_status(status, " unexpected failure of uloc_addLikelySubtags(), minimal \"%s\" status \"%s\"\n", minimal, u_errorName(status));
6019 status = U_ZERO_ERROR;
6020 }
6021 else if (uprv_strlen(maximal) == 0) {
6022 if (uprv_stricmp(minimal, buffer) != 0) {
6023 log_err(" unexpected maximal value \"%s\" in uloc_addLikelySubtags(), minimal \"%s\" = \"%s\"\n", maximal, minimal, buffer);
6024 }
6025 }
6026 else if (uprv_stricmp(maximal, buffer) != 0) {
6027 log_err(" maximal doesn't match expected \"%s\" in uloc_addLikelySubtags(), minimal \"%s\" = \"%s\"\n", maximal, minimal, buffer);
6028 }
6029 }
6030
6031 for (i = 0; i < UPRV_LENGTHOF(full_data); ++i) {
6032
6033 UErrorCode status = U_ZERO_ERROR;
6034 const char* const maximal = full_data[i][1];
6035 const char* const minimal = full_data[i][2];
6036
6037 if (strlen(maximal) > 0) {
6038
6039 /* const int32_t length = */
6040 uloc_minimizeSubtags(
6041 maximal,
6042 buffer,
6043 sizeof(buffer),
6044 &status);
6045
6046 if (U_FAILURE(status)) {
6047 log_err_status(status, " unexpected failure of uloc_minimizeSubtags(), maximal \"%s\" status %s\n", maximal, u_errorName(status));
6048 status = U_ZERO_ERROR;
6049 }
6050 else if (uprv_strlen(minimal) == 0) {
6051 if (uprv_stricmp(maximal, buffer) != 0) {
6052 log_err(" unexpected minimal value \"%s\" in uloc_minimizeSubtags(), maximal \"%s\" = \"%s\"\n", minimal, maximal, buffer);
6053 }
6054 }
6055 else if (uprv_stricmp(minimal, buffer) != 0) {
6056 log_err(" minimal doesn't match expected %s in uloc_MinimizeSubtags(), maximal \"%s\" = %s\n", minimal, maximal, buffer);
6057 }
6058 }
6059 }
6060
6061 for (i = 0; i < UPRV_LENGTHOF(maximizeErrors); ++i) {
6062
6063 UErrorCode status = U_ZERO_ERROR;
6064 const char* const minimal = maximizeErrors[i].tag;
6065 const char* const maximal = maximizeErrors[i].expected;
6066 const UErrorCode expectedStatus = maximizeErrors[i].uerror;
6067 const int32_t expectedLength = getExpectedReturnValue(&maximizeErrors[i]);
6068 const int32_t bufferSize = getBufferSize(&maximizeErrors[i], sizeof(buffer));
6069
6070 const int32_t length =
6071 uloc_addLikelySubtags(
6072 minimal,
6073 buffer,
6074 bufferSize,
6075 &status);
6076
6077 if (status == U_ZERO_ERROR) {
6078 log_err(" unexpected U_ZERO_ERROR for uloc_addLikelySubtags(), minimal \"%s\" expected status %s\n", minimal, u_errorName(expectedStatus));
6079 status = U_ZERO_ERROR;
6080 }
6081 else if (status != expectedStatus) {
6082 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));
6083 }
6084 else if (length != expectedLength) {
6085 log_err(" unexpected length for uloc_addLikelySubtags(), minimal \"%s\" expected length %d, but got %d\n", minimal, expectedLength, length);
6086 }
6087 else if (status == U_BUFFER_OVERFLOW_ERROR || status == U_STRING_NOT_TERMINATED_WARNING) {
6088 if (uprv_strnicmp(maximal, buffer, bufferSize) != 0) {
6089 log_err(" maximal doesn't match expected %s in uloc_addLikelySubtags(), minimal \"%s\" = %*s\n",
6090 maximal, minimal, (int)sizeof(buffer), buffer);
6091 }
6092 }
6093 }
6094
6095 for (i = 0; i < UPRV_LENGTHOF(minimizeErrors); ++i) {
6096
6097 UErrorCode status = U_ZERO_ERROR;
6098 const char* const maximal = minimizeErrors[i].tag;
6099 const char* const minimal = minimizeErrors[i].expected;
6100 const UErrorCode expectedStatus = minimizeErrors[i].uerror;
6101 const int32_t expectedLength = getExpectedReturnValue(&minimizeErrors[i]);
6102 const int32_t bufferSize = getBufferSize(&minimizeErrors[i], sizeof(buffer));
6103
6104 const int32_t length =
6105 uloc_minimizeSubtags(
6106 maximal,
6107 buffer,
6108 bufferSize,
6109 &status);
6110
6111 if (status == U_ZERO_ERROR) {
6112 log_err(" unexpected U_ZERO_ERROR for uloc_minimizeSubtags(), maximal \"%s\" expected status %s\n", maximal, u_errorName(expectedStatus));
6113 status = U_ZERO_ERROR;
6114 }
6115 else if (status != expectedStatus) {
6116 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));
6117 }
6118 else if (length != expectedLength) {
6119 log_err(" unexpected length for uloc_minimizeSubtags(), maximal \"%s\" expected length %d, but got %d\n", maximal, expectedLength, length);
6120 }
6121 else if (status == U_BUFFER_OVERFLOW_ERROR || status == U_STRING_NOT_TERMINATED_WARNING) {
6122 if (uprv_strnicmp(minimal, buffer, bufferSize) != 0) {
6123 log_err(" minimal doesn't match expected \"%s\" in uloc_minimizeSubtags(), minimal \"%s\" = \"%*s\"\n",
6124 minimal, maximal, (int)sizeof(buffer), buffer);
6125 }
6126 }
6127 }
6128 }
6129
6130 const char* const locale_to_langtag[][3] = {
6131 {"", "und", "und"},
6132 {"en", "en", "en"},
6133 {"en_US", "en-US", "en-US"},
6134 {"iw_IL", "he-IL", "he-IL"},
6135 {"sr_Latn_SR", "sr-Latn-SR", "sr-Latn-SR"},
6136 {"en__POSIX", "en-u-va-posix", "en-u-va-posix"},
6137 {"en_POSIX", "en-u-va-posix", "en-u-va-posix"},
6138 {"en_US_POSIX_VAR", "en-US-posix-x-lvariant-var", NULL}, /* variant POSIX_VAR is processed as regular variant */
6139 {"en_US_VAR_POSIX", "en-US-x-lvariant-var-posix", NULL}, /* variant VAR_POSIX is processed as regular variant */
6140 {"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 */
6141 {"en_US_POSIX@ca=japanese", "en-US-u-ca-japanese-va-posix", "en-US-u-ca-japanese-va-posix"},
6142 {"und_555", "und-555", "und-555"},
6143 {"123", "und", NULL},
6144 {"%$#&", "und", NULL},
6145 {"_Latn", "und-Latn", "und-Latn"},
6146 {"_DE", "und-DE", "und-DE"},
6147 {"und_FR", "und-FR", "und-FR"},
6148 {"th_TH_TH", "th-TH-x-lvariant-th", NULL},
6149 {"bogus", "bogus", "bogus"},
6150 {"foooobarrr", "und", NULL},
6151 {"aa_BB_CYRL", "aa-BB-x-lvariant-cyrl", NULL},
6152 {"en_US_1234", "en-US-1234", "en-US-1234"},
6153 {"en_US_VARIANTA_VARIANTB", "en-US-varianta-variantb", "en-US-varianta-variantb"},
6154 {"ja__9876_5432", "ja-9876-5432", "ja-9876-5432"},
6155 {"zh_Hant__VAR", "zh-Hant-x-lvariant-var", NULL},
6156 {"es__BADVARIANT_GOODVAR", "es-goodvar", NULL},
6157 {"en@calendar=gregorian", "en-u-ca-gregory", "en-u-ca-gregory"},
6158 {"de@collation=phonebook;calendar=gregorian", "de-u-ca-gregory-co-phonebk", "de-u-ca-gregory-co-phonebk"},
6159 {"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"},
6160 {"en@timezone=America/New_York;calendar=japanese", "en-u-ca-japanese-tz-usnyc", "en-u-ca-japanese-tz-usnyc"},
6161 {"en@timezone=US/Eastern", "en-u-tz-usnyc", "en-u-tz-usnyc"},
6162 {"en@x=x-y-z;a=a-b-c", "en-x-x-y-z", NULL},
6163 {"it@collation=badcollationtype;colStrength=identical;cu=usd-eur", "it-u-cu-usd-eur-ks-identic", NULL},
6164 {"en_US_POSIX", "en-US-u-va-posix", "en-US-u-va-posix"},
6165 {"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"},
6166 {"@x=elmer", "x-elmer", "x-elmer"},
6167 {"en@x=elmer", "en-x-elmer", "en-x-elmer"},
6168 {"@x=elmer;a=exta", "und-a-exta-x-elmer", "und-a-exta-x-elmer"},
6169 {"en_US@attribute=attr1-attr2;calendar=gregorian", "en-US-u-attr1-attr2-ca-gregory", "en-US-u-attr1-attr2-ca-gregory"},
6170 /* #12671 */
6171 {"en@a=bar;attribute=baz", "en-a-bar-u-baz", "en-a-bar-u-baz"},
6172 {"en@a=bar;attribute=baz;x=u-foo", "en-a-bar-u-baz-x-u-foo", "en-a-bar-u-baz-x-u-foo"},
6173 {"en@attribute=baz", "en-u-baz", "en-u-baz"},
6174 {"en@attribute=baz;calendar=islamic-civil", "en-u-baz-ca-islamic-civil", "en-u-baz-ca-islamic-civil"},
6175 {"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"},
6176 {"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"},
6177 {"en@9=efg;a=baz", "en-9-efg-a-baz", "en-9-efg-a-baz"},
6178
6179 // Before ICU 64, ICU locale canonicalization had some additional mappings.
6180 // They were removed for ICU-20187 "drop support for long-obsolete locale ID variants".
6181 // The following now uses standard canonicalization.
6182 {"az_AZ_CYRL", "az-AZ-x-lvariant-cyrl", NULL},
6183
6184 {NULL, NULL, NULL}
6185 };
6186
6187 static void TestToLanguageTag(void) {
6188 char langtag[256];
6189 int32_t i;
6190 UErrorCode status;
6191 int32_t len;
6192 const char *inloc;
6193 const char *expected;
6194
6195 for (i = 0; locale_to_langtag[i][0] != NULL; i++) {
6196 inloc = locale_to_langtag[i][0];
6197
6198 /* testing non-strict mode */
6199 status = U_ZERO_ERROR;
6200 langtag[0] = 0;
6201 expected = locale_to_langtag[i][1];
6202
6203 len = uloc_toLanguageTag(inloc, langtag, sizeof(langtag), FALSE, &status);
6204 (void)len; /* Suppress set but not used warning. */
6205 if (U_FAILURE(status)) {
6206 if (expected != NULL) {
6207 log_err("Error returned by uloc_toLanguageTag for locale id [%s] - error: %s\n",
6208 inloc, u_errorName(status));
6209 }
6210 } else {
6211 if (expected == NULL) {
6212 log_err("Error should be returned by uloc_toLanguageTag for locale id [%s], but [%s] is returned without errors\n",
6213 inloc, langtag);
6214 } else if (uprv_strcmp(langtag, expected) != 0) {
6215 log_data_err("uloc_toLanguageTag returned language tag [%s] for input locale [%s] - expected: [%s]. Are you missing data?\n",
6216 langtag, inloc, expected);
6217 }
6218 }
6219
6220 /* testing strict mode */
6221 status = U_ZERO_ERROR;
6222 langtag[0] = 0;
6223 expected = locale_to_langtag[i][2];
6224
6225 len = uloc_toLanguageTag(inloc, langtag, sizeof(langtag), TRUE, &status);
6226 if (U_FAILURE(status)) {
6227 if (expected != NULL) {
6228 log_data_err("Error returned by uloc_toLanguageTag {strict} for locale id [%s] - error: %s Are you missing data?\n",
6229 inloc, u_errorName(status));
6230 }
6231 } else {
6232 if (expected == NULL) {
6233 log_err("Error should be returned by uloc_toLanguageTag {strict} for locale id [%s], but [%s] is returned without errors\n",
6234 inloc, langtag);
6235 } else if (uprv_strcmp(langtag, expected) != 0) {
6236 log_err("uloc_toLanguageTag {strict} returned language tag [%s] for input locale [%s] - expected: [%s]\n",
6237 langtag, inloc, expected);
6238 }
6239 }
6240 }
6241 }
6242
6243 static void TestBug20132(void) {
6244 char langtag[256];
6245 UErrorCode status;
6246 int32_t len;
6247
6248 static const char inloc[] = "en-C";
6249 static const char expected[] = "en-x-lvariant-c";
6250 const int32_t expected_len = (int32_t)uprv_strlen(expected);
6251
6252 /* Before ICU-20132 was fixed, calling uloc_toLanguageTag() with a too small
6253 * buffer would not immediately return the buffer size actually needed, but
6254 * instead require several iterations before getting the correct size. */
6255
6256 status = U_ZERO_ERROR;
6257 len = uloc_toLanguageTag(inloc, langtag, 1, FALSE, &status);
6258
6259 if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) {
6260 log_data_err("Error returned by uloc_toLanguageTag for locale id [%s] - error: %s Are you missing data?\n",
6261 inloc, u_errorName(status));
6262 }
6263
6264 if (len != expected_len) {
6265 log_err("Bad length returned by uloc_toLanguageTag for locale id [%s]: %i != %i\n", inloc, len, expected_len);
6266 }
6267
6268 status = U_ZERO_ERROR;
6269 len = uloc_toLanguageTag(inloc, langtag, expected_len, FALSE, &status);
6270
6271 if (U_FAILURE(status)) {
6272 log_data_err("Error returned by uloc_toLanguageTag for locale id [%s] - error: %s Are you missing data?\n",
6273 inloc, u_errorName(status));
6274 }
6275
6276 if (len != expected_len) {
6277 log_err("Bad length returned by uloc_toLanguageTag for locale id [%s]: %i != %i\n", inloc, len, expected_len);
6278 } else if (uprv_strncmp(langtag, expected, expected_len) != 0) {
6279 log_data_err("uloc_toLanguageTag returned language tag [%.*s] for input locale [%s] - expected: [%s]. Are you missing data?\n",
6280 len, langtag, inloc, expected);
6281 }
6282 }
6283
6284 #define FULL_LENGTH -1
6285 static const struct {
6286 const char *bcpID;
6287 const char *locID;
6288 int32_t len;
6289 } langtag_to_locale[] = {
6290 {"en", "en", FULL_LENGTH},
6291 {"en-us", "en_US", FULL_LENGTH},
6292 {"und-US", "_US", FULL_LENGTH},
6293 {"und-latn", "_Latn", FULL_LENGTH},
6294 {"en-US-posix", "en_US_POSIX", FULL_LENGTH},
6295 {"de-de_euro", "de", 2},
6296 {"kok-IN", "kok_IN", FULL_LENGTH},
6297 {"123", "", 0},
6298 {"en_us", "", 0},
6299 {"en-latn-x", "en_Latn", 7},
6300 {"art-lojban", "jbo", FULL_LENGTH},
6301 {"zh-hakka", "hak", FULL_LENGTH},
6302 {"zh-cmn-CH", "cmn_CH", FULL_LENGTH},
6303 {"zh-cmn-CH-u-co-pinyin", "cmn_CH@collation=pinyin", FULL_LENGTH},
6304 {"xxx-yy", "xxx_YY", FULL_LENGTH},
6305 {"fr-234", "fr_234", FULL_LENGTH},
6306 {"i-default", "en@x=i-default", FULL_LENGTH},
6307 {"i-test", "", 0},
6308 {"ja-jp-jp", "ja_JP", 5},
6309 {"bogus", "bogus", FULL_LENGTH},
6310 {"boguslang", "", 0},
6311 {"EN-lATN-us", "en_Latn_US", FULL_LENGTH},
6312 {"und-variant-1234", "__VARIANT_1234", FULL_LENGTH},
6313 {"und-varzero-var1-vartwo", "__VARZERO", 11},
6314 {"en-u-ca-gregory", "en@calendar=gregorian", FULL_LENGTH},
6315 {"en-U-cu-USD", "en@currency=usd", FULL_LENGTH},
6316 {"en-US-u-va-posix", "en_US_POSIX", FULL_LENGTH},
6317 {"en-us-u-ca-gregory-va-posix", "en_US_POSIX@calendar=gregorian", FULL_LENGTH},
6318 {"en-us-posix-u-va-posix", "en_US_POSIX@va=posix", FULL_LENGTH},
6319 {"en-us-u-va-posix2", "en_US@va=posix2", FULL_LENGTH},
6320 {"en-us-vari1-u-va-posix", "en_US_VARI1@va=posix", FULL_LENGTH},
6321 {"ar-x-1-2-3", "ar@x=1-2-3", FULL_LENGTH},
6322 {"fr-u-nu-latn-cu-eur", "fr@currency=eur;numbers=latn", FULL_LENGTH},
6323 {"de-k-kext-u-co-phonebk-nu-latn", "de@collation=phonebook;k=kext;numbers=latn", FULL_LENGTH},
6324 {"ja-u-cu-jpy-ca-jp", "ja@calendar=yes;currency=jpy;jp=yes", FULL_LENGTH},
6325 {"en-us-u-tz-usnyc", "en_US@timezone=America/New_York", FULL_LENGTH},
6326 {"und-a-abc-def", "und@a=abc-def", FULL_LENGTH},
6327 {"zh-u-ca-chinese-x-u-ca-chinese", "zh@calendar=chinese;x=u-ca-chinese", FULL_LENGTH},
6328 {"x-elmer", "@x=elmer", FULL_LENGTH},
6329 {"en-US-u-attr1-attr2-ca-gregory", "en_US@attribute=attr1-attr2;calendar=gregorian", FULL_LENGTH},
6330 {"sr-u-kn", "sr@colnumeric=yes", FULL_LENGTH},
6331 {"de-u-kn-co-phonebk", "de@collation=phonebook;colnumeric=yes", FULL_LENGTH},
6332 {"en-u-attr2-attr1-kn-kb", "en@attribute=attr1-attr2;colbackwards=yes;colnumeric=yes", FULL_LENGTH},
6333 {"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},
6334 {"de-u-xc-xphonebk-co-phonebk-ca-buddhist-mo-very-lo-extensi-xd-that-de-should-vc-probably-xz-killthebuffer",
6335 "de@calendar=buddhist;collation=phonebook;de=should;lo=extensi;mo=very;vc=probably;xc=xphonebk;xd=that;xz=yes", 91},
6336 {"de-1901-1901", "de__1901", 7},
6337 {"de-DE-1901-1901", "de_DE_1901", 10},
6338 {"en-a-bbb-a-ccc", "en@a=bbb", 8},
6339 /* #12761 */
6340 {"en-a-bar-u-baz", "en@a=bar;attribute=baz", FULL_LENGTH},
6341 {"en-a-bar-u-baz-x-u-foo", "en@a=bar;attribute=baz;x=u-foo", FULL_LENGTH},
6342 {"en-u-baz", "en@attribute=baz", FULL_LENGTH},
6343 {"en-u-baz-ca-islamic-civil", "en@attribute=baz;calendar=islamic-civil", FULL_LENGTH},
6344 {"en-a-bar-u-ca-islamic-civil-x-u-foo", "en@a=bar;calendar=islamic-civil;x=u-foo", FULL_LENGTH},
6345 {"en-a-bar-u-baz-ca-islamic-civil-x-u-foo", "en@a=bar;attribute=baz;calendar=islamic-civil;x=u-foo", FULL_LENGTH},
6346 {"und-Arab-u-em-emoji", "_Arab@em=emoji", FULL_LENGTH},
6347 {"und-Latn-u-em-emoji", "_Latn@em=emoji", FULL_LENGTH},
6348 {"und-Latn-DE-u-em-emoji", "_Latn_DE@em=emoji", FULL_LENGTH},
6349 {"und-Zzzz-DE-u-em-emoji", "_Zzzz_DE@em=emoji", FULL_LENGTH},
6350 {"und-DE-u-em-emoji", "_DE@em=emoji", FULL_LENGTH},
6351 // #20098
6352 {"hant-cmn-cn", "hant", 4},
6353 {"zh-cmn-TW", "cmn_TW", FULL_LENGTH},
6354 {"zh-x_t-ab", "zh", 2},
6355 {"zh-hans-cn-u-ca-x_t-u", "zh_Hans_CN@calendar=yes", 15},
6356 /* #20140 dupe keys in U-extension */
6357 {"zh-u-ca-chinese-ca-gregory", "zh@calendar=chinese", FULL_LENGTH},
6358 {"zh-u-ca-gregory-co-pinyin-ca-chinese", "zh@calendar=gregorian;collation=pinyin", FULL_LENGTH},
6359 {"de-latn-DE-1901-u-co-phonebk-co-pinyin-ca-gregory", "de_Latn_DE_1901@calendar=gregorian;collation=phonebook", FULL_LENGTH},
6360 {"th-u-kf-nu-thai-kf-false", "th@colcasefirst=yes;numbers=thai", FULL_LENGTH},
6361 /* #9562 IANA language tag data update */
6362 {"en-gb-oed", "en_GB_OXENDICT", FULL_LENGTH},
6363 {"i-navajo", "nv", FULL_LENGTH},
6364 {"i-navajo-a-foo", "nv@a=foo", FULL_LENGTH},
6365 {"i-navajo-latn-us", "nv_Latn_US", FULL_LENGTH},
6366 {"sgn-br", "bzs", FULL_LENGTH},
6367 {"sgn-br-u-co-phonebk", "bzs@collation=phonebook", FULL_LENGTH},
6368 {"ja-latn-hepburn-heploc", "ja_Latn__ALALC97", FULL_LENGTH},
6369 {"ja-latn-hepburn-heploc-u-ca-japanese", "ja_Latn__ALALC97@calendar=japanese", FULL_LENGTH},
6370 {"en-a-bcde-0-fgh", "en@0=fgh;a=bcde", FULL_LENGTH},
6371 };
6372
6373 static void TestForLanguageTag(void) {
6374 char locale[256];
6375 int32_t i;
6376 UErrorCode status;
6377 int32_t parsedLen;
6378 int32_t expParsedLen;
6379
6380 for (i = 0; i < UPRV_LENGTHOF(langtag_to_locale); i++) {
6381 status = U_ZERO_ERROR;
6382 locale[0] = 0;
6383 expParsedLen = langtag_to_locale[i].len;
6384 if (expParsedLen == FULL_LENGTH) {
6385 expParsedLen = (int32_t)uprv_strlen(langtag_to_locale[i].bcpID);
6386 }
6387 uloc_forLanguageTag(langtag_to_locale[i].bcpID, locale, sizeof(locale), &parsedLen, &status);
6388 if (U_FAILURE(status)) {
6389 log_err_status(status, "Error returned by uloc_forLanguageTag for language tag [%s] - error: %s\n",
6390 langtag_to_locale[i].bcpID, u_errorName(status));
6391 } else {
6392 if (uprv_strcmp(langtag_to_locale[i].locID, locale) != 0) {
6393 log_data_err("uloc_forLanguageTag returned locale [%s] for input language tag [%s] - expected: [%s]\n",
6394 locale, langtag_to_locale[i].bcpID, langtag_to_locale[i].locID);
6395 }
6396 if (parsedLen != expParsedLen) {
6397 log_err("uloc_forLanguageTag parsed length of %d for input language tag [%s] - expected parsed length: %d\n",
6398 parsedLen, langtag_to_locale[i].bcpID, expParsedLen);
6399 }
6400 }
6401 }
6402 }
6403
6404 static const struct {
6405 const char *input;
6406 const char *canonical;
6407 } langtag_to_canonical[] = {
6408 {"de-DD", "de-DE"},
6409 {"de-DD-u-co-phonebk", "de-DE-u-co-phonebk"},
6410 {"jw-id", "jv-ID"},
6411 {"jw-id-u-ca-islamic-civil", "jv-ID-u-ca-islamic-civil"},
6412 {"mo-md", "ro-MD"},
6413 {"my-bu-u-nu-mymr", "my-MM-u-nu-mymr"},
6414 {"yuu-ru", "yug-RU"},
6415 };
6416
6417
6418 static void TestLangAndRegionCanonicalize(void) {
6419 char locale[256];
6420 char canonical[256];
6421 int32_t i;
6422 UErrorCode status;
6423 for (i = 0; i < UPRV_LENGTHOF(langtag_to_canonical); i++) {
6424 status = U_ZERO_ERROR;
6425 const char* input = langtag_to_canonical[i].input;
6426 uloc_forLanguageTag(input, locale, sizeof(locale), NULL, &status);
6427 uloc_toLanguageTag(locale, canonical, sizeof(canonical), TRUE, &status);
6428 if (U_FAILURE(status)) {
6429 log_err_status(status, "Error returned by uloc_forLanguageTag or uloc_toLanguageTag "
6430 "for language tag [%s] - error: %s\n", input, u_errorName(status));
6431 } else {
6432 const char* expected_canonical = langtag_to_canonical[i].canonical;
6433 if (uprv_strcmp(expected_canonical, canonical) != 0) {
6434 log_data_err("input language tag [%s] is canonicalized to [%s] - expected: [%s]\n",
6435 input, canonical, expected_canonical);
6436 }
6437 }
6438 }
6439 }
6440
6441 static void TestToUnicodeLocaleKey(void)
6442 {
6443 /* $IN specifies the result should be the input pointer itself */
6444 static const char* DATA[][2] = {
6445 {"calendar", "ca"},
6446 {"CALEndar", "ca"}, /* difference casing */
6447 {"ca", "ca"}, /* bcp key itself */
6448 {"kv", "kv"}, /* no difference between legacy and bcp */
6449 {"foo", NULL}, /* unknown, bcp ill-formed */
6450 {"ZZ", "$IN"}, /* unknown, bcp well-formed - */
6451 {NULL, NULL}
6452 };
6453
6454 int32_t i;
6455 for (i = 0; DATA[i][0] != NULL; i++) {
6456 const char* keyword = DATA[i][0];
6457 const char* expected = DATA[i][1];
6458 const char* bcpKey = NULL;
6459
6460 bcpKey = uloc_toUnicodeLocaleKey(keyword);
6461 if (expected == NULL) {
6462 if (bcpKey != NULL) {
6463 log_err("toUnicodeLocaleKey: keyword=%s => %s, expected=NULL\n", keyword, bcpKey);
6464 }
6465 } else if (bcpKey == NULL) {
6466 log_data_err("toUnicodeLocaleKey: keyword=%s => NULL, expected=%s\n", keyword, expected);
6467 } else if (uprv_strcmp(expected, "$IN") == 0) {
6468 if (bcpKey != keyword) {
6469 log_err("toUnicodeLocaleKey: keyword=%s => %s, expected=%s(input pointer)\n", keyword, bcpKey, keyword);
6470 }
6471 } else if (uprv_strcmp(bcpKey, expected) != 0) {
6472 log_err("toUnicodeLocaleKey: keyword=%s => %s, expected=%s\n", keyword, bcpKey, expected);
6473 }
6474 }
6475 }
6476
6477 static void TestBug20321UnicodeLocaleKey(void)
6478 {
6479 // key = alphanum alpha ;
6480 static const char* invalid[] = {
6481 "a0",
6482 "00",
6483 "a@",
6484 "0@",
6485 "@a",
6486 "@a",
6487 "abc",
6488 "0bc",
6489 };
6490 for (int i = 0; i < UPRV_LENGTHOF(invalid); i++) {
6491 const char* bcpKey = NULL;
6492 bcpKey = uloc_toUnicodeLocaleKey(invalid[i]);
6493 if (bcpKey != NULL) {
6494 log_err("toUnicodeLocaleKey: keyword=%s => %s, expected=NULL\n", invalid[i], bcpKey);
6495 }
6496 }
6497 static const char* valid[] = {
6498 "aa",
6499 "0a",
6500 };
6501 for (int i = 0; i < UPRV_LENGTHOF(valid); i++) {
6502 const char* bcpKey = NULL;
6503 bcpKey = uloc_toUnicodeLocaleKey(valid[i]);
6504 if (bcpKey == NULL) {
6505 log_err("toUnicodeLocaleKey: keyword=%s => NULL, expected!=NULL\n", valid[i]);
6506 }
6507 }
6508 }
6509
6510 static void TestToLegacyKey(void)
6511 {
6512 /* $IN specifies the result should be the input pointer itself */
6513 static const char* DATA[][2] = {
6514 {"kb", "colbackwards"},
6515 {"kB", "colbackwards"}, /* different casing */
6516 {"Collation", "collation"}, /* keyword itself with different casing */
6517 {"kv", "kv"}, /* no difference between legacy and bcp */
6518 {"foo", "$IN"}, /* unknown, bcp ill-formed */
6519 {"ZZ", "$IN"}, /* unknown, bcp well-formed */
6520 {"e=mc2", NULL}, /* unknown, bcp/legacy ill-formed */
6521 {NULL, NULL}
6522 };
6523
6524 int32_t i;
6525 for (i = 0; DATA[i][0] != NULL; i++) {
6526 const char* keyword = DATA[i][0];
6527 const char* expected = DATA[i][1];
6528 const char* legacyKey = NULL;
6529
6530 legacyKey = uloc_toLegacyKey(keyword);
6531 if (expected == NULL) {
6532 if (legacyKey != NULL) {
6533 log_err("toLegacyKey: keyword=%s => %s, expected=NULL\n", keyword, legacyKey);
6534 }
6535 } else if (legacyKey == NULL) {
6536 log_err("toLegacyKey: keyword=%s => NULL, expected=%s\n", keyword, expected);
6537 } else if (uprv_strcmp(expected, "$IN") == 0) {
6538 if (legacyKey != keyword) {
6539 log_err("toLegacyKey: keyword=%s => %s, expected=%s(input pointer)\n", keyword, legacyKey, keyword);
6540 }
6541 } else if (uprv_strcmp(legacyKey, expected) != 0) {
6542 log_data_err("toUnicodeLocaleKey: keyword=%s, %s, expected=%s\n", keyword, legacyKey, expected);
6543 }
6544 }
6545 }
6546
6547 static void TestToUnicodeLocaleType(void)
6548 {
6549 /* $IN specifies the result should be the input pointer itself */
6550 static const char* DATA[][3] = {
6551 {"tz", "Asia/Kolkata", "inccu"},
6552 {"calendar", "gregorian", "gregory"},
6553 {"ca", "gregorian", "gregory"},
6554 {"ca", "Gregorian", "gregory"},
6555 {"ca", "buddhist", "buddhist"},
6556 {"Calendar", "Japanese", "japanese"},
6557 {"calendar", "Islamic-Civil", "islamic-civil"},
6558 {"calendar", "islamicc", "islamic-civil"}, /* bcp type alias */
6559 {"colalternate", "NON-IGNORABLE", "noignore"},
6560 {"colcaselevel", "yes", "true"},
6561 {"rg", "GBzzzz", "$IN"},
6562 {"tz", "america/new_york", "usnyc"},
6563 {"tz", "Asia/Kolkata", "inccu"},
6564 {"timezone", "navajo", "usden"},
6565 {"ca", "aaaa", "$IN"}, /* unknown type, well-formed type */
6566 {"ca", "gregory-japanese-islamic", "$IN"}, /* unknown type, well-formed type */
6567 {"zz", "gregorian", NULL}, /* unknown key, ill-formed type */
6568 {"co", "foo-", NULL}, /* unknown type, ill-formed type */
6569 {"variableTop", "00A0", "$IN"}, /* valid codepoints type */
6570 {"variableTop", "wxyz", "$IN"}, /* invalid codepoints type - return as is for now */
6571 {"kr", "space-punct", "space-punct"}, /* valid reordercode type */
6572 {"kr", "digit-spacepunct", NULL}, /* invalid (bcp ill-formed) reordercode type */
6573 {NULL, NULL, NULL}
6574 };
6575
6576 int32_t i;
6577 for (i = 0; DATA[i][0] != NULL; i++) {
6578 const char* keyword = DATA[i][0];
6579 const char* value = DATA[i][1];
6580 const char* expected = DATA[i][2];
6581 const char* bcpType = NULL;
6582
6583 bcpType = uloc_toUnicodeLocaleType(keyword, value);
6584 if (expected == NULL) {
6585 if (bcpType != NULL) {
6586 log_err("toUnicodeLocaleType: keyword=%s, value=%s => %s, expected=NULL\n", keyword, value, bcpType);
6587 }
6588 } else if (bcpType == NULL) {
6589 log_data_err("toUnicodeLocaleType: keyword=%s, value=%s => NULL, expected=%s\n", keyword, value, expected);
6590 } else if (uprv_strcmp(expected, "$IN") == 0) {
6591 if (bcpType != value) {
6592 log_err("toUnicodeLocaleType: keyword=%s, value=%s => %s, expected=%s(input pointer)\n", keyword, value, bcpType, value);
6593 }
6594 } else if (uprv_strcmp(bcpType, expected) != 0) {
6595 log_data_err("toUnicodeLocaleType: keyword=%s, value=%s => %s, expected=%s\n", keyword, value, bcpType, expected);
6596 }
6597 }
6598 }
6599
6600 static void TestToLegacyType(void)
6601 {
6602 /* $IN specifies the result should be the input pointer itself */
6603 static const char* DATA[][3] = {
6604 {"calendar", "gregory", "gregorian"},
6605 {"ca", "gregory", "gregorian"},
6606 {"ca", "Gregory", "gregorian"},
6607 {"ca", "buddhist", "buddhist"},
6608 {"Calendar", "Japanese", "japanese"},
6609 {"calendar", "Islamic-Civil", "islamic-civil"},
6610 {"calendar", "islamicc", "islamic-civil"}, /* bcp type alias */
6611 {"colalternate", "noignore", "non-ignorable"},
6612 {"colcaselevel", "true", "yes"},
6613 {"rg", "gbzzzz", "gbzzzz"},
6614 {"tz", "usnyc", "America/New_York"},
6615 {"tz", "inccu", "Asia/Calcutta"},
6616 {"timezone", "usden", "America/Denver"},
6617 {"timezone", "usnavajo", "America/Denver"}, /* bcp type alias */
6618 {"colstrength", "quarternary", "quaternary"}, /* type alias */
6619 {"ca", "aaaa", "$IN"}, /* unknown type */
6620 {"calendar", "gregory-japanese-islamic", "$IN"}, /* unknown type, well-formed type */
6621 {"zz", "gregorian", "$IN"}, /* unknown key, bcp ill-formed type */
6622 {"ca", "gregorian-calendar", "$IN"}, /* known key, bcp ill-formed type */
6623 {"co", "e=mc2", NULL}, /* known key, ill-formed bcp/legacy type */
6624 {"variableTop", "00A0", "$IN"}, /* valid codepoints type */
6625 {"variableTop", "wxyz", "$IN"}, /* invalid codepoints type - return as is for now */
6626 {"kr", "space-punct", "space-punct"}, /* valid reordercode type */
6627 {"kr", "digit-spacepunct", "digit-spacepunct"}, /* invalid reordercode type, but ok for legacy syntax */
6628 {NULL, NULL, NULL}
6629 };
6630
6631 int32_t i;
6632 for (i = 0; DATA[i][0] != NULL; i++) {
6633 const char* keyword = DATA[i][0];
6634 const char* value = DATA[i][1];
6635 const char* expected = DATA[i][2];
6636 const char* legacyType = NULL;
6637
6638 legacyType = uloc_toLegacyType(keyword, value);
6639 if (expected == NULL) {
6640 if (legacyType != NULL) {
6641 log_err("toLegacyType: keyword=%s, value=%s => %s, expected=NULL\n", keyword, value, legacyType);
6642 }
6643 } else if (legacyType == NULL) {
6644 log_err("toLegacyType: keyword=%s, value=%s => NULL, expected=%s\n", keyword, value, expected);
6645 } else if (uprv_strcmp(expected, "$IN") == 0) {
6646 if (legacyType != value) {
6647 log_err("toLegacyType: keyword=%s, value=%s => %s, expected=%s(input pointer)\n", keyword, value, legacyType, value);
6648 }
6649 } else if (uprv_strcmp(legacyType, expected) != 0) {
6650 log_data_err("toLegacyType: keyword=%s, value=%s => %s, expected=%s\n", keyword, value, legacyType, expected);
6651 } else {
6652 log_verbose("toLegacyType: keyword=%s, value=%s => %s\n", keyword, value, legacyType);
6653 }
6654 }
6655 }
6656
6657
6658
6659 static void test_unicode_define(const char *namech, char ch, const char *nameu, UChar uch)
6660 {
6661 UChar asUch[1];
6662 asUch[0]=0;
6663 log_verbose("Testing whether %s[\\x%02x,'%c'] == %s[U+%04X]\n", namech, ch,(int)ch, nameu, (int) uch);
6664 u_charsToUChars(&ch, asUch, 1);
6665 if(asUch[0] != uch) {
6666 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);
6667 } else {
6668 log_verbose(" .. OK, == U+%04X\n", (int)asUch[0]);
6669 }
6670 }
6671
6672 #define TEST_UNICODE_DEFINE(x,y) test_unicode_define(#x, (char)(x), #y, (UChar)(y))
6673
6674 static void TestUnicodeDefines(void) {
6675 TEST_UNICODE_DEFINE(ULOC_KEYWORD_SEPARATOR, ULOC_KEYWORD_SEPARATOR_UNICODE);
6676 TEST_UNICODE_DEFINE(ULOC_KEYWORD_ASSIGN, ULOC_KEYWORD_ASSIGN_UNICODE);
6677 TEST_UNICODE_DEFINE(ULOC_KEYWORD_ITEM_SEPARATOR, ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE);
6678 }
6679
6680 static void TestIsRightToLeft() {
6681 // API test only. More test cases in intltest/LocaleTest.
6682 if(uloc_isRightToLeft("root") || !uloc_isRightToLeft("EN-HEBR")) {
6683 log_err("uloc_isRightToLeft() failed");
6684 }
6685 }
6686
6687 typedef struct {
6688 const char * badLocaleID;
6689 const char * displayLocale;
6690 const char * expectedName;
6691 UErrorCode expectedStatus;
6692 } BadLocaleItem;
6693
6694 static const BadLocaleItem badLocaleItems[] = {
6695 { "-9223372036854775808", "en", "9223372036854775808", U_USING_DEFAULT_WARNING },
6696 /* add more in the future */
6697 { NULL, NULL, NULL, U_ZERO_ERROR } /* terminator */
6698 };
6699
6700 enum { kUBufDispNameMax = 128, kBBufDispNameMax = 256 };
6701
6702 static void TestBadLocaleIDs() {
6703 const BadLocaleItem* itemPtr;
6704 for (itemPtr = badLocaleItems; itemPtr->badLocaleID != NULL; itemPtr++) {
6705 UChar ubufExpect[kUBufDispNameMax], ubufGet[kUBufDispNameMax];
6706 UErrorCode status = U_ZERO_ERROR;
6707 int32_t ulenExpect = u_unescape(itemPtr->expectedName, ubufExpect, kUBufDispNameMax);
6708 int32_t ulenGet = uloc_getDisplayName(itemPtr->badLocaleID, itemPtr->displayLocale, ubufGet, kUBufDispNameMax, &status);
6709 if (status != itemPtr->expectedStatus ||
6710 (U_SUCCESS(status) && (ulenGet != ulenExpect || u_strncmp(ubufGet, ubufExpect, ulenExpect) != 0))) {
6711 char bbufExpect[kBBufDispNameMax], bbufGet[kBBufDispNameMax];
6712 u_austrncpy(bbufExpect, ubufExpect, ulenExpect);
6713 u_austrncpy(bbufGet, ubufGet, ulenGet);
6714 log_err("FAIL: For localeID %s, displayLocale %s, calling uloc_getDisplayName:\n"
6715 " expected status %-26s, name (len %2d): %s\n"
6716 " got status %-26s, name (len %2d): %s\n",
6717 itemPtr->badLocaleID, itemPtr->displayLocale,
6718 u_errorName(itemPtr->expectedStatus), ulenExpect, bbufExpect,
6719 u_errorName(status), ulenGet, bbufGet );
6720 }
6721 }
6722 }
6723
6724 // Test case for ICU-20370.
6725 // The issue shows as an Addresss Sanitizer failure.
6726 static void TestBug20370() {
6727 const char *localeID = "x-privatebutreallylongtagfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar";
6728 uint32_t lcid = uloc_getLCID(localeID);
6729 if (lcid != 0) {
6730 log_err("FAIL: Expected LCID value of 0 for invalid localeID input.");
6731 }
6732 }
6733
6734
6735 // Test case for ICU-20149
6736 // Handle the duplicate U extension attribute
6737 static void TestBug20149() {
6738 const char *localeID = "zh-u-foo-foo-co-pinyin";
6739 char locale[256];
6740 UErrorCode status = U_ZERO_ERROR;
6741 int32_t parsedLen;
6742 locale[0] = '\0';
6743 uloc_forLanguageTag(localeID, locale, sizeof(locale), &parsedLen, &status);
6744 if (U_FAILURE(status) ||
6745 0 !=strcmp("zh@attribute=foo;collation=pinyin", locale)) {
6746 log_err("ERROR: in uloc_forLanguageTag %s return %s\n", myErrorName(status), locale);
6747 }
6748 }
6749
6750
6751 typedef enum UldnNameType {
6752 TEST_ULDN_LOCALE,
6753 TEST_ULDN_LANGUAGE,
6754 TEST_ULDN_SCRIPT,
6755 TEST_ULDN_REGION,
6756 TEST_ULOC_LOCALE, // only valid with optStdMidLong
6757 TEST_ULOC_LANGUAGE, // only valid with optStdMidLong
6758 TEST_ULOC_SCRIPT, // only valid with optStdMidLong
6759 TEST_ULOC_REGION, // only valid with optStdMidLong
6760 } UldnNameType;
6761
6762 typedef struct {
6763 const char * localeToName; // NULL to terminate a list of these
6764 UldnNameType nameType;
6765 const UChar * expectResult;
6766 } UldnItem;
6767
6768 typedef struct {
6769 const char * displayLocale;
6770 const UDisplayContext * displayOptions; // set of 3 UDisplayContext items
6771 const UldnItem * testItems;
6772 int32_t countItems;
6773 } UldnLocAndOpts;
6774
6775 static const UDisplayContext optStdMidLong[3] = {UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDISPCTX_LENGTH_FULL};
6776 static const UDisplayContext optStdMidShrt[3] = {UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDISPCTX_LENGTH_SHORT};
6777 static const UDisplayContext optDiaMidLong[3] = {UDISPCTX_DIALECT_NAMES, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDISPCTX_LENGTH_FULL};
6778 static const UDisplayContext optDiaMidShrt[3] = {UDISPCTX_DIALECT_NAMES, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UDISPCTX_LENGTH_SHORT};
6779
6780 static const UDisplayContext optStdBegLong[3] = {UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, UDISPCTX_LENGTH_FULL};
6781 static const UDisplayContext optStdBegShrt[3] = {UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, UDISPCTX_LENGTH_SHORT};
6782 static const UDisplayContext optDiaBegLong[3] = {UDISPCTX_DIALECT_NAMES, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, UDISPCTX_LENGTH_FULL};
6783 static const UDisplayContext optDiaBegShrt[3] = {UDISPCTX_DIALECT_NAMES, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, UDISPCTX_LENGTH_SHORT};
6784
6785 static const UDisplayContext optStdLstLong[3] = {UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, UDISPCTX_LENGTH_FULL};
6786 static const UDisplayContext optStdLstShrt[3] = {UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, UDISPCTX_LENGTH_SHORT};
6787 static const UDisplayContext optDiaLstLong[3] = {UDISPCTX_DIALECT_NAMES, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, UDISPCTX_LENGTH_FULL};
6788 static const UDisplayContext optDiaLstShrt[3] = {UDISPCTX_DIALECT_NAMES, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, UDISPCTX_LENGTH_SHORT};
6789
6790 static const UldnItem en_StdMidLong[] = {
6791 { "en_US", TEST_ULDN_LOCALE, u"English (US)" },
6792 { "en_US_POSIX", TEST_ULDN_LOCALE, u"English (US, Computer)" },
6793 { "en_US@calendar=chinese", TEST_ULDN_LOCALE, u"English (US, Chinese Calendar)" },
6794 { "en_CA", TEST_ULDN_LOCALE, u"English (Canada)" },
6795 { "pt", TEST_ULDN_LOCALE, u"Portuguese" },
6796 { "pt_BR", TEST_ULDN_LOCALE, u"Portuguese (Brazil)" },
6797 { "pt_PT", TEST_ULDN_LOCALE, u"Portuguese (Portugal)" },
6798 { "zh_Hans", TEST_ULDN_LOCALE, u"Chinese, Simplified" }, // Apple <rdar://problem/50750364>
6799 { "zh_Hans_CN", TEST_ULDN_LOCALE, u"Chinese, Simplified (China mainland)" }, // Apple <rdar://problem/50750364>
6800 { "zh_Hant", TEST_ULDN_LOCALE, u"Chinese, Traditional" }, // Apple <rdar://problem/50750364>
6801 { "zh_Hant_HK", TEST_ULDN_LOCALE, u"Chinese, Traditional (Hong Kong)" }, // Apple <rdar://problem/50750364>
6802 { "yue_Hans", TEST_ULDN_LOCALE, u"Cantonese, Simplified" }, // Apple <rdar://problem/50750364>
6803 { "yue_Hans_CN", TEST_ULDN_LOCALE, u"Cantonese, Simplified (China mainland)" }, // Apple <rdar://problem/50750364>
6804 { "yue_Hant", TEST_ULDN_LOCALE, u"Cantonese, Traditional" }, // Apple <rdar://problem/50750364>
6805 { "yue_Hant_HK", TEST_ULDN_LOCALE, u"Cantonese, Traditional (Hong Kong)" }, // Apple <rdar://problem/50750364>
6806 { "zh_Hans@calendar=chinese", TEST_ULDN_LOCALE, u"Chinese, Simplified (Chinese Calendar)" }, // Apple <rdar://problem/50750364>
6807 { "zh_Hans_CN@calendar=chinese", TEST_ULDN_LOCALE, u"Chinese, Simplified (China mainland, Chinese Calendar)" }, // Apple <rdar://problem/50750364>
6808 { "zh_Hant@calendar=chinese", TEST_ULDN_LOCALE, u"Chinese, Traditional (Chinese Calendar)" }, // Apple <rdar://problem/50750364>
6809 { "zh_Hant_HK@calendar=chinese", TEST_ULDN_LOCALE, u"Chinese, Traditional (Hong Kong, Chinese Calendar)" }, // Apple <rdar://problem/50750364>
6810 { "yue_Hans@calendar=chinese", TEST_ULDN_LOCALE, u"Cantonese, Simplified (Chinese Calendar)" }, // Apple <rdar://problem/50750364>
6811 { "yue_Hans_CN@calendar=chinese", TEST_ULDN_LOCALE, u"Cantonese, Simplified (China mainland, Chinese Calendar)" }, // Apple <rdar://problem/50750364>
6812 { "yue_Hant@calendar=chinese", TEST_ULDN_LOCALE, u"Cantonese, Traditional (Chinese Calendar)" }, // Apple <rdar://problem/50750364>
6813 { "yue_Hant_HK@calendar=chinese", TEST_ULDN_LOCALE, u"Cantonese, Traditional (Hong Kong, Chinese Calendar)" }, // Apple <rdar://problem/50750364>
6814 { "zh_HK", TEST_ULDN_LOCALE, u"Chinese (Hong Kong)" },
6815 { "Latn", TEST_ULDN_SCRIPT, u"Latin" },
6816 { "Hans", TEST_ULDN_SCRIPT, u"Simplified Han" },
6817 { "Hant", TEST_ULDN_SCRIPT, u"Traditional Han" },
6818 { "US", TEST_ULDN_REGION, u"United States" },
6819 { "CA", TEST_ULDN_REGION, u"Canada" },
6820 { "GB", TEST_ULDN_REGION, u"United Kingdom" },
6821 { "HK", TEST_ULDN_REGION, u"Hong Kong" },
6822 { "ps_Arab", TEST_ULDN_LOCALE, u"Pashto (Arabic)" },
6823 { "ps_Arab_AF", TEST_ULDN_LOCALE, u"Pashto (Arabic, Afghanistan)" },
6824 { "ks_Arab", TEST_ULDN_LOCALE, u"Kashmiri (Naskh)" }, // Apple <rdar://problem/50687287>
6825 { "ks_Aran", TEST_ULDN_LOCALE, u"Kashmiri (Nastaliq)" }, // Apple <rdar://problem/47494884>
6826 { "ks_Arab_IN", TEST_ULDN_LOCALE, u"Kashmiri (Naskh, India)" }, // Apple <rdar://problem/50687287>
6827 { "ks_Aran_IN", TEST_ULDN_LOCALE, u"Kashmiri (Nastaliq, India)" }, // Apple <rdar://problem/47494884>
6828 { "pa_Arab", TEST_ULDN_LOCALE, u"Punjabi (Naskh)" }, // Apple <rdar://problem/50687287>
6829 { "pa_Aran", TEST_ULDN_LOCALE, u"Punjabi (Nastaliq)" }, // Apple <rdar://problem/50687287>
6830 { "pa_Arab_PK", TEST_ULDN_LOCALE, u"Punjabi (Naskh, Pakistan)" }, // Apple <rdar://problem/50687287>
6831 { "pa_Aran_PK", TEST_ULDN_LOCALE, u"Punjabi (Nastaliq, Pakistan)" }, // Apple <rdar://problem/50687287>
6832 { "ur_Arab", TEST_ULDN_LOCALE, u"Urdu (Naskh)" }, // Apple <rdar://problem/50687287>
6833 { "ur_Aran", TEST_ULDN_LOCALE, u"Urdu (Nastaliq)" }, // Apple <rdar://problem/47494884>
6834 { "ur_Arab_PK", TEST_ULDN_LOCALE, u"Urdu (Naskh, Pakistan)" }, // Apple <rdar://problem/50687287>
6835 { "ur_Aran_PK", TEST_ULDN_LOCALE, u"Urdu (Nastaliq, Pakistan)" }, // Apple <rdar://problem/47494884>
6836 { "ps_Arab@calendar=islamic", TEST_ULDN_LOCALE, u"Pashto (Arabic, Islamic Calendar)" },
6837 { "ps_Arab_AF@calendar=islamic", TEST_ULDN_LOCALE, u"Pashto (Arabic, Afghanistan, Islamic Calendar)" },
6838 { "ks_Arab@calendar=islamic", TEST_ULDN_LOCALE, u"Kashmiri (Naskh, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
6839 { "ks_Aran@calendar=islamic", TEST_ULDN_LOCALE, u"Kashmiri (Nastaliq, Islamic Calendar)" }, // Apple <rdar://problem/47494884>
6840 { "ks_Arab_IN@calendar=islamic", TEST_ULDN_LOCALE, u"Kashmiri (Naskh, India, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
6841 { "ks_Aran_IN@calendar=islamic", TEST_ULDN_LOCALE, u"Kashmiri (Nastaliq, India, Islamic Calendar)" }, // Apple <rdar://problem/47494884>
6842 { "pa_Arab@calendar=islamic", TEST_ULDN_LOCALE, u"Punjabi (Naskh, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
6843 { "pa_Aran@calendar=islamic", TEST_ULDN_LOCALE, u"Punjabi (Nastaliq, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
6844 { "pa_Arab_PK@calendar=islamic", TEST_ULDN_LOCALE, u"Punjabi (Naskh, Pakistan, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
6845 { "pa_Aran_PK@calendar=islamic", TEST_ULDN_LOCALE, u"Punjabi (Nastaliq, Pakistan, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
6846 { "ur_Arab@calendar=islamic", TEST_ULDN_LOCALE, u"Urdu (Naskh, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
6847 { "ur_Aran@calendar=islamic", TEST_ULDN_LOCALE, u"Urdu (Nastaliq, Islamic Calendar)" }, // Apple <rdar://problem/47494884>
6848 { "ur_Arab_PK@calendar=islamic", TEST_ULDN_LOCALE, u"Urdu (Naskh, Pakistan, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
6849 { "ur_Aran_PK@calendar=islamic", TEST_ULDN_LOCALE, u"Urdu (Nastaliq, Pakistan, Islamic Calendar)" }, // Apple <rdar://problem/47494884>
6850 { "Arab", TEST_ULDN_SCRIPT, u"Arabic" },
6851 { "Aran", TEST_ULDN_SCRIPT, u"Nastaliq" }, // Apple <rdar://problem/47494884>
6852 { "Qaag", TEST_ULDN_SCRIPT, u"Zawgyi" }, // Apple <rdar://problem/51471316>
6853 { "my_Qaag", TEST_ULDN_LOCALE, u"Burmese (Zawgyi)" }, // Apple <rdar://problem/51471316>
6854
6855 { "zh_Hans", TEST_ULOC_LOCALE, u"Chinese, Simplified" }, // Apple <rdar://problem/51418203>
6856 { "zh_Hans_CN", TEST_ULOC_LOCALE, u"Chinese, Simplified (China mainland)" }, // Apple <rdar://problem/51418203>
6857 { "zh_Hant", TEST_ULOC_LOCALE, u"Chinese, Traditional" }, // Apple <rdar://problem/51418203>
6858 { "zh_Hant_HK", TEST_ULOC_LOCALE, u"Chinese, Traditional (Hong Kong)" }, // Apple <rdar://problem/51418203>
6859 { "yue_Hans", TEST_ULOC_LOCALE, u"Cantonese, Simplified" }, // Apple <rdar://problem/51418203>
6860 { "yue_Hans_CN", TEST_ULOC_LOCALE, u"Cantonese, Simplified (China mainland)" }, // Apple <rdar://problem/51418203>
6861 { "yue_Hant", TEST_ULOC_LOCALE, u"Cantonese, Traditional" }, // Apple <rdar://problem/51418203>
6862 { "yue_Hant_HK", TEST_ULOC_LOCALE, u"Cantonese, Traditional (Hong Kong)" }, // Apple <rdar://problem/51418203>
6863 { "zh_Hans@calendar=chinese", TEST_ULOC_LOCALE, u"Chinese, Simplified (Chinese Calendar)" }, // Apple <rdar://problem/50750364>
6864 { "zh_Hans_CN@calendar=chinese", TEST_ULOC_LOCALE, u"Chinese, Simplified (China mainland, Chinese Calendar)" }, // Apple <rdar://problem/50750364>
6865 { "zh_Hant@calendar=chinese", TEST_ULOC_LOCALE, u"Chinese, Traditional (Chinese Calendar)" }, // Apple <rdar://problem/50750364>
6866 { "zh_Hant_HK@calendar=chinese", TEST_ULOC_LOCALE, u"Chinese, Traditional (Hong Kong, Chinese Calendar)" }, // Apple <rdar://problem/50750364>
6867 { "yue_Hans@calendar=chinese", TEST_ULOC_LOCALE, u"Cantonese, Simplified (Chinese Calendar)" }, // Apple <rdar://problem/50750364>
6868 { "yue_Hans_CN@calendar=chinese", TEST_ULOC_LOCALE, u"Cantonese, Simplified (China mainland, Chinese Calendar)" }, // Apple <rdar://problem/50750364>
6869 { "yue_Hant@calendar=chinese", TEST_ULOC_LOCALE, u"Cantonese, Traditional (Chinese Calendar)" }, // Apple <rdar://problem/50750364>
6870 { "yue_Hant_HK@calendar=chinese", TEST_ULOC_LOCALE, u"Cantonese, Traditional (Hong Kong, Chinese Calendar)" }, // Apple <rdar://problem/50750364>
6871 { "ks_Arab", TEST_ULOC_LOCALE, u"Kashmiri (Naskh)" }, // Apple <rdar://problem/51418203>
6872 { "ks_Aran", TEST_ULOC_LOCALE, u"Kashmiri (Nastaliq)" }, // Apple <rdar://problem/47494884>
6873 { "ks_Arab_IN", TEST_ULOC_LOCALE, u"Kashmiri (Naskh, India)" }, // Apple <rdar://problem/51418203>
6874 { "ks_Aran_IN", TEST_ULOC_LOCALE, u"Kashmiri (Nastaliq, India)" }, // Apple <rdar://problem/47494884>
6875 { "pa_Arab", TEST_ULOC_LOCALE, u"Punjabi (Naskh)" }, // Apple <rdar://problem/51418203>
6876 { "pa_Aran", TEST_ULOC_LOCALE, u"Punjabi (Nastaliq)" }, // Apple <rdar://problem/51418203>
6877 { "pa_Arab_PK", TEST_ULOC_LOCALE, u"Punjabi (Naskh, Pakistan)" }, // Apple <rdar://problem/51418203>
6878 { "pa_Aran_PK", TEST_ULOC_LOCALE, u"Punjabi (Nastaliq, Pakistan)" }, // Apple <rdar://problem/51418203>
6879 { "ur_Arab", TEST_ULOC_LOCALE, u"Urdu (Naskh)" }, // Apple <rdar://problem/51418203>
6880 { "ur_Aran", TEST_ULOC_LOCALE, u"Urdu (Nastaliq)" }, // Apple <rdar://problem/47494884>
6881 { "ur_Arab_PK", TEST_ULOC_LOCALE, u"Urdu (Naskh, Pakistan)" }, // Apple <rdar://problem/51418203>
6882 { "ur_Aran_PK", TEST_ULOC_LOCALE, u"Urdu (Nastaliq, Pakistan)" }, // Apple <rdar://problem/47494884>
6883 { "ks_Arab@calendar=islamic", TEST_ULOC_LOCALE, u"Kashmiri (Naskh, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
6884 { "ks_Aran@calendar=islamic", TEST_ULOC_LOCALE, u"Kashmiri (Nastaliq, Islamic Calendar)" }, // Apple <rdar://problem/47494884>
6885 { "ks_Arab_IN@calendar=islamic", TEST_ULOC_LOCALE, u"Kashmiri (Naskh, India, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
6886 { "ks_Aran_IN@calendar=islamic", TEST_ULOC_LOCALE, u"Kashmiri (Nastaliq, India, Islamic Calendar)" }, // Apple <rdar://problem/47494884>
6887 { "pa_Arab@calendar=islamic", TEST_ULOC_LOCALE, u"Punjabi (Naskh, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
6888 { "pa_Aran@calendar=islamic", TEST_ULOC_LOCALE, u"Punjabi (Nastaliq, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
6889 { "pa_Arab_PK@calendar=islamic", TEST_ULOC_LOCALE, u"Punjabi (Naskh, Pakistan, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
6890 { "pa_Aran_PK@calendar=islamic", TEST_ULOC_LOCALE, u"Punjabi (Nastaliq, Pakistan, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
6891 { "ur_Arab@calendar=islamic", TEST_ULOC_LOCALE, u"Urdu (Naskh, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
6892 { "ur_Aran@calendar=islamic", TEST_ULOC_LOCALE, u"Urdu (Nastaliq, Islamic Calendar)" }, // Apple <rdar://problem/47494884>
6893 { "ur_Arab_PK@calendar=islamic", TEST_ULOC_LOCALE, u"Urdu (Naskh, Pakistan, Islamic Calendar)" }, // Apple <rdar://problem/50687287>
6894 { "ur_Aran_PK@calendar=islamic", TEST_ULOC_LOCALE, u"Urdu (Nastaliq, Pakistan, Islamic Calendar)" }, // Apple <rdar://problem/47494884>
6895 { "my_Qaag", TEST_ULOC_LOCALE, u"Burmese (Zawgyi)" }, // Apple <rdar://problem/51471316>
6896 };
6897
6898 static const UldnItem en_StdMidShrt[] = {
6899 { "en_US", TEST_ULDN_LOCALE, u"English (US)" },
6900 { "en_US_POSIX", TEST_ULDN_LOCALE, u"English (US, Computer)" },
6901 { "en_US@calendar=chinese", TEST_ULDN_LOCALE, u"English (US, Chinese Calendar)" },
6902 { "en_CA", TEST_ULDN_LOCALE, u"English (Canada)" },
6903 { "pt", TEST_ULDN_LOCALE, u"Portuguese" },
6904 { "pt_BR", TEST_ULDN_LOCALE, u"Portuguese (Brazil)" },
6905 { "pt_PT", TEST_ULDN_LOCALE, u"Portuguese (Portugal)" },
6906 { "zh_Hans", TEST_ULDN_LOCALE, u"Chinese, Simplified" },
6907 { "zh_Hant_HK", TEST_ULDN_LOCALE, u"Chinese, Traditional (Hong Kong)" },
6908 { "zh_HK", TEST_ULDN_LOCALE, u"Chinese (Hong Kong)" },
6909 { "Latn", TEST_ULDN_SCRIPT, u"Latin" },
6910 { "Hans", TEST_ULDN_SCRIPT, u"Simplified Han" },
6911 { "Hant", TEST_ULDN_SCRIPT, u"Traditional Han" },
6912 { "US", TEST_ULDN_REGION, u"US" },
6913 { "CA", TEST_ULDN_REGION, u"Canada" },
6914 { "GB", TEST_ULDN_REGION, u"UK" },
6915 { "HK", TEST_ULDN_REGION, u"Hong Kong" },
6916 };
6917
6918 static const UldnItem en_DiaMidLong[] = {
6919 { "en_US", TEST_ULDN_LOCALE, u"American English" },
6920 { "en_US_POSIX", TEST_ULDN_LOCALE, u"American English (Computer)" },
6921 { "en_US@calendar=chinese", TEST_ULDN_LOCALE, u"American English (Chinese Calendar)" },
6922 { "en_CA", TEST_ULDN_LOCALE, u"Canadian English" },
6923 { "pt", TEST_ULDN_LOCALE, u"Portuguese" },
6924 { "pt_BR", TEST_ULDN_LOCALE, u"Brazilian Portuguese" },
6925 { "pt_PT", TEST_ULDN_LOCALE, u"European Portuguese" },
6926 { "zh_Hans", TEST_ULDN_LOCALE, u"Chinese, Simplified" },
6927 { "zh_Hant_HK", TEST_ULDN_LOCALE, u"Chinese, Traditional (Hong Kong)" },
6928 { "zh_HK", TEST_ULDN_LOCALE, u"Chinese (Hong Kong)" },
6929 { "Latn", TEST_ULDN_SCRIPT, u"Latin" },
6930 { "Hans", TEST_ULDN_SCRIPT, u"Simplified Han" },
6931 { "Hant", TEST_ULDN_SCRIPT, u"Traditional Han" },
6932 { "US", TEST_ULDN_REGION, u"United States" },
6933 { "CA", TEST_ULDN_REGION, u"Canada" },
6934 { "GB", TEST_ULDN_REGION, u"United Kingdom" },
6935 { "HK", TEST_ULDN_REGION, u"Hong Kong" },
6936 };
6937
6938 static const UldnItem en_DiaMidShrt[] = {
6939 { "en_US", TEST_ULDN_LOCALE, u"US English" },
6940 { "en_US_POSIX", TEST_ULDN_LOCALE, u"US English (Computer)" },
6941 { "en_US@calendar=chinese", TEST_ULDN_LOCALE, u"US English (Chinese Calendar)" },
6942 { "en_CA", TEST_ULDN_LOCALE, u"Canadian English" },
6943 { "pt", TEST_ULDN_LOCALE, u"Portuguese" },
6944 { "pt_BR", TEST_ULDN_LOCALE, u"Brazilian Portuguese" },
6945 { "pt_PT", TEST_ULDN_LOCALE, u"European Portuguese" },
6946 { "zh_Hans", TEST_ULDN_LOCALE, u"Chinese, Simplified" },
6947 { "zh_Hant_HK", TEST_ULDN_LOCALE, u"Chinese, Traditional (Hong Kong)" },
6948 { "zh_HK", TEST_ULDN_LOCALE, u"Chinese (Hong Kong)" },
6949 { "Latn", TEST_ULDN_SCRIPT, u"Latin" },
6950 { "Hans", TEST_ULDN_SCRIPT, u"Simplified Han" },
6951 { "Hant", TEST_ULDN_SCRIPT, u"Traditional Han" },
6952 { "US", TEST_ULDN_REGION, u"US" },
6953 { "CA", TEST_ULDN_REGION, u"Canada" },
6954 { "GB", TEST_ULDN_REGION, u"UK" },
6955 { "HK", TEST_ULDN_REGION, u"Hong Kong" },
6956 };
6957
6958 static const UldnItem en_CA_DiaMidLong[] = { // <rdar://problem/60916890>
6959 { "yue_Hans", TEST_ULDN_LOCALE, u"Cantonese, Simplified" },
6960 { "yue_Hant", TEST_ULDN_LOCALE, u"Cantonese, Traditional" },
6961 { "zh_Hans", TEST_ULDN_LOCALE, u"Chinese, Simplified" },
6962 { "zh_Hant", TEST_ULDN_LOCALE, u"Chinese, Traditional" },
6963 { "ar_001", TEST_ULDN_LOCALE, u"Modern Standard Arabic" },
6964 { "de_AT", TEST_ULDN_LOCALE, u"Austrian German" },
6965 { "es_419", TEST_ULDN_LOCALE, u"Latin American Spanish" },
6966 { "fr_CA", TEST_ULDN_LOCALE, u"Canadian French" },
6967 { "en_GB", TEST_ULDN_LOCALE, u"British English" },
6968 { "en_US", TEST_ULDN_LOCALE, u"American English" },
6969 };
6970
6971 static const UldnItem en_CA_DiaMidShrt[] = { // <rdar://problem/60916890>
6972 { "yue_Hans", TEST_ULDN_LOCALE, u"Cantonese, Simplified" },
6973 { "yue_Hant", TEST_ULDN_LOCALE, u"Cantonese, Traditional" },
6974 { "zh_Hans", TEST_ULDN_LOCALE, u"Chinese, Simplified" },
6975 { "zh_Hant", TEST_ULDN_LOCALE, u"Chinese, Traditional" },
6976 { "ar_001", TEST_ULDN_LOCALE, u"Modern Standard Arabic" },
6977 { "de_AT", TEST_ULDN_LOCALE, u"Austrian German" },
6978 { "es_419", TEST_ULDN_LOCALE, u"Latin American Spanish" },
6979 { "fr_CA", TEST_ULDN_LOCALE, u"Canadian French" },
6980 { "en_GB", TEST_ULDN_LOCALE, u"UK English" },
6981 { "en_US", TEST_ULDN_LOCALE, u"US English" },
6982 };
6983
6984 static const UldnItem en_GB_DiaMidLong[] = { // <rdar://problem/60916890>
6985 { "yue_Hans", TEST_ULDN_LOCALE, u"Cantonese, Simplified" },
6986 { "yue_Hant", TEST_ULDN_LOCALE, u"Cantonese, Traditional" },
6987 { "zh_Hans", TEST_ULDN_LOCALE, u"Chinese, Simplified" },
6988 { "zh_Hant", TEST_ULDN_LOCALE, u"Chinese, Traditional" },
6989 { "ar_001", TEST_ULDN_LOCALE, u"Modern Standard Arabic" },
6990 { "de_AT", TEST_ULDN_LOCALE, u"Austrian German" },
6991 { "es_419", TEST_ULDN_LOCALE, u"Latin American Spanish" },
6992 { "fr_CA", TEST_ULDN_LOCALE, u"Canadian French" },
6993 { "en_GB", TEST_ULDN_LOCALE, u"British English" },
6994 { "en_US", TEST_ULDN_LOCALE, u"American English" },
6995 };
6996
6997 static const UldnItem en_GB_DiaMidShrt[] = { // <rdar://problem/60916890>
6998 { "yue_Hans", TEST_ULDN_LOCALE, u"Cantonese, Simplified" },
6999 { "yue_Hant", TEST_ULDN_LOCALE, u"Cantonese, Traditional" },
7000 { "zh_Hans", TEST_ULDN_LOCALE, u"Chinese, Simplified" },
7001 { "zh_Hant", TEST_ULDN_LOCALE, u"Chinese, Traditional" },
7002 { "ar_001", TEST_ULDN_LOCALE, u"Modern Standard Arabic" },
7003 { "de_AT", TEST_ULDN_LOCALE, u"Austrian German" },
7004 { "es_419", TEST_ULDN_LOCALE, u"Latin American Spanish" },
7005 { "fr_CA", TEST_ULDN_LOCALE, u"Canadian French" },
7006 { "en_GB", TEST_ULDN_LOCALE, u"UK English" },
7007 { "en_US", TEST_ULDN_LOCALE, u"US English" },
7008 };
7009
7010 static const UldnItem en_IN_StdMidLong[] = {
7011 { "bn", TEST_ULDN_LOCALE, u"Bangla" },
7012 { "bn_Beng", TEST_ULDN_LOCALE, u"Bangla (Bangla)" },
7013 { "or", TEST_ULDN_LOCALE, u"Odia" },
7014 { "or_Orya", TEST_ULDN_LOCALE, u"Odia (Odia)" },
7015 };
7016
7017 static const UldnItem fr_StdMidLong[] = {
7018 { "en_US", TEST_ULDN_LOCALE, u"anglais (É.-U.)" },
7019 { "US", TEST_ULDN_REGION, u"États-Unis" },
7020 { "HK", TEST_ULDN_REGION, u"Hong Kong" },
7021 };
7022
7023 static const UldnItem fr_StdMidShrt[] = {
7024 { "en_US", TEST_ULDN_LOCALE, u"anglais (É.-U.)" },
7025 { "US", TEST_ULDN_REGION, u"É.-U." },
7026 { "HK", TEST_ULDN_REGION, u"Hong Kong" },
7027 };
7028
7029 static const UldnItem fr_StdBegLong[] = {
7030 { "en_US", TEST_ULDN_LOCALE, u"Anglais (É.-U.)" },
7031 };
7032
7033 static const UldnItem fr_StdLstLong[] = {
7034 { "en_US", TEST_ULDN_LOCALE, u"Anglais (É.-U.)" },
7035 { "PS", TEST_ULDN_REGION, u"Territoires palestiniens" },
7036 };
7037
7038 static const UldnItem fr_DiaMidLong[] = {
7039 { "en_US", TEST_ULDN_LOCALE, u"anglais américain" },
7040 };
7041
7042 static const UldnItem ca_StdLstLong[] = {
7043 { "PS", TEST_ULDN_REGION, u"Territoris palestins" },
7044 { "SZ", TEST_ULDN_REGION, u"eSwatini" }, // Apple <rdar://65139631>
7045 };
7046
7047 static const UldnItem nb_StdMidLong[] = {
7048 { "ur_Arab", TEST_ULDN_LOCALE, u"urdu (naskh)" },
7049 };
7050
7051 static const UldnItem ur_StdMidLong[] = {
7052 { "ps_Arab", TEST_ULDN_LOCALE, u"پشتو (عربی)" },
7053 { "ps_Arab_AF", TEST_ULDN_LOCALE, u"پشتو (عربی،افغانستان)" },
7054 { "ur_Aran", TEST_ULDN_LOCALE, u"اردو (نستعلیق)" }, // Apple <rdar://problem/47494884>
7055 { "ur_Arab", TEST_ULDN_LOCALE, u"اردو (نسخ)" }, // Apple <rdar://problem/50687287>
7056 { "ur_Aran_PK", TEST_ULDN_LOCALE, u"اردو (نستعلیق،پاکستان)" }, // Apple <rdar://problem/47494884>
7057 { "ur_Arab_PK", TEST_ULDN_LOCALE, u"اردو (نسخ،پاکستان)" }, // Apple <rdar://problem/50687287>
7058
7059 { "ps_Arab", TEST_ULOC_LOCALE, u"پشتو (عربی)" },
7060 { "ps_Arab_AF", TEST_ULOC_LOCALE, u"پشتو (عربی،افغانستان)" },
7061 { "ur_Aran", TEST_ULOC_LOCALE, u"اردو (نستعلیق)" }, // Apple <rdar://problem/47494884>
7062 { "ur_Arab", TEST_ULOC_LOCALE, u"اردو (نسخ)" }, // Apple <rdar://problem/51418203>
7063 { "ur_Aran_PK", TEST_ULOC_LOCALE, u"اردو (نستعلیق،پاکستان)" }, // Apple <rdar://problem/47494884>
7064 { "ur_Arab_PK", TEST_ULOC_LOCALE, u"اردو (نسخ،پاکستان)" }, // Apple <rdar://problem/51418203>
7065 };
7066
7067 static const UldnItem pa_Arab_StdMidLong[] = {
7068 { "pa_Aran", TEST_ULDN_LOCALE, u"پنجابی (نستعلیق)" }, // Apple <rdar://problem/47494884>
7069 { "pa_Arab", TEST_ULDN_LOCALE, u"پنجابی (نسخ)" }, // Apple <rdar://problem/50687287>
7070 { "pa_Aran_PK", TEST_ULDN_LOCALE, u"پنجابی (نستعلیق, پاکستان)" }, // Apple <rdar://problem/47494884>
7071 { "pa_Arab_PK", TEST_ULDN_LOCALE, u"پنجابی (نسخ, پاکستان)" }, // Apple <rdar://problem/50687287>
7072
7073 { "pa_Aran", TEST_ULOC_LOCALE, u"پنجابی (نستعلیق)" }, // Apple <rdar://problem/51418203>
7074 { "pa_Arab", TEST_ULOC_LOCALE, u"پنجابی (نسخ)" }, // Apple <rdar://problem/51418203>
7075 { "pa_Aran_PK", TEST_ULOC_LOCALE, u"پنجابی (نستعلیق, پاکستان)" }, // Apple <rdar://problem/51418203>
7076 { "pa_Arab_PK", TEST_ULOC_LOCALE, u"پنجابی (نسخ, پاکستان)" }, // Apple <rdar://problem/51418203>
7077 };
7078
7079 static const UldnItem zh_StdMidLong[] = {
7080 { "zh_Hans", TEST_ULDN_LOCALE, u"简体中文" }, // Apple <rdar://problem/50750364>
7081 { "zh_Hans_CN", TEST_ULDN_LOCALE, u"简体中文(中国大陆)" }, // Apple <rdar://problem/50750364>
7082 { "zh_Hant", TEST_ULDN_LOCALE, u"繁体中文" }, // Apple <rdar://problem/50750364>
7083 { "zh_Hant_HK", TEST_ULDN_LOCALE, u"繁体中文(香港)" }, // Apple <rdar://problem/50750364>
7084 { "yue_Hans", TEST_ULDN_LOCALE, u"简体粤语" }, // Apple <rdar://problem/50750364>
7085 { "yue_Hans_CN", TEST_ULDN_LOCALE, u"简体粤语(中国大陆)" }, // Apple <rdar://problem/50750364>
7086 { "yue_Hant", TEST_ULDN_LOCALE, u"繁体粤语" }, // Apple <rdar://problem/50750364>
7087 { "yue_Hant_HK", TEST_ULDN_LOCALE, u"繁体粤语(香港)" }, // Apple <rdar://problem/50750364>
7088 { "ps_Arab", TEST_ULDN_LOCALE, u"普什图语(阿拉伯文)" },
7089 { "ps_Arab_AF", TEST_ULDN_LOCALE, u"普什图语(阿拉伯文,阿富汗)" },
7090 { "ur_Aran", TEST_ULDN_LOCALE, u"乌尔都语(波斯体)" }, // Apple <rdar://problem/47494884>
7091 { "ur_Arab", TEST_ULDN_LOCALE, u"乌尔都语(誊抄体)" }, // Apple <rdar://problem/50687287>
7092 { "ur_Aran_PK", TEST_ULDN_LOCALE, u"乌尔都语(波斯体,巴基斯坦)" }, // Apple <rdar://problem/47494884>
7093 { "ur_Arab_PK", TEST_ULDN_LOCALE, u"乌尔都语(誊抄体,巴基斯坦)" }, // Apple <rdar://problem/50687287>
7094
7095 { "zh_Hans", TEST_ULOC_LOCALE, u"简体中文" }, // Apple <rdar://problem/51418203>
7096 { "zh_Hans_CN", TEST_ULOC_LOCALE, u"简体中文(中国大陆)" }, // Apple <rdar://problem/51418203>
7097 { "zh_Hant", TEST_ULOC_LOCALE, u"繁体中文" }, // Apple <rdar://problem/51418203>
7098 { "zh_Hant_HK", TEST_ULOC_LOCALE, u"繁体中文(香港)" }, // Apple <rdar://problem/51418203>
7099 { "yue_Hans", TEST_ULOC_LOCALE, u"简体粤语" }, // Apple <rdar://problem/51418203>
7100 { "yue_Hans_CN", TEST_ULOC_LOCALE, u"简体粤语(中国大陆)" }, // Apple <rdar://problem/51418203>
7101 { "yue_Hant", TEST_ULOC_LOCALE, u"繁体粤语" }, // Apple <rdar://problem/51418203>
7102 { "yue_Hant_HK", TEST_ULOC_LOCALE, u"繁体粤语(香港)" }, // Apple <rdar://problem/51418203>
7103 { "ur_Aran", TEST_ULOC_LOCALE, u"乌尔都语(波斯体)" }, // Apple <rdar://problem/47494884>
7104 { "ur_Arab", TEST_ULOC_LOCALE, u"乌尔都语(誊抄体)" }, // Apple <rdar://problem/51418203>
7105 { "ur_Aran_PK", TEST_ULOC_LOCALE, u"乌尔都语(波斯体,巴基斯坦)" }, // Apple <rdar://problem/47494884>
7106 { "ur_Arab_PK", TEST_ULOC_LOCALE, u"乌尔都语(誊抄体,巴基斯坦)" }, // Apple <rdar://problem/51418203>
7107 };
7108
7109 static const UldnItem yue_Hans_StdMidLong[] = {
7110 { "zh_Hans_CN", TEST_ULOC_LOCALE, u"简体中文(中国大陆)" }, // Apple <rdar://problem/53136228>
7111 { "zh_Hant_HK", TEST_ULOC_LOCALE, u"繁体中文(香港)" }, // Apple <rdar://problem/53136228>
7112 { "yue_Hans_CN", TEST_ULOC_LOCALE, u"简体粤语(中国大陆)" }, // Apple <rdar://problem/53136228>
7113 { "yue_Hant_HK", TEST_ULOC_LOCALE, u"繁体粤语(香港)" }, // Apple <rdar://problem/53136228>
7114 };
7115
7116 static const UldnItem nds_StdMidLong[] = { // Apple <rdar://problem/64703717>
7117 { "nds", TEST_ULOC_LOCALE, u"Neddersass’sch" },
7118 };
7119
7120 static const UldnItem hi_StdMidLong[] = { // Apple <rdar://problem/53653337>
7121 { "Aran", TEST_ULDN_SCRIPT, u"नसतालीक़" },
7122 };
7123
7124 static const UldnItem hi_Latn_StdMidLong[] = { // Apple <rdar://problem/53216112>
7125 { "en", TEST_ULDN_LOCALE, u"English" },
7126 { "hi_Deva", TEST_ULDN_LOCALE, u"Hindi (Devanagari)" },
7127 { "hi_Latn", TEST_ULDN_LOCALE, u"Hindi (Latin)" },
7128 { "hi_Latn_IN", TEST_ULDN_LOCALE, u"Hindi (Latin, Bhaarat)" },
7129 };
7130
7131 static const UldnItem mni_Beng_StdMidLong[] = { // Apple <rdar://problem/54153189>
7132 { "mni_Beng", TEST_ULDN_LOCALE, u"মৈতৈলোন্ (বাংলা)" },
7133 { "mni_Mtei", TEST_ULDN_LOCALE, u"মৈতৈলোন্ (মেইটেই মায়েক)" },
7134 };
7135
7136 static const UldnItem mni_Mtei_StdMidLong[] = { // Apple <rdar://problem/54153189>
7137 { "mni_Beng", TEST_ULDN_LOCALE, u"ꯃꯤꯇꯩꯂꯣꯟ (ꯕꯪꯂꯥ)" },
7138 { "mni_Mtei", TEST_ULDN_LOCALE, u"ꯃꯤꯇꯩꯂꯣꯟ (ꯃꯤꯇꯩ ꯃꯌꯦꯛ)" },
7139 };
7140
7141 static const UldnItem sat_Olck_StdMidLong[] = { // Apple <rdar://problem/54153189>
7142 { "sat_Olck", TEST_ULDN_LOCALE, u"ᱥᱟᱱᱛᱟᱲᱤ (ᱚᱞ ᱪᱤᱠᱤ)" },
7143 { "sat_Deva", TEST_ULDN_LOCALE, u"ᱥᱟᱱᱛᱟᱲᱤ (ᱫᱮᱣᱟᱱᱟᱜᱟᱨᱤ)" },
7144 };
7145
7146 static const UldnItem sat_Deva_StdMidLong[] = { // Apple <rdar://problem/54153189>
7147 { "sat_Olck", TEST_ULDN_LOCALE, u"सानताड़ी (अल चीकी)" },
7148 { "sat_Deva", TEST_ULDN_LOCALE, u"सानताड़ी (देवानागारी)" },
7149 };
7150
7151 static const UldnItem en_AU_StdBegLong[] = { // Apple <rrdar://69835367>
7152 { "019", TEST_ULDN_REGION, u"Americas" },
7153 { "002", TEST_ULDN_REGION, u"Africa" },
7154 { "150", TEST_ULDN_REGION, u"Europe" },
7155 { "142", TEST_ULDN_REGION, u"Asia" },
7156 { "009", TEST_ULDN_REGION, u"Oceania" },
7157 };
7158
7159 static const UldnItem es_MX_StdBegLong[] = { // Apple <rrdar://69835367>
7160 { "019", TEST_ULDN_REGION, u"América" },
7161 { "002", TEST_ULDN_REGION, u"África" },
7162 { "150", TEST_ULDN_REGION, u"Europa" },
7163 { "142", TEST_ULDN_REGION, u"Asia" },
7164 { "009", TEST_ULDN_REGION, u"Oceanía" },
7165 };
7166
7167 static const UldnLocAndOpts uldnLocAndOpts[] = {
7168 { "en", optStdMidLong, en_StdMidLong, UPRV_LENGTHOF(en_StdMidLong) },
7169 { "en", optStdMidShrt, en_StdMidShrt, UPRV_LENGTHOF(en_StdMidShrt) },
7170 { "en", optDiaMidLong, en_DiaMidLong, UPRV_LENGTHOF(en_DiaMidLong) },
7171 { "en", optDiaMidShrt, en_DiaMidShrt, UPRV_LENGTHOF(en_DiaMidShrt) },
7172 { "en_CA", optDiaMidLong, en_CA_DiaMidLong, UPRV_LENGTHOF(en_CA_DiaMidLong) }, // <rdar://problem/60916890>
7173 { "en_CA", optDiaMidShrt, en_CA_DiaMidShrt, UPRV_LENGTHOF(en_CA_DiaMidShrt) }, // <rdar://problem/60916890>
7174 { "en_GB", optDiaMidLong, en_GB_DiaMidLong, UPRV_LENGTHOF(en_GB_DiaMidLong) }, // <rdar://problem/60916890>
7175 { "en_GB", optDiaMidShrt, en_GB_DiaMidShrt, UPRV_LENGTHOF(en_GB_DiaMidShrt) }, // <rdar://problem/60916890>
7176 { "en_IN", optStdMidLong, en_IN_StdMidLong, UPRV_LENGTHOF(en_IN_StdMidLong) }, // <rdar://problem/65959353>
7177 { "fr", optStdMidLong, fr_StdMidLong, UPRV_LENGTHOF(fr_StdMidLong) },
7178 { "fr", optStdMidShrt, fr_StdMidShrt, UPRV_LENGTHOF(fr_StdMidShrt) },
7179 { "fr", optStdBegLong, fr_StdBegLong, UPRV_LENGTHOF(fr_StdBegLong) },
7180 { "fr", optStdLstLong, fr_StdLstLong, UPRV_LENGTHOF(fr_StdLstLong) },
7181 { "fr_CA", optStdLstLong, fr_StdLstLong, UPRV_LENGTHOF(fr_StdLstLong) },
7182 { "fr", optDiaMidLong, fr_DiaMidLong, UPRV_LENGTHOF(fr_DiaMidLong) },
7183 { "ca", optStdLstLong, ca_StdLstLong, UPRV_LENGTHOF(ca_StdLstLong) },
7184 { "nb", optStdMidLong, nb_StdMidLong, UPRV_LENGTHOF(nb_StdMidLong) }, // <rdar://problem/65008672>
7185 { "ur", optStdMidLong, ur_StdMidLong, UPRV_LENGTHOF(ur_StdMidLong) },
7186 { "ur_Arab", optStdMidLong, ur_StdMidLong, UPRV_LENGTHOF(ur_StdMidLong) },
7187 { "ur_Aran", optStdMidLong, ur_StdMidLong, UPRV_LENGTHOF(ur_StdMidLong) },
7188 { "pa_Arab", optStdMidLong, pa_Arab_StdMidLong, UPRV_LENGTHOF(pa_Arab_StdMidLong) },
7189 { "pa_Aran", optStdMidLong, pa_Arab_StdMidLong, UPRV_LENGTHOF(pa_Arab_StdMidLong) },
7190 { "zh", optStdMidLong, zh_StdMidLong, UPRV_LENGTHOF(zh_StdMidLong) },
7191 { "yue_Hans", optStdMidLong, yue_Hans_StdMidLong, UPRV_LENGTHOF(yue_Hans_StdMidLong) },
7192 { "nds", optStdMidLong, nds_StdMidLong, UPRV_LENGTHOF(nds_StdMidLong) },
7193 { "hi", optStdMidLong, hi_StdMidLong, UPRV_LENGTHOF(hi_StdMidLong) },
7194 { "hi_Latn", optStdMidLong, hi_Latn_StdMidLong, UPRV_LENGTHOF(hi_Latn_StdMidLong) },
7195 { "mni_Beng", optStdMidLong, mni_Beng_StdMidLong, UPRV_LENGTHOF(mni_Beng_StdMidLong) },
7196 { "mni_Mtei", optStdMidLong, mni_Mtei_StdMidLong, UPRV_LENGTHOF(mni_Mtei_StdMidLong) },
7197 { "sat_Olck", optStdMidLong, sat_Olck_StdMidLong, UPRV_LENGTHOF(sat_Olck_StdMidLong) },
7198 { "sat_Deva", optStdMidLong, sat_Deva_StdMidLong, UPRV_LENGTHOF(sat_Deva_StdMidLong) },
7199 { "en_AU", optStdBegLong, en_AU_StdBegLong, UPRV_LENGTHOF(en_AU_StdBegLong) }, // <rdar://69835367>
7200 { "es_MX", optStdBegLong, es_MX_StdBegLong, UPRV_LENGTHOF(es_MX_StdBegLong) }, // <rdar://69835367>
7201 { NULL, NULL, NULL, 0 }
7202 };
7203
7204 enum { kUNameBuf = 128, kBNameBuf = 256 };
7205
7206 static void TestUldnNameVariants() {
7207 const UldnLocAndOpts * uloPtr;
7208 for (uloPtr = uldnLocAndOpts; uloPtr->displayLocale != NULL; uloPtr++) {
7209 UErrorCode status = U_ZERO_ERROR;
7210 ULocaleDisplayNames * uldn = uldn_openForContext(uloPtr->displayLocale, (UDisplayContext*)uloPtr->displayOptions, 3, &status);
7211 if (U_FAILURE(status)) {
7212 log_data_err("uldn_openForContext fails, displayLocale %s, contexts %03X %03X %03X: %s - Are you missing data?\n",
7213 uloPtr->displayLocale, uloPtr->displayOptions[0], uloPtr->displayOptions[1], uloPtr->displayOptions[2],
7214 u_errorName(status) );
7215 continue;
7216 }
7217 const UldnItem * itemPtr = uloPtr->testItems;
7218 int32_t itemCount = uloPtr->countItems;
7219 for (; itemCount-- > 0; itemPtr++) {
7220 UChar uget[kUNameBuf];
7221 int32_t ulenget, ulenexp;
7222 const char* typeString;
7223 status = U_ZERO_ERROR;
7224 switch (itemPtr->nameType) {
7225 case TEST_ULDN_LOCALE:
7226 ulenget = uldn_localeDisplayName(uldn, itemPtr->localeToName, uget, kUNameBuf, &status);
7227 typeString = "uldn_localeDisplayName";
7228 break;
7229 case TEST_ULDN_LANGUAGE:
7230 ulenget = uldn_languageDisplayName(uldn, itemPtr->localeToName, uget, kUNameBuf, &status);
7231 typeString = "uldn_languageDisplayName";
7232 break;
7233 case TEST_ULDN_SCRIPT:
7234 ulenget = uldn_scriptDisplayName(uldn, itemPtr->localeToName, uget, kUNameBuf, &status);
7235 typeString = "uldn_scriptDisplayName";
7236 break;
7237 case TEST_ULDN_REGION:
7238 ulenget = uldn_regionDisplayName(uldn, itemPtr->localeToName, uget, kUNameBuf, &status);
7239 typeString = "uldn_regionDisplayName";
7240 break;
7241 case TEST_ULOC_LOCALE:
7242 ulenget = uloc_getDisplayName(itemPtr->localeToName, uloPtr->displayLocale, uget, kUNameBuf, &status);
7243 typeString = "uloc_getDisplayName";
7244 break;
7245 case TEST_ULOC_LANGUAGE:
7246 ulenget = uloc_getDisplayLanguage(itemPtr->localeToName, uloPtr->displayLocale, uget, kUNameBuf, &status);
7247 typeString = "uloc_getDisplayLanguage";
7248 break;
7249 case TEST_ULOC_SCRIPT:
7250 ulenget = uloc_getDisplayScript(itemPtr->localeToName, uloPtr->displayLocale, uget, kUNameBuf, &status);
7251 typeString = "uloc_getDisplayScript";
7252 break;
7253 case TEST_ULOC_REGION:
7254 ulenget = uloc_getDisplayCountry(itemPtr->localeToName, uloPtr->displayLocale, uget, kUNameBuf, &status);
7255 typeString = "uloc_getDisplayCountry";
7256 break;
7257 default:
7258 continue;
7259 }
7260 if (U_FAILURE(status)) {
7261 log_data_err("%s fails, displayLocale %s, contexts %03X %03X %03X, localeToName %s: %s\n",
7262 typeString, uloPtr->displayLocale, uloPtr->displayOptions[0], uloPtr->displayOptions[1], uloPtr->displayOptions[2],
7263 itemPtr->localeToName, u_errorName(status) );
7264 continue;
7265 }
7266 ulenexp = u_strlen(itemPtr->expectResult);
7267 if (ulenget != ulenexp || u_strncmp(uget, itemPtr->expectResult, ulenexp) != 0) {
7268 char bexp[kBNameBuf], bget[kBNameBuf];
7269 u_strToUTF8(bexp, kBNameBuf, NULL, itemPtr->expectResult, ulenexp, &status);
7270 u_strToUTF8(bget, kBNameBuf, NULL, uget, ulenget, &status);
7271 log_data_err("%s fails, displayLocale %s, contexts %03X %03X %03X, localeToName %s:\n expect %2d: %s\n get %2d: %s\n",
7272 typeString, uloPtr->displayLocale, uloPtr->displayOptions[0], uloPtr->displayOptions[1], uloPtr->displayOptions[2],
7273 itemPtr->localeToName, ulenexp, bexp, ulenget, bget );
7274 }
7275 }
7276
7277 uldn_close(uldn);
7278 }
7279 }
7280
7281 #define ULOC_UND_TESTNUM 9
7282
7283 static const char* for_empty[ULOC_UND_TESTNUM] = { // ""
7284 "", // uloc_getName
7285 "", // uloc_getLanguage
7286 "en_Latn_US_POSIX", // uloc_addLikelySubtags
7287 "en__POSIX", // uloc_minimizeSubtags
7288 "en_US_POSIX", // uloc_canonicalize
7289 "", // uloc_getParent
7290 "und", // uloc_toLanguageTag
7291 "", // uloc_getDisplayName in en
7292 "", // uloc_getDisplayLanguage in en
7293 };
7294 static const char* for_root[ULOC_UND_TESTNUM] = { // "root"
7295 "root", // uloc_getName
7296 "root", // uloc_getLanguage
7297 "root", // uloc_addLikelySubtags
7298 "root", // uloc_minimizeSubtags
7299 "root", // uloc_canonicalize
7300 "", // uloc_getParent
7301 "root", // uloc_toLanguageTag
7302 "Root", // uloc_getDisplayName in en
7303 "Root", // uloc_getDisplayLanguage in en
7304 };
7305 static const char* for_und[ULOC_UND_TESTNUM] = { // "und"
7306 "und", // uloc_getName
7307 "und", // uloc_getLanguage
7308 "en_Latn_US", // uloc_addLikelySubtags
7309 "und", // uloc_minimizeSubtags
7310 "und", // uloc_canonicalize
7311 "", // uloc_getParent
7312 "und", // uloc_toLanguageTag
7313 "Unknown language", // uloc_getDisplayName in en
7314 "Unknown language", // uloc_getDisplayLanguage in en
7315 };
7316 static const char* for_und_ZZ[ULOC_UND_TESTNUM] = { // "und_ZZ"
7317 "und_ZZ", // uloc_getName
7318 "und", // uloc_getLanguage
7319 "en_Latn_US", // uloc_addLikelySubtags
7320 "und", // uloc_minimizeSubtags
7321 "und_ZZ", // uloc_canonicalize
7322 "und", // uloc_getParent
7323 "und-ZZ", // uloc_toLanguageTag
7324 "Unknown language (Unknown Region)", // uloc_getDisplayName in en
7325 "Unknown language", // uloc_getDisplayLanguage in en
7326 };
7327 static const char* for_empty_ZZ[ULOC_UND_TESTNUM] = { // "_ZZ"
7328 "_ZZ", // uloc_getName
7329 "", // uloc_getLanguage
7330 "en_Latn_US", // uloc_addLikelySubtags
7331 "und", // uloc_minimizeSubtags
7332 "_ZZ", // uloc_canonicalize
7333 "", // uloc_getParent
7334 "und-ZZ", // uloc_toLanguageTag
7335 "Unknown Region", // uloc_getDisplayName in en
7336 "", // uloc_getDisplayLanguage in en
7337 };
7338
7339 typedef struct {
7340 const char * locale;
7341 const char ** expResults;
7342 } RootUndEmptyItem;
7343
7344 static const RootUndEmptyItem rootUndEmptryItems[] = {
7345 { "", for_empty },
7346 { "root", for_root },
7347 { "und", for_und },
7348 { "und_ZZ", for_und_ZZ },
7349 { "_ZZ", for_empty_ZZ },
7350 { NULL, NULL }
7351 };
7352
7353 enum { kULocMax = 64, kBLocMax = 128 };
7354
7355 static void TestRootUndEmpty() {
7356 const RootUndEmptyItem* itemPtr;
7357 for (itemPtr = rootUndEmptryItems; itemPtr->locale != NULL; itemPtr++) {
7358 const char* loc = itemPtr->locale;
7359 const char** expResultsPtr = itemPtr->expResults;
7360 const char* bexp;
7361 char bget[kBLocMax];
7362 UChar uexp[kULocMax];
7363 UChar uget[kULocMax];
7364 int32_t ulen, blen;
7365 UErrorCode status;
7366
7367 status = U_ZERO_ERROR;
7368 bexp = *expResultsPtr++;
7369 blen = uloc_getName(loc, bget, kBLocMax, &status);
7370 if (U_FAILURE(status)) {
7371 log_err("loc \"%s\", uloc_getName status: %s\n", loc, u_errorName(status) );
7372 } else if (uprv_strcmp(bget, bexp) != 0) {
7373 log_err("loc \"%s\", uloc_getName expect \"%s\", get \"%s\"\n", loc, bexp, bget );
7374 }
7375
7376 status = U_ZERO_ERROR;
7377 bexp = *expResultsPtr++;
7378 blen = uloc_getLanguage(loc, bget, kBLocMax, &status);
7379 if (U_FAILURE(status)) {
7380 log_err("loc \"%s\", uloc_getLanguage status: %s\n", loc, u_errorName(status) );
7381 } else if (uprv_strcmp(bget, bexp) != 0) {
7382 log_err("loc \"%s\", uloc_getLanguage expect \"%s\", get \"%s\"\n", loc, bexp, bget );
7383 }
7384
7385 status = U_ZERO_ERROR;
7386 bexp = *expResultsPtr++;
7387 blen = uloc_addLikelySubtags(loc, bget, kBLocMax, &status);
7388 if (U_FAILURE(status)) {
7389 log_err("loc \"%s\", uloc_addLikelySubtags status: %s\n", loc, u_errorName(status) );
7390 } else if (uprv_strcmp(bget, bexp) != 0) {
7391 log_err("loc \"%s\", uloc_addLikelySubtags expect \"%s\", get \"%s\"\n", loc, bexp, bget );
7392 }
7393
7394 status = U_ZERO_ERROR;
7395 bexp = *expResultsPtr++;
7396 blen = uloc_minimizeSubtags(loc, bget, kBLocMax, &status);
7397 if (U_FAILURE(status)) {
7398 log_err("loc \"%s\", uloc_minimizeSubtags status: %s\n", loc, u_errorName(status) );
7399 } else if (uprv_strcmp(bget, bexp) != 0) {
7400 log_err("loc \"%s\", uloc_minimizeSubtags expect \"%s\", get \"%s\"\n", loc, bexp, bget );
7401 }
7402
7403 status = U_ZERO_ERROR;
7404 bexp = *expResultsPtr++;
7405 blen = uloc_canonicalize(loc, bget, kBLocMax, &status);
7406 if (U_FAILURE(status)) {
7407 log_err("loc \"%s\", uloc_canonicalize status: %s\n", loc, u_errorName(status) );
7408 } else if (uprv_strcmp(bget, bexp) != 0) {
7409 log_err("loc \"%s\", uloc_canonicalize expect \"%s\", get \"%s\"\n", loc, bexp, bget );
7410 }
7411
7412 status = U_ZERO_ERROR;
7413 bexp = *expResultsPtr++;
7414 blen = uloc_getParent(loc, bget, kBLocMax, &status);
7415 if (U_FAILURE(status)) {
7416 log_err("loc \"%s\", uloc_getParent status: %s\n", loc, u_errorName(status) );
7417 } else if (uprv_strcmp(bget, bexp) != 0) {
7418 log_err("loc \"%s\", uloc_getParent expect \"%s\", get \"%s\"\n", loc, bexp, bget );
7419 }
7420
7421 status = U_ZERO_ERROR;
7422 bexp = *expResultsPtr++;
7423 blen = uloc_toLanguageTag(loc, bget, kBLocMax, TRUE, &status);
7424 if (U_FAILURE(status)) {
7425 log_err("loc \"%s\", uloc_toLanguageTag status: %s\n", loc, u_errorName(status) );
7426 } else if (uprv_strcmp(bget, bexp) != 0) {
7427 log_err("loc \"%s\", uloc_toLanguageTag expect \"%s\", get \"%s\"\n", loc, bexp, bget );
7428 }
7429
7430 status = U_ZERO_ERROR;
7431 bexp = *expResultsPtr++;
7432 u_unescape(bexp, uexp, kULocMax);
7433 uexp[kULocMax-1] = 0; // force zero term
7434 ulen = uloc_getDisplayName(loc, "en", uget, kULocMax, &status);
7435 if (U_FAILURE(status)) {
7436 log_err("loc \"%s\", uloc_getDisplayName en status: %s\n", loc, u_errorName(status) );
7437 } else if (u_strcmp(uget, uexp) != 0) {
7438 u_austrncpy(bget, uget, kBLocMax);
7439 bget[kBLocMax-1] = 0;
7440 log_err("loc \"%s\", uloc_getDisplayName en expect \"%s\", get \"%s\"\n", loc, bexp, bget );
7441 }
7442
7443 status = U_ZERO_ERROR;
7444 bexp = *expResultsPtr++;
7445 u_unescape(bexp, uexp, kULocMax);
7446 uexp[kULocMax-1] = 0; // force zero term
7447 ulen = uloc_getDisplayLanguage(loc, "en", uget, kULocMax, &status);
7448 if (U_FAILURE(status)) {
7449 log_err("loc \"%s\", uloc_getDisplayLanguage en status: %s\n", loc, u_errorName(status) );
7450 } else if (u_strcmp(uget, uexp) != 0) {
7451 u_austrncpy(bget, uget, kBLocMax);
7452 bget[kBLocMax-1] = 0;
7453 log_err("loc \"%s\", uloc_getDisplayLanguage en expect \"%s\", get \"%s\"\n", loc, bexp, bget );
7454 }
7455 }
7456 }
7457
7458
7459 #if !U_PLATFORM_HAS_WIN32_API
7460 /* Apple-specific, test for Apple-specific function ualoc_getAppleParent */
7461 static const char* localesAndAppleParent[] = {
7462 "en", "root",
7463 "en-US", "en",
7464 "en-CA", "en_001",
7465 "en-CN", "en",
7466 "en-JP", "en",
7467 "en-TW", "en",
7468 "en-001", "en",
7469 "en_001", "en",
7470 "en-150", "en_GB",
7471 "en-GB", "en_001",
7472 "en_GB", "en_001",
7473 "en-AU", "en_GB",
7474 "en-BE", "en_150",
7475 "en-DG", "en_GB",
7476 "en-FK", "en_GB",
7477 "en-GG", "en_GB",
7478 "en-GI", "en_GB",
7479 "en-HK", "en_GB",
7480 "en-IE", "en_GB",
7481 "en-IM", "en_GB",
7482 "en-IN", "en_GB",
7483 "en-IO", "en_GB",
7484 "en-JE", "en_GB",
7485 "en-JM", "en_GB",
7486 "en-MO", "en_GB",
7487 "en-MT", "en_GB",
7488 "en-MV", "en_GB",
7489 "en-NZ", "en_AU",
7490 "en-PK", "en_GB",
7491 "en-SG", "en_GB",
7492 "en-SH", "en_GB",
7493 "en-VG", "en_GB",
7494 "es", "root",
7495 "es-ES", "es",
7496 "es-419", "es",
7497 "es_419", "es",
7498 "es-MX", "es_419",
7499 "es-AR", "es_419",
7500 "es-BR", "es_419",
7501 "es-BZ", "es_419",
7502 "es-AG", "es_419",
7503 "es-AW", "es_419",
7504 "es-CA", "es_419",
7505 "es-CW", "es_419",
7506 "es-SX", "es_419",
7507 "es-TT", "es_419",
7508 "fr", "root",
7509 "fr-CA", "fr",
7510 "fr-CH", "fr",
7511 "haw", "root",
7512 "nl", "root",
7513 "nl-BE", "nl",
7514 "pt", "root",
7515 "pt-BR", "pt",
7516 "pt-PT", "pt",
7517 "pt-MO", "pt_PT",
7518 "pt-CH", "pt_PT",
7519 "pt-GQ", "pt_PT",
7520 "pt-LU", "pt_PT",
7521 "sr", "root",
7522 "sr-Cyrl", "sr",
7523 "sr-Latn", "root",
7524 "tlh", "root",
7525 "zh_CN", "root",
7526 "zh-CN", "root",
7527 "zh", "zh_CN",
7528 "zh-Hans", "zh",
7529 "zh_TW", "root",
7530 "zh-TW", "root",
7531 "zh-Hant", "zh_TW",
7532 "zh_HK", "zh_Hant_HK",
7533 "zh-HK", "zh_Hant_HK",
7534 "zh_Hant", "zh_TW",
7535 "zh-Hant-HK", "zh_Hant",
7536 "zh_Hant_HK", "zh_Hant",
7537 "zh-Hant-MO", "zh_Hant_HK",
7538 "zh-Hans-HK", "zh_Hans",
7539 "root", "root",
7540 "en-Latn", "en",
7541 "en-Latn-US", "en_Latn",
7542 "en_US_POSIX", "en_US",
7543 "en_Latn_US_POSIX", "en_Latn_US",
7544 "en-u-ca-hebrew", "root",
7545 "en@calendar=hebrew", "root",
7546 "en_@calendar=hebrew", "root",
7547 "en-", "root",
7548 "en_", "root",
7549 "Default@2x", "root",
7550 "default", "root",
7551 NULL /* terminator */
7552 };
7553
7554 static void TestGetAppleParent() {
7555 const char **localesPtr = localesAndAppleParent;
7556 const char * locale;
7557 while ((locale = *localesPtr++) != NULL) {
7558 const char * expectParent = *localesPtr++;
7559 UErrorCode status = U_ZERO_ERROR;
7560 char getParent[ULOC_FULLNAME_CAPACITY];
7561 int32_t plen = ualoc_getAppleParent(locale, getParent, ULOC_FULLNAME_CAPACITY, &status);
7562 if (U_FAILURE(status)) {
7563 log_err("FAIL: ualoc_getAppleParent input \"%s\", status %s\n", locale, u_errorName(status));
7564 } else if (uprv_strcmp(expectParent, getParent) != 0) {
7565 log_err("FAIL: ualoc_getAppleParent input \"%s\", expected parent \"%s\", got parent \"%s\"\n", locale, expectParent, getParent);
7566 }
7567 }
7568 }
7569
7570 /* Apple-specific, test for Apple-specific function ualoc_getLanguagesForRegion */
7571 enum { kUALanguageEntryMin = 10, kUALanguageEntryMax = 20 };
7572
7573 static void TestGetLanguagesForRegion() {
7574 UALanguageEntry entries[kUALanguageEntryMax];
7575 int32_t entryCount;
7576 UErrorCode status;
7577 const char * region;
7578
7579 status = U_ZERO_ERROR;
7580 region = "CN";
7581 entryCount = ualoc_getLanguagesForRegion(region, 0.001, entries, kUALanguageEntryMin, &status);
7582 if (U_FAILURE(status)) {
7583 log_err("FAIL: ualoc_getLanguagesForRegion %s, status %s\n", region, u_errorName(status));
7584 } else {
7585 // Expect approximately:
7586 // zh_Hans 0.90 UALANGSTATUS_OFFICIAL
7587 // wuu 0.06 Wu
7588 // hsn 0.06 Xiang
7589 // yue 0.043 Yue including Cantonese
7590 // hak 0.023 Hakka
7591 // nan 0.019 Minnan
7592 // gan 0.017 Gan
7593 // ii 0.006 Yi
7594 // ug_Arab 0.0055 Uighur UALANGSTATUS_REGIONAL_OFFICIAL
7595 // ...at least 4 more with fractions >= 0.001
7596 if (entryCount < kUALanguageEntryMin) {
7597 log_err("FAIL: ualoc_getLanguagesForRegion %s, entryCount %d is too small\n", region, entryCount);
7598 } else {
7599 UALanguageEntry* entryPtr = entries;
7600 if (uprv_strcmp(entryPtr->languageCode, "zh_Hans") != 0 || entryPtr->userFraction < 0.8 || entryPtr->userFraction > 1.0 || entryPtr->status != UALANGSTATUS_OFFICIAL) {
7601 log_err("FAIL: ualoc_getLanguagesForRegion %s, invalid entries[0] { %s, %.3f, %d }\n", region, entryPtr->languageCode, entryPtr->userFraction, (int)entryPtr->status);
7602 }
7603 for (entryPtr++; entryPtr < entries + kUALanguageEntryMin && uprv_strcmp(entryPtr->languageCode, "ug_Arab") != 0; entryPtr++)
7604 ;
7605 if (entryPtr < entries + kUALanguageEntryMin) {
7606 // we found ug_Arab, make sure it has correct status
7607 if (entryPtr->status != UALANGSTATUS_REGIONAL_OFFICIAL) {
7608 log_err("FAIL: ualoc_getLanguagesForRegion %s, ug_Arab had incorrect status %d\n", (int)entryPtr->status);
7609 }
7610 } else {
7611 // did not find ug_Arab
7612 log_err("FAIL: ualoc_getLanguagesForRegion %s, entries did not include ug_Arab\n", region);
7613 }
7614 }
7615 }
7616
7617 status = U_ZERO_ERROR;
7618 region = "CA";
7619 entryCount = ualoc_getLanguagesForRegion(region, 0.001, entries, kUALanguageEntryMin, &status);
7620 if (U_FAILURE(status)) {
7621 log_err("FAIL: ualoc_getLanguagesForRegion %s, status %s\n", region, u_errorName(status));
7622 } else {
7623 // Expect approximately:
7624 // en 0.85 UALANGSTATUS_OFFICIAL
7625 // fr 0.22 UALANGSTATUS_OFFICIAL
7626 // ...
7627 if (entryCount < 2) {
7628 log_err("FAIL: ualoc_getLanguagesForRegion %s, entryCount %d is too small\n", region, entryCount);
7629 } else {
7630 if (uprv_strcmp(entries[0].languageCode, "en") != 0 || entries[0].userFraction < 0.7 || entries[0].userFraction > 1.0 || entries[0].status != UALANGSTATUS_OFFICIAL) {
7631 log_err("FAIL: ualoc_getLanguagesForRegion %s, invalid entries[0] { %s, %.3f, %d }\n", region, entries[0].languageCode, entries[0].userFraction, (int)entries[0].status);
7632 }
7633 if (uprv_strcmp(entries[1].languageCode, "fr") != 0 || entries[1].userFraction < 0.1 || entries[1].userFraction > 1.0 || entries[1].status != UALANGSTATUS_OFFICIAL) {
7634 log_err("FAIL: ualoc_getLanguagesForRegion %s, invalid entries[1] { %s, %.3f, %d }\n", region, entries[1].languageCode, entries[1].userFraction, (int)entries[1].status);
7635 }
7636 }
7637 }
7638
7639 status = U_ZERO_ERROR;
7640 region = "IN";
7641 entryCount = ualoc_getLanguagesForRegion(region, 0.001, NULL, 0, &status);
7642 if (U_FAILURE(status)) {
7643 log_err("FAIL: ualoc_getLanguagesForRegion %s, status %s\n", region, u_errorName(status));
7644 } else {
7645 if (entryCount < 40) {
7646 log_err("FAIL: ualoc_getLanguagesForRegion %s, entryCount %d is too small\n", region, entryCount);
7647 }
7648 }
7649
7650 status = U_ZERO_ERROR;
7651 region = "FO";
7652 entryCount = ualoc_getLanguagesForRegion(region, 0.001, entries, kUALanguageEntryMin, &status);
7653 if (U_FAILURE(status)) {
7654 log_err("FAIL: ualoc_getLanguagesForRegion %s, status %s\n", region, u_errorName(status));
7655 } else {
7656 // Expect approximately:
7657 // fo 0.93 UALANGSTATUS_OFFICIAL
7658 // da 0.03 UALANGSTATUS_OFFICIAL
7659 // ...
7660 if (entryCount < 2) {
7661 log_err("FAIL: ualoc_getLanguagesForRegion %s, entryCount %d is too small\n", region, entryCount);
7662 } else {
7663 if (uprv_strcmp(entries[0].languageCode, "fo") != 0 || entries[0].userFraction < 0.90 || entries[0].userFraction > 0.98 || entries[0].status != UALANGSTATUS_OFFICIAL) {
7664 log_err("FAIL: ualoc_getLanguagesForRegion %s, invalid entries[0] { %s, %.3f, %d }\n", region, entries[0].languageCode, entries[0].userFraction, (int)entries[0].status);
7665 }
7666 if (uprv_strcmp(entries[1].languageCode, "da") != 0 || entries[1].userFraction < 0.02 || entries[1].userFraction > 0.04 || entries[1].status != UALANGSTATUS_OFFICIAL) {
7667 log_err("FAIL: ualoc_getLanguagesForRegion %s, invalid entries[1] { %s, %.3f, %d }\n", region, entries[1].languageCode, entries[1].userFraction, (int)entries[1].status);
7668 }
7669 }
7670 }
7671
7672 status = U_ZERO_ERROR;
7673 region = "ID";
7674 entryCount = ualoc_getLanguagesForRegion(region, 0.0075, entries, kUALanguageEntryMax, &status);
7675 if (U_FAILURE(status)) {
7676 log_err("FAIL: ualoc_getLanguagesForRegion %s, status %s\n", region, u_errorName(status));
7677 } else {
7678 // Expect about 15 entries, the last should be for ms_Arab with a fraction < 0.01 // <rdar://problem/27943264>
7679 if (entryCount < 10) {
7680 log_err("FAIL: ualoc_getLanguagesForRegion %s with minFraction=0.0075, entryCount %d is too small\n", region, entryCount);
7681 } else {
7682 if (uprv_strcmp(entries[entryCount-1].languageCode, "ms_Arab") != 0 || entries[entryCount-1].userFraction >= 0.01) {
7683 log_err("FAIL: ualoc_getLanguagesForRegion %s, invalid entries[entryCount-1] { %s, %.3f, %d }\n",
7684 region, entries[entryCount-1].languageCode, entries[entryCount-1].userFraction, (int)entries[entryCount-1].status);
7685 }
7686 }
7687 }
7688 }
7689
7690
7691 #if U_PLATFORM_IS_DARWIN_BASED
7692 #include <unistd.h>
7693 #include <mach/mach_time.h>
7694 #define GET_START() mach_absolute_time()
7695 #define GET_DURATION(start, info) ((mach_absolute_time() - start) * info.numer)/info.denom
7696 #else
7697 // Here we already know !U_PLATFORM_HAS_WIN32_API is true
7698 // So the following is for Linux
7699 #include <unistd.h>
7700 #include "putilimp.h"
7701 #define GET_START() (uint64_t)uprv_getUTCtime()
7702 #define GET_DURATION(start, info) ((uint64_t)uprv_getUTCtime() - start)
7703 #endif
7704
7705 enum { kMaxLocsToUse = 8 };
7706 static void TestAppleLocalizationsToUsePerf() { // <rdar://problem/62458844&63471438>
7707 static const char* preferredLangs[] = {"zh_Hans","pt_BR","fr_BE"};
7708 static const char* availableLocs[] = {"ar","de","en","en_AU","en_GB","es","es_419","fr","fr_CA","it","ja","ko","nl","no","pt","pt_PT","ru","zh_CN","zh_HK","zh_TW"};
7709 const char * locsToUse[kMaxLocsToUse];
7710 UErrorCode status;
7711 int32_t numLocsToUse;
7712 uint64_t start, duration;
7713 #if U_PLATFORM_IS_DARWIN_BASED
7714 mach_timebase_info_data_t info;
7715 mach_timebase_info(&info);
7716 #endif
7717
7718 log_info("sleeping 10 sec to check heap before...\n");
7719 sleep(10);
7720 status = U_ZERO_ERROR;
7721 start = GET_START();
7722 numLocsToUse = ualoc_localizationsToUse(preferredLangs, UPRV_LENGTHOF(preferredLangs),
7723 availableLocs, UPRV_LENGTHOF(availableLocs),
7724 locsToUse, kMaxLocsToUse, &status);
7725 duration = GET_DURATION(start, info);
7726 log_info("ualoc_localizationsToUse first use nsec %llu; status %s, numLocsToUse %d: %s ...\n",
7727 duration, u_errorName(status), numLocsToUse, (numLocsToUse>=0)? locsToUse[0]: "");
7728 log_info("sleeping 10 sec to check heap after...\n");
7729 sleep(10);
7730
7731 status = U_ZERO_ERROR;
7732 start = GET_START();
7733 numLocsToUse = ualoc_localizationsToUse(preferredLangs, UPRV_LENGTHOF(preferredLangs),
7734 availableLocs, UPRV_LENGTHOF(availableLocs),
7735 locsToUse, kMaxLocsToUse, &status);
7736 duration = GET_DURATION(start, info);
7737 log_info("ualoc_localizationsToUse second use nsec %llu; status %s, numLocsToUse %d\n",
7738 duration, u_errorName(status), numLocsToUse);
7739 }
7740
7741 /* data for TestAppleLocalizationsToUse */
7742
7743 typedef struct {
7744 const char * const *locs;
7745 int32_t locCount;
7746 } AppleLocsAndCount;
7747
7748 enum { kNumLocSets = 6 };
7749
7750 typedef struct {
7751 const char * language;
7752 const char ** expLocsForSets[kNumLocSets];
7753 } LangAndExpLocs;
7754
7755
7756 static const char * appleLocs1[] = {
7757 "Arabic",
7758 "Danish",
7759 "Dutch",
7760 "English",
7761 "Finnish",
7762 "French",
7763 "German",
7764 "Italian",
7765 "Japanese",
7766 "Korean",
7767 "Norwegian",
7768 "Polish",
7769 "Portuguese",
7770 "Russian",
7771 "Spanish",
7772 "Swedish",
7773 "Thai",
7774 "Turkish",
7775 "ca",
7776 "cs",
7777 "el",
7778 "he",
7779 "hr",
7780 "hu",
7781 "id",
7782 "ms",
7783 "ro",
7784 "sk",
7785 "uk",
7786 "vi",
7787 "zh_CN", "zh_TW",
7788 };
7789
7790 static const char * appleLocs2[] = {
7791 "ar",
7792 "ca",
7793 "cs",
7794 "da",
7795 "de",
7796 "el",
7797 "en", "en_AU", "en_GB",
7798 "es", "es_MX",
7799 "fi",
7800 "fr", "fr_CA",
7801 "he",
7802 "hr",
7803 "hu",
7804 "id",
7805 "it",
7806 "ja",
7807 "ko",
7808 "ms",
7809 "nl",
7810 "no",
7811 "pl",
7812 "pt", "pt_PT",
7813 "ro",
7814 "ru",
7815 "sk",
7816 "sv",
7817 "th",
7818 "tr",
7819 "uk",
7820 "vi",
7821 "zh_CN", "zh_HK", "zh_TW",
7822 };
7823
7824 static const char * appleLocs3[] = {
7825 "ar",
7826 "ca",
7827 "cs",
7828 "da",
7829 "de",
7830 "el",
7831 "en", "en_AU", "en_CA", "en_GB",
7832 "es", "es_419",
7833 "fi",
7834 "fr", "fr_CA", "fr_FR",
7835 "he",
7836 "hr",
7837 "hu",
7838 "id",
7839 "it", "it_CH", // <rdar://problem/35829322>
7840 "ja",
7841 "ko",
7842 "ms",
7843 "nb",
7844 "nl",
7845 "pl",
7846 "pt", "pt_BR", "pt_PT",
7847 "ro",
7848 "ru",
7849 "sk",
7850 "sv",
7851 "th",
7852 "tr",
7853 "uk",
7854 "vi",
7855 "zh_CN", "zh_HK", "zh_MO", "zh_TW",
7856 };
7857
7858 static const char * appleLocs4[] = {
7859 "en", "en_AU", "en_CA", "en_GB", "en_IN", "en_US",
7860 "es", "es_419", "es_MX",
7861 "fr", "fr_CA", "fr_CH", "fr_FR",
7862 "it", "it_CH", "it_IT", // <rdar://problem/35829322>
7863 "nl", "nl_BE", "nl_NL",
7864 "pt", "pt_BR",
7865 "ro", "ro_MD", "ro_RO",
7866 "zh_Hans", "zh_Hant", "zh_Hant_HK",
7867 };
7868
7869 static const char * appleLocs5[] = {
7870 "en", "en_001", "en_AU", "en_GB",
7871 "es", "es_ES", "es_MX",
7872 "zh_CN", "zh_Hans", "zh_Hant", "zh_TW",
7873 "yi",
7874 "fil",
7875 "haw",
7876 "tlh",
7877 "sr",
7878 "sr-Latn",
7879 };
7880
7881 // list 6
7882 static const char * appleLocs6[] = {
7883 "en", "en_001", "en_150", "en_AU", "en_GB",
7884 "es", "es_419", "es_ES", "es_MX",
7885 "zh_CN", "zh_Hans", "zh_Hant", "zh_Hant_HK", "zh_HK", "zh_TW",
7886 "iw",
7887 "in",
7888 "mo",
7889 "tl",
7890 };
7891
7892 static const AppleLocsAndCount locAndCountEntries[kNumLocSets] = {
7893 { appleLocs1, UPRV_LENGTHOF(appleLocs1) },
7894 { appleLocs2, UPRV_LENGTHOF(appleLocs2) },
7895 { appleLocs3, UPRV_LENGTHOF(appleLocs3) },
7896 { appleLocs4, UPRV_LENGTHOF(appleLocs4) },
7897 { appleLocs5, UPRV_LENGTHOF(appleLocs5) },
7898 { appleLocs6, UPRV_LENGTHOF(appleLocs6) },
7899 };
7900
7901
7902 static const char* l1_ar[] = { "ar", NULL };
7903 static const char* l1_Ara[] = { "Arabic", NULL };
7904 static const char* l1_ca[] = { "ca", NULL };
7905 static const char* l1_cs[] = { "cs", NULL };
7906 static const char* l1_da[] = { "da", NULL };
7907 static const char* l1_Dan[] = { "Danish", NULL };
7908 static const char* l1_de[] = { "de", NULL };
7909 static const char* l1_Ger[] = { "German", NULL };
7910 static const char* l1_el[] = { "el", NULL };
7911 static const char* l1_en[] = { "en", NULL };
7912 static const char* l1_Eng[] = { "English", NULL };
7913 static const char* l2_en_001_[] = { "en_001", "en", NULL };
7914 static const char* l2_en_CA_[] = { "en_CA", "en", NULL };
7915 static const char* l2_en_GB_[] = { "en_GB", "en", NULL };
7916 static const char* l2_en_US_[] = { "en_US", "en", NULL };
7917 static const char* l2_en_GB_Eng[] = { "en_GB", "English", NULL };
7918 static const char* l3_en_GB001_[] = { "en_GB", "en_001", "en", NULL };
7919 static const char* l3_en_AUGB_[] = { "en_AU", "en_GB", "en", NULL };
7920 static const char* l3_en_INGB_[] = { "en_IN", "en_GB", "en", NULL };
7921 static const char* l4_en_150GB001_[] = { "en_150", "en_GB", "en_001", "en", NULL };
7922 static const char* l4_en_AUGB001_[] = { "en_AU", "en_GB", "en_001", "en", NULL };
7923 static const char* l1_es[] = { "es", NULL };
7924 static const char* l1_Spa[] = { "Spanish", NULL };
7925 static const char* l2_es_419_[] = { "es_419", "es", NULL };
7926 static const char* l2_es_ES_[] = { "es_ES", "es", NULL };
7927 static const char* l2_es_MX_[] = { "es_MX", "es", NULL };
7928 static const char* l2_es_MX_Spa[] = { "es_MX", "Spanish", NULL };
7929 static const char* l3_es_MX419_[] = { "es_MX", "es_419", "es", NULL };
7930 static const char* l1_fi[] = { "fi", NULL };
7931 static const char* l1_Fin[] = { "Finnish", NULL };
7932 static const char* l1_fil[] = { "fil", NULL };
7933 static const char* l1_tl[] = { "tl", NULL };
7934 static const char* l1_fr[] = { "fr", NULL };
7935 static const char* l1_Fre[] = { "French", NULL };
7936 static const char* l2_fr_CA_[] = { "fr_CA", "fr", NULL };
7937 static const char* l2_fr_CH_[] = { "fr_CH", "fr", NULL };
7938 static const char* l2_fr_FR_[] = { "fr_FR", "fr", NULL };
7939 static const char* l1_haw[] = { "haw", NULL };
7940 static const char* l1_he[] = { "he", NULL };
7941 static const char* l1_hr[] = { "hr", NULL };
7942 static const char* l1_hu[] = { "hu", NULL };
7943 static const char* l1_id[] = { "id", NULL };
7944 static const char* l1_in[] = { "in", NULL };
7945 static const char* l1_it[] = { "it", NULL };
7946 static const char* l2_it_CH[] = { "it_CH", "it", NULL }; // <rdar://problem/35829322>
7947 static const char* l2_it_IT[] = { "it_IT", "it", NULL }; // <rdar://problem/35829322>
7948 static const char* l1_Ita[] = { "Italian", NULL };
7949 static const char* l1_ja[] = { "ja", NULL };
7950 static const char* l1_Japn[] = { "Japanese", NULL };
7951 static const char* l1_ko[] = { "ko", NULL };
7952 static const char* l1_Kor[] = { "Korean", NULL };
7953 static const char* l1_ms[] = { "ms", NULL };
7954 static const char* l1_nb[] = { "nb", NULL };
7955 static const char* l1_no[] = { "no", NULL };
7956 static const char* l1_Nor[] = { "Norwegian", NULL };
7957 static const char* l2_no_NO_[] = { "no_NO", "no", NULL };
7958 static const char* l1_nl[] = { "nl", NULL };
7959 static const char* l1_Dut[] = { "Dutch", NULL };
7960 static const char* l2_nl_BE_[] = { "nl_BE", "nl", NULL };
7961 static const char* l1_pl[] = { "pl", NULL };
7962 static const char* l1_Pol[] = { "Polish", NULL };
7963 static const char* l1_pt[] = { "pt", NULL };
7964 static const char* l1_pt_PT[] = { "pt_PT", NULL };
7965 static const char* l1_Port[] = { "Portuguese", NULL };
7966 static const char* l2_pt_BR_[] = { "pt_BR", "pt", NULL };
7967 static const char* l2_pt_PT_[] = { "pt_PT", "pt", NULL };
7968 static const char* l1_ro[] = { "ro", NULL };
7969 static const char* l2_ro_MD_[] = { "ro_MD", "ro", NULL };
7970 static const char* l1_mo[] = { "mo", NULL };
7971 static const char* l1_ru[] = { "ru", NULL };
7972 static const char* l1_Rus[] = { "Russian", NULL };
7973 static const char* l1_sk[] = { "sk", NULL };
7974 static const char* l1_sr[] = { "sr", NULL };
7975 static const char* l1_srLatn[] = { "sr-Latn", NULL };
7976 static const char* l1_sv[] = { "sv", NULL };
7977 static const char* l1_Swe[] = { "Swedish", NULL };
7978 static const char* l1_th[] = { "th", NULL };
7979 static const char* l1_Thai[] = { "Thai", NULL };
7980 static const char* l1_tlh[] = { "tlh", NULL };
7981 static const char* l1_tr[] = { "tr", NULL };
7982 static const char* l1_Tur[] = { "Turkish", NULL };
7983 static const char* l1_uk[] = { "uk", NULL };
7984 static const char* l1_vi[] = { "vi", NULL };
7985 static const char* l1_yi[] = { "yi", NULL };
7986 static const char* l1_iw[] = { "iw", NULL };
7987 static const char* l1_zh_CN[] = { "zh_CN", NULL };
7988 static const char* l1_zh_TW[] = { "zh_TW", NULL };
7989 static const char* l1_zh_HK[] = { "zh_HK", NULL };
7990 static const char* l1_zh_Hans[] = { "zh_Hans", NULL };
7991 static const char* l1_zh_Hant[] = { "zh_Hant", NULL };
7992 static const char* l1_zhHant[] = { "zh-Hant", NULL };
7993 static const char* l2_zh_HKTW[] = { "zh_HK", "zh_TW", NULL };
7994 static const char* l2_zh_Hant_HK_[] = { "zh_Hant_HK", "zh_Hant", NULL };
7995 static const char* l2_zh_CN_Hans[] = { "zh_CN", "zh_Hans", NULL };
7996 static const char* l2_zh_TW_Hant[] = { "zh_TW", "zh_Hant", NULL };
7997 static const char* l2_zh_TW_Hant_[] = { "zh_TW", "zh-Hant", NULL };
7998 static const char* l3_zh_MOHKTW[] = { "zh_MO", "zh_HK", "zh_TW", NULL };
7999 static const char* l3_zh_HK_HantHK_Hant[] = { "zh_HK", "zh_Hant_HK", "zh_Hant", NULL };
8000 static const char* l3_zh_HKTW_Hant[] = { "zh_Hant_HK", "zh_HK", "zh_TW", "zh_Hant", NULL };
8001 static const char* l3_zh_HantHKHKTW_Hant[] = { "zh_HK", "zh_Hant_HK", "zh_TW", "zh_Hant", NULL };
8002
8003 static const LangAndExpLocs appleLangAndLoc[] = {
8004 // language\ result for appleLocs1 appleLocs2 appleLocs3 appleLocs4 appleLocs5 appleLocs6
8005 { "zh", { l1_zh_CN, l1_zh_CN, l1_zh_CN, l1_zh_Hans, l1_zh_Hans, l1_zh_Hans } },
8006 { "zh-Hans", { l1_zh_CN, l1_zh_CN, l1_zh_CN, l1_zh_Hans, l1_zh_Hans, l1_zh_Hans } },
8007 { "zh-Hant", { l1_zh_TW, l1_zh_TW, l1_zh_TW, l1_zh_Hant, l1_zh_Hant, l1_zh_Hant } },
8008 { "zh-Hans-CN", { l1_zh_CN, l1_zh_CN, l1_zh_CN, l1_zh_Hans, l2_zh_CN_Hans, l2_zh_CN_Hans } },
8009 { "zh-Hans-SG", { l1_zh_CN, l1_zh_CN, l1_zh_CN, l1_zh_Hans, l1_zh_Hans, l1_zh_Hans } },
8010 { "zh-Hant-TW", { l1_zh_TW, l1_zh_TW, l1_zh_TW, l1_zh_Hant, l2_zh_TW_Hant, l2_zh_TW_Hant } },
8011 { "zh-Hant-HK", { l1_zh_TW, l2_zh_HKTW, l2_zh_HKTW, l2_zh_Hant_HK_, l1_zh_Hant, l3_zh_HKTW_Hant} },
8012 { "zh-Hant-MO", { l1_zh_TW, l2_zh_HKTW, l3_zh_MOHKTW, l2_zh_Hant_HK_, l1_zh_Hant, l3_zh_HKTW_Hant} },
8013 { "zh-Hans-HK", { l1_zh_CN, l1_zh_CN, l1_zh_CN, l1_zh_Hans, l1_zh_Hans, l1_zh_Hans } },
8014 { "zh-CN", { l1_zh_CN, l1_zh_CN, l1_zh_CN, l1_zh_Hans, l2_zh_CN_Hans, l2_zh_CN_Hans } },
8015 { "zh-SG", { l1_zh_CN, l1_zh_CN, l1_zh_CN, l1_zh_Hans, l1_zh_Hans, l1_zh_Hans } },
8016 { "zh-TW", { l1_zh_TW, l1_zh_TW, l1_zh_TW, l1_zh_Hant, l2_zh_TW_Hant, l2_zh_TW_Hant } },
8017 { "zh-HK", { l1_zh_TW, l2_zh_HKTW, l2_zh_HKTW, l2_zh_Hant_HK_, l1_zh_Hant, l3_zh_HantHKHKTW_Hant } },
8018 { "zh-MO", { l1_zh_TW, l2_zh_HKTW, l3_zh_MOHKTW, l2_zh_Hant_HK_, l1_zh_Hant, l3_zh_HKTW_Hant} },
8019 { "yue-CN", { l1_zh_CN, l1_zh_CN, l1_zh_CN, l1_zh_Hans, l1_zh_Hans, l1_zh_Hans } }, // <rdar://problem/30671866> should 5/6 be zh_CN?
8020 { "yue-HK", { l1_zh_TW, l1_zh_TW, l1_zh_TW, l1_zh_Hant, l1_zh_Hant, l1_zh_Hant } }, // <rdar://problem/30671866> should 2/3 be zh_HK, 4/6 be zh_Hant_HK_ ?
8021 { "yue-Hans", { l1_zh_CN, l1_zh_CN, l1_zh_CN, l1_zh_Hans, l1_zh_Hans, l1_zh_Hans } },
8022 { "yue-Hant", { l1_zh_TW, l1_zh_TW, l1_zh_TW, l1_zh_Hant, l1_zh_Hant, l1_zh_Hant } },
8023 { "en", { l1_Eng, l1_en, l1_en, l1_en, l1_en, l1_en } },
8024 { "en-US", { l1_Eng, l1_en, l1_en, l2_en_US_, l1_en, l1_en } },
8025 { "en_US", { l1_Eng, l1_en, l1_en, l2_en_US_, l1_en, l1_en } },
8026 { "en-CN", { l1_Eng, l1_en, l1_en, l1_en, l1_en, l1_en } },
8027 { "en-JP", { l1_Eng, l1_en, l1_en, l1_en, l1_en, l1_en } },
8028 { "en-TW", { l1_Eng, l1_en, l1_en, l1_en, l1_en, l1_en } },
8029 { "en-TR", { l1_Eng, l1_en, l1_en, l1_en, l1_en, l1_en } },
8030 { "en-001", { l1_Eng, l1_en, l1_en, l1_en, l2_en_001_, l2_en_001_ } },
8031 { "en-CA", { l1_Eng, l1_en, l2_en_CA_, l2_en_CA_, l2_en_001_, l2_en_001_ } },
8032 { "en-IL", { l1_Eng, l1_en, l1_en, l1_en, l2_en_001_, l2_en_001_ } },
8033 { "en-GB", { l1_Eng, l2_en_GB_, l2_en_GB_, l2_en_GB_, l3_en_GB001_, l3_en_GB001_ } },
8034 { "en-IN", { l1_Eng, l2_en_GB_, l2_en_GB_, l3_en_INGB_, l3_en_GB001_, l3_en_GB001_ } },
8035 { "en-BD", { l1_Eng, l2_en_GB_, l2_en_GB_, l2_en_GB_, l3_en_GB001_, l3_en_GB001_ } },
8036 { "en-LK", { l1_Eng, l2_en_GB_, l2_en_GB_, l2_en_GB_, l3_en_GB001_, l3_en_GB001_ } },
8037 { "en-GG", { l1_Eng, l2_en_GB_, l2_en_GB_, l2_en_GB_, l3_en_GB001_, l3_en_GB001_ } },
8038 { "en-HK", { l1_Eng, l2_en_GB_, l2_en_GB_, l2_en_GB_, l3_en_GB001_, l3_en_GB001_ } },
8039 { "en-IE", { l1_Eng, l2_en_GB_, l2_en_GB_, l2_en_GB_, l3_en_GB001_, l3_en_GB001_ } },
8040 { "en-JM", { l1_Eng, l2_en_GB_, l2_en_GB_, l2_en_GB_, l3_en_GB001_, l3_en_GB001_ } },
8041 { "en-MO", { l1_Eng, l2_en_GB_, l2_en_GB_, l2_en_GB_, l3_en_GB001_, l3_en_GB001_ } },
8042 { "en-MT", { l1_Eng, l2_en_GB_, l2_en_GB_, l2_en_GB_, l3_en_GB001_, l3_en_GB001_ } },
8043 { "en-PK", { l1_Eng, l2_en_GB_, l2_en_GB_, l2_en_GB_, l3_en_GB001_, l3_en_GB001_ } },
8044 { "en-SG", { l1_Eng, l2_en_GB_, l2_en_GB_, l2_en_GB_, l3_en_GB001_, l3_en_GB001_ } },
8045 { "en-VG", { l1_Eng, l2_en_GB_, l2_en_GB_, l2_en_GB_, l3_en_GB001_, l3_en_GB001_ } },
8046 { "en-ZA", { l1_Eng, l2_en_GB_, l2_en_GB_, l2_en_GB_, l3_en_GB001_, l3_en_GB001_ } },
8047 { "en-AU", { l1_Eng, l3_en_AUGB_, l3_en_AUGB_, l3_en_AUGB_, l4_en_AUGB001_, l4_en_AUGB001_ } },
8048 { "en-NZ", { l1_Eng, l3_en_AUGB_, l3_en_AUGB_, l3_en_AUGB_, l4_en_AUGB001_, l4_en_AUGB001_ } },
8049 { "en-WS", { l1_Eng, l3_en_AUGB_, l3_en_AUGB_, l3_en_AUGB_, l4_en_AUGB001_, l4_en_AUGB001_ } },
8050 { "en-150", { l1_Eng, l2_en_GB_, l2_en_GB_, l2_en_GB_, l3_en_GB001_, l4_en_150GB001_ } },
8051 { "en-FR", { l1_Eng, l2_en_GB_, l2_en_GB_, l2_en_GB_, l3_en_GB001_, l4_en_150GB001_ } },
8052 { "en-BE", { l1_Eng, l2_en_GB_, l2_en_GB_, l2_en_GB_, l3_en_GB001_, l4_en_150GB001_ } },
8053 { "en-Latn", { l1_Eng, l1_en, l1_en, l1_en, l1_en, l1_en } },
8054 { "en-Latn-US", { l1_Eng, l1_en, l1_en, l1_en,/*TODO*/ l1_en, l1_en } },
8055 { "en-US-POSIX", { l1_Eng, l1_en, l1_en, l2_en_US_, l1_en, l1_en } },
8056 { "en-Latn-US-POSIX", { l1_Eng, l1_en, l1_en, l1_en, l1_en, l1_en } },
8057 { "en-u-ca-hebrew", { l1_Eng, l1_en, l1_en, l1_en, l1_en, l1_en } },
8058 { "en@calendar=hebrew", { l1_Eng, l1_en, l1_en, l1_en, l1_en, l1_en } },
8059 { "en-", { l1_Eng, l1_en, l1_en, l1_en, l1_en, l1_en } },
8060 { "en_", { l1_Eng, l1_en, l1_en, l1_en, l1_en, l1_en } },
8061 { "es", { l1_Spa, l1_es, l1_es, l1_es, l1_es, l1_es } },
8062 { "es-ES", { l1_Spa, l1_es, l1_es, l1_es, l2_es_ES_, l2_es_ES_ } },
8063 { "es-419", { l1_Spa, l1_es, l2_es_419_, l2_es_419_, l1_es, l2_es_419_ } },
8064 { "es-MX", { l1_Spa, l2_es_MX_, l2_es_419_, l3_es_MX419_, l2_es_MX_, l3_es_MX419_ } },
8065 { "es-AR", { l1_Spa, l1_es, l2_es_419_, l2_es_419_, l1_es, l2_es_419_ } },
8066 { "es-BO", { l1_Spa, l1_es, l2_es_419_, l2_es_419_, l1_es, l2_es_419_ } }, // <rdar://problem/34459988>
8067 { "es-BR", { l1_Spa, l1_es, l2_es_419_, l2_es_419_, l1_es, l2_es_419_ } },
8068 { "es-BZ", { l1_Spa, l1_es, l2_es_419_, l2_es_419_, l1_es, l2_es_419_ } },
8069 { "es-AG", { l1_Spa, l1_es, l2_es_419_, l2_es_419_, l1_es, l2_es_419_ } },
8070 { "es-AW", { l1_Spa, l1_es, l2_es_419_, l2_es_419_, l1_es, l2_es_419_ } },
8071 { "es-CA", { l1_Spa, l1_es, l2_es_419_, l2_es_419_, l1_es, l2_es_419_ } },
8072 { "es-CW", { l1_Spa, l1_es, l2_es_419_, l2_es_419_, l1_es, l2_es_419_ } },
8073 { "es-SX", { l1_Spa, l1_es, l2_es_419_, l2_es_419_, l1_es, l2_es_419_ } },
8074 { "es-TT", { l1_Spa, l1_es, l2_es_419_, l2_es_419_, l1_es, l2_es_419_ } },
8075 { "es-Latn", { l1_Spa, l1_es, l1_es, l1_es, l1_es, l1_es } },
8076 { "es-Latn-MX", { l1_Spa, l1_es, l1_es, l1_es, l1_es, l1_es } },
8077 { "pt", { l1_Port, l1_pt, l1_pt, l1_pt, NULL, NULL } },
8078 { "pt-BR", { l1_Port, l1_pt, l2_pt_BR_, l2_pt_BR_, NULL, NULL } },
8079 { "pt-PT", { l1_Port, l2_pt_PT_, l2_pt_PT_, l1_pt, NULL, NULL } },
8080 { "pt-MO", { l1_Port, l2_pt_PT_, l2_pt_PT_, l1_pt, NULL, NULL } },
8081 { "pt-CH", { l1_Port, l2_pt_PT_, l2_pt_PT_, l1_pt, NULL, NULL } },
8082 { "pt-FR", { l1_Port, l2_pt_PT_, l2_pt_PT_, l1_pt, NULL, NULL } },
8083 { "pt-GQ", { l1_Port, l2_pt_PT_, l2_pt_PT_, l1_pt, NULL, NULL } },
8084 { "pt-LU", { l1_Port, l2_pt_PT_, l2_pt_PT_, l1_pt, NULL, NULL } },
8085 { "fr", { l1_Fre, l1_fr, l1_fr, l1_fr, NULL, NULL } },
8086 { "fr-FR", { l1_Fre, l1_fr, l2_fr_FR_, l2_fr_FR_, NULL, NULL } },
8087 { "fr-CA", { l1_Fre, l2_fr_CA_, l2_fr_CA_, l2_fr_CA_, NULL, NULL } },
8088 { "fr-CH", { l1_Fre, l1_fr, l1_fr, l2_fr_CH_, NULL, NULL } },
8089 { "ar", { l1_Ara, l1_ar, l1_ar, NULL, NULL, NULL } },
8090 { "da", { l1_Dan, l1_da, l1_da, NULL, NULL, NULL } },
8091 { "nl", { l1_Dut, l1_nl, l1_nl, l1_nl, NULL, NULL } },
8092 { "nl-BE", { l1_Dut, l1_nl, l1_nl, l2_nl_BE_, NULL, NULL } },
8093 { "fi", { l1_Fin, l1_fi, l1_fi, NULL, NULL, NULL } },
8094 { "de", { l1_Ger, l1_de, l1_de, NULL, NULL, NULL } },
8095 { "it", { l1_Ita, l1_it, l1_it, l1_it, NULL, NULL } },
8096 { "it_CH", { l1_Ita, l1_it, l2_it_CH, l2_it_CH, NULL, NULL } }, // <rdar://problem/35829322>
8097 { "it_IT", { l1_Ita, l1_it, l1_it, l2_it_IT, NULL, NULL } }, // <rdar://problem/35829322>
8098 { "it_VA", { l1_Ita, l1_it, l1_it, l1_it, NULL, NULL } }, // <rdar://problem/35829322>
8099 { "ja", { l1_Japn, l1_ja, l1_ja, NULL, NULL, NULL } },
8100 { "ko", { l1_Kor, l1_ko, l1_ko, NULL, NULL, NULL } },
8101 { "nb", { l1_Nor, l1_no, l1_nb, NULL, NULL, NULL } },
8102 { "no", { l1_Nor, l1_no, l1_nb, NULL, NULL, NULL } },
8103 { "pl", { l1_Pol, l1_pl, l1_pl, NULL, NULL, NULL } },
8104 { "ru", { l1_Rus, l1_ru, l1_ru, NULL, NULL, NULL } },
8105 { "sv", { l1_Swe, l1_sv, l1_sv, NULL, NULL, NULL } },
8106 { "th", { l1_Thai, l1_th, l1_th, NULL, NULL, NULL } },
8107 { "tr", { l1_Tur, l1_tr, l1_tr, NULL, NULL, NULL } },
8108 { "ca", { l1_ca, l1_ca, l1_ca, NULL, NULL, NULL } },
8109 { "cs", { l1_cs, l1_cs, l1_cs, NULL, NULL, NULL } },
8110 { "el", { l1_el, l1_el, l1_el, NULL, NULL, NULL } },
8111 { "he", { l1_he, l1_he, l1_he, NULL, NULL, l1_iw } },
8112 { "iw", { l1_he, l1_he, l1_he, NULL, NULL, l1_iw } },
8113 { "hr", { l1_hr, l1_hr, l1_hr, NULL, NULL, NULL } },
8114 { "hu", { l1_hu, l1_hu, l1_hu, NULL, NULL, NULL } },
8115 { "id", { l1_id, l1_id, l1_id, NULL, NULL, l1_in } },
8116 { "in", { l1_id, l1_id, l1_id, NULL, NULL, l1_in } },
8117 { "ms", { l1_ms, l1_ms, l1_ms, NULL, NULL, NULL } },
8118 { "ro", { l1_ro, l1_ro, l1_ro, l1_ro, NULL, l1_mo } },
8119 { "mo", { l1_ro, l1_ro, l1_ro, l1_ro, NULL, l1_mo } },
8120 { "sk", { l1_sk, l1_sk, l1_sk, NULL, NULL, NULL } },
8121 { "uk", { l1_uk, l1_uk, l1_uk, NULL, NULL, NULL } },
8122 { "vi", { l1_vi, l1_vi, l1_vi, NULL, NULL, NULL } },
8123 { "yi", { NULL, NULL, NULL, NULL, l1_yi, NULL } },
8124 { "ji", { NULL, NULL, NULL, NULL, l1_yi, NULL } },
8125 { "fil", { NULL, NULL, NULL, NULL, l1_fil, l1_tl } },
8126 { "tl", { NULL, NULL, NULL, NULL, l1_fil, l1_tl } },
8127 { "haw", { NULL, NULL, NULL, NULL, l1_haw, NULL } },
8128 { "sr", { NULL, NULL, NULL, NULL, l1_sr, NULL } },
8129 { "sr-Cyrl", { NULL, NULL, NULL, NULL, l1_sr, NULL } },
8130 { "sr-Latn", { NULL, NULL, NULL, NULL, l1_srLatn, NULL } },
8131 { "tlh", { NULL, NULL, NULL, NULL, l1_tlh, NULL } },
8132 { "Default@2x", { NULL, NULL, NULL, NULL, NULL, NULL } },
8133 { "default", { NULL, NULL, NULL, NULL, NULL, NULL } },
8134 { "root", { NULL, NULL, NULL, NULL, NULL, NULL } },
8135 { "", { NULL, NULL, NULL, NULL, NULL, NULL } },
8136 { "_US", { NULL, NULL, NULL, NULL, NULL, NULL } },
8137 { "-US", { NULL, NULL, NULL, NULL, NULL, NULL } },
8138 { "-u-ca-hebrew", { NULL, NULL, NULL, NULL, NULL, NULL } },
8139 { "-u-ca-hebrew", { NULL, NULL, NULL, NULL, NULL, NULL } },
8140 { "@calendar=hebrew", { NULL, NULL, NULL, NULL, NULL, NULL } },
8141 };
8142 enum { kNumAppleLangAndLoc = UPRV_LENGTHOF(appleLangAndLoc) };
8143
8144 /* tests from <rdar://problem/21518031> */
8145
8146 static const char * appleLocsA1[] = { "en", "fr", "no", "zh-Hant" };
8147 static const char * appleLocsA2[] = { "en", "fr", "nb", "zh_TW", "zh_CN", "zh-Hant" };
8148 static const char * appleLocsA3[] = { "en", "en_IN", "en_GB", "fr", "de", "zh_TW" };
8149 static const char * appleLocsA4[] = { "Spanish", "es_MX", "English", "en_GB" };
8150 static const char * appleLocsA5[] = { "en", "fr", "de", "pt", "pt_PT" };
8151 static const char * appleLocsA6[] = { "en", "no", "no_NO", "pt_PT" };
8152
8153 static const AppleLocsAndCount locAndCountEntriesA[kNumLocSets] = {
8154 { appleLocsA1, UPRV_LENGTHOF(appleLocsA1) },
8155 { appleLocsA2, UPRV_LENGTHOF(appleLocsA2) },
8156 { appleLocsA3, UPRV_LENGTHOF(appleLocsA3) },
8157 { appleLocsA4, UPRV_LENGTHOF(appleLocsA4) },
8158 { appleLocsA5, UPRV_LENGTHOF(appleLocsA5) },
8159 { appleLocsA6, UPRV_LENGTHOF(appleLocsA6) },
8160 };
8161
8162 static const LangAndExpLocs appleLangAndLocA[] = {
8163 // language\ result for appleLocsA1 appleLocsA2 appleLocsA3 appleLocsA4 appleLocsA5 appleLocsA6
8164 { "zh-Hant", { l1_zhHant,/*0*/ l1_zhHant,/*zh_TW*/ l1_zh_TW, NULL, NULL, NULL } },
8165 { "zh_Hant", { l1_zhHant, l1_zhHant,/*zh_TW*/ l1_zh_TW, NULL, NULL, NULL } },
8166 { "zh_HK", { l1_zhHant, l1_zhHant,/*zh_TW*/ l1_zh_TW, NULL, NULL, NULL } },
8167 { "en_IN", { l1_en, l1_en, l3_en_INGB_, l2_en_GB_Eng, l1_en, l1_en } },
8168 { "es_MX", { NULL, NULL, NULL, l2_es_MX_Spa, NULL, NULL } },
8169 { "pt_PT", { NULL, NULL, NULL, NULL, l2_pt_PT_, l1_pt_PT } },
8170 { "pt", { NULL, NULL, NULL, NULL, l1_pt, l1_pt_PT } },
8171 { "no", { l1_no, l1_nb, NULL, NULL, NULL, l1_no } },
8172 { "no_NO", { l1_no, l1_nb, NULL, NULL, NULL, l2_no_NO_ } },
8173 { "nb", { l1_no, l1_nb, NULL, NULL, NULL, l1_no } },
8174 { "nb_NO", { l1_no, l1_nb, NULL, NULL, NULL, l2_no_NO_ } },
8175 };
8176 enum { kNumAppleLangAndLocA = UPRV_LENGTHOF(appleLangAndLocA) };
8177
8178 /* tests from log attached to 21682790 */
8179
8180 static const char * appleLocsB1[] = {
8181 "ar", "Base", "ca", "cs",
8182 "da", "Dutch", "el", "English",
8183 "es_MX", "fi", "French", "German",
8184 "he", "hr", "hu", "id",
8185 "Italian", "Japanese", "ko", "ms",
8186 "no", "pl", "pt", "pt_PT",
8187 "ro", "ru", "sk", "Spanish",
8188 "sv", "th", "tr", "uk",
8189 "vi", "zh_CN", "zh_TW"
8190 };
8191
8192 static const char * appleLocsB2[] = {
8193 "ar", "ca", "cs",
8194 "da", "Dutch", "el", "English",
8195 "es_MX", "fi", "French", "German",
8196 "he", "hr", "hu", "id",
8197 "Italian", "Japanese", "ko", "ms",
8198 "no", "pl", "pt", "pt_PT",
8199 "ro", "ru", "sk", "Spanish",
8200 "sv", "th", "tr", "uk",
8201 "vi", "zh_CN", "zh_TW"
8202 };
8203
8204 static const char * appleLocsB3[] = {
8205 "ar", "ca", "cs", "da",
8206 "de", "el", "en", "es",
8207 "es_MX", "fi", "French", "he",
8208 "hr", "hu", "id", "Italian",
8209 "ja", "ko", "ms", "nl",
8210 "no", "pl", "pt", "pt_PT",
8211 "ro", "ru", "sk", "sv",
8212 "th", "tr", "uk", "vi",
8213 "zh_CN", "zh_TW"
8214 };
8215
8216 static const char * appleLocsB4[] = {
8217 "ar", "ca", "cs", "da",
8218 "de", "el", "en", "es",
8219 "es_MX", "fi", "fr", "he",
8220 "hr", "hu", "id", "it",
8221 "ja", "ko", "ms", "nl",
8222 "no", "pl", "pt", "pt_PT",
8223 "ro", "ru", "sk", "sv",
8224 "th", "tr", "uk", "vi",
8225 "zh_CN", "zh_TW"
8226 };
8227
8228 static const char * appleLocsB5[] = { "en" };
8229
8230 static const char * appleLocsB6[] = { "English" };
8231
8232 static const AppleLocsAndCount locAndCountEntriesB[kNumLocSets] = {
8233 { appleLocsB1, UPRV_LENGTHOF(appleLocsB1) },
8234 { appleLocsB2, UPRV_LENGTHOF(appleLocsB2) },
8235 { appleLocsB3, UPRV_LENGTHOF(appleLocsB3) },
8236 { appleLocsB4, UPRV_LENGTHOF(appleLocsB4) },
8237 { appleLocsB5, UPRV_LENGTHOF(appleLocsB5) },
8238 { appleLocsB6, UPRV_LENGTHOF(appleLocsB6) },
8239 };
8240
8241 static const LangAndExpLocs appleLangAndLocB[] = {
8242 // language\ result for appleLocsB1 appleLocsB2 appleLocsB3 appleLocsB4 appleLocsB5 appleLocsB6
8243 // Prefs 1, logged with sets B1-B3
8244 { "en", { l1_Eng, l1_Eng, l1_en, l1_en, l1_en, l1_Eng } },
8245 { "es", { l1_Spa, l1_Spa, l1_es, l1_es, NULL, NULL } },
8246 // Prefs 2, logged with sets B1-B6
8247 { "English", { l1_Eng, l1_Eng, l1_en, l1_en, l1_en, l1_Eng } },
8248 { "Spanish", { l1_Spa, l1_Spa, l1_es, l1_es, NULL, NULL } },
8249 };
8250 enum { kNumAppleLangAndLocB = UPRV_LENGTHOF(appleLangAndLocB) };
8251
8252 typedef struct {
8253 const AppleLocsAndCount * locAndCountEntriesPtr;
8254 const LangAndExpLocs * appleLangAndLocPtr;
8255 int32_t appleLangAndLocCount;
8256 } AppleLocToUseTestSet;
8257
8258 static const AppleLocToUseTestSet altuTestSets[] = {
8259 { locAndCountEntries, appleLangAndLoc, kNumAppleLangAndLoc },
8260 { locAndCountEntriesA, appleLangAndLocA, kNumAppleLangAndLocA },
8261 { locAndCountEntriesB, appleLangAndLocB, kNumAppleLangAndLocB },
8262 { NULL, NULL, 0 }
8263 };
8264
8265 /* tests for multiple prefs sets */
8266
8267 static const char * appleLocsM1[] = { "en", "en_GB", "pt", "pt_PT", "zh_CN", "zh_Hant" };
8268 static const char * prefLangsM1[] = { "tlh", "zh_HK", "zh_SG", "zh_Hans", "pt_BR", "pt_PT", "en_IN", "en" };
8269 static const char * locsToUseM1[] = { "zh_Hant" };
8270
8271 // Tests from first pass at <rdar://problem/22012864>, 2015-11-18
8272
8273 static const char * appleLocsM2[] = { "fr-FR", "en-US", "en-GB" };
8274 static const char * prefLangsM2[] = { "fr-CH" };
8275 static const char * locsToUseM2[] = { "fr-FR" };
8276
8277 static const char * appleLocsM3[] = { "es-es", "fr-fr" };
8278 static const char * prefLangsM3[] = { "fr-US", "fr", "en-US" };
8279 static const char * locsToUseM3[] = { "fr-fr" };
8280
8281 static const char * appleLocsM4[] = { "es-es", "fr-fr", "fr" };
8282 static const char * prefLangsM4[] = { "fr-US", "fr", "en-US" };
8283 static const char * locsToUseM4[] = { "fr" };
8284
8285 // Tests from second pass at <rdar://problem/22012864>, 2015-12-08
8286 // Per Karan M
8287 static const char * appleLocsM5[] = { "en-US", "fr-FR", "de-DE", "es-ES", "es-419", "pt-PT", "pt-BR", "zh-CN", "zh-TW", "zh-HK", "ja-JP", "ko-KR" };
8288 static const char * prefLangsM5[] = { "fr-US", "en-US" };
8289 static const char * locsToUseM5[] = { "fr-FR" };
8290 // Per Peter E; expected result changed from "en-US" to "de-CH" per <rdar://problem/26559053>
8291 static const char * appleLocsM6[] = { "de-CH", "en-US" };
8292 static const char * prefLangsM6[] = { "de-DE", "en-US" };
8293 static const char * locsToUseM6[] = { "de-CH" };
8294 // The following is used for M7-MD
8295 static const char * appleLocsMx[] = { "de-DE", "en-AU", "es-ES", "fr-FR", "hi-IN", "pt-BR", "zh-HK", "zh-TW" };
8296 // Per Karan M
8297 static const char * prefLangsM7[] = { "fr-ES", "en-AU" };
8298 static const char * locsToUseM7[] = { "fr-FR" };
8299 // Per Karan M
8300 static const char * prefLangsM8[] = { "de-IT", "en-AU" };
8301 static const char * locsToUseM8[] = { "de-DE" };
8302 // Per Karan M
8303 static const char * prefLangsM9[] = { "hi-US", "en-AU" };
8304 static const char * locsToUseM9[] = { "hi-IN" };
8305 // Per Karan M
8306 static const char * prefLangsMA[] = { "en-IN", "zh-HK" };
8307 static const char * locsToUseMA[] = { "en-AU" };
8308 // Per Karan M
8309 static const char * prefLangsMB[] = { "pt-PT", "en-AU" };
8310 static const char * locsToUseMB[] = { "en-AU" };
8311 // per Paul B:
8312 static const char * prefLangsMC[] = { "pt-PT", "ar" };
8313 static const char * locsToUseMC[] = { "pt-BR" };
8314 // Per Karan M
8315 static const char * prefLangsMD[] = { "zh-CN", "en-AU" };
8316 static const char * locsToUseMD[] = { "en-AU" };
8317 // Per Karan M
8318 static const char * appleLocsME[] = { "de-DE", "en-AU", "es-ES", "fr-FR", "hi-IN", "pt-BR", "zh-CN", "zh-HK" };
8319 static const char * prefLangsME[] = { "zh-TW", "en-AU" };
8320 static const char * locsToUseME[] = { "zh-HK" };
8321 // Per Peter E in diagnosis for <rdar://problem/22012864> and <rdar://problem/23815194>
8322 static const char * appleLocsMF[] = { "en", "en-GB", "fr", "es" };
8323 static const char * prefLangsMF[] = { "en-IN", "en-GB", "de", "fr" };
8324 static const char * locsToUseMF[] = { "en-GB", "en" };
8325 // Per Karan M in <rdar://problem/23982460>
8326 static const char * appleLocsMG[] = { "zh-Hans", "zh-Hant", "zh-HK" };
8327 static const char * prefLangsMG[] = { "zh-Hans-US", "zh-HK", "en-US" };
8328 static const char * locsToUseMG[] = { "zh-Hans" };
8329 // Per <rdar://problem/25903891>
8330 static const char * appleLocsMH[] = { "zh-TW", "zh-CN", "zh-HK" };
8331 static const char * prefLangsMH[] = { "zh-Hans-HK", "zh-HK", "en" };
8332 static const char * locsToUseMH[] = { "zh-CN" };
8333 // Per <rdar://problem/26559053>
8334 static const char * appleLocsMI[] = { "unk", "en-US", "ar-SA" };
8335 static const char * prefLangsMI[] = { "ar-US" };
8336 static const char * locsToUseMI[] = { "ar-SA" };
8337 // Per <rdar://problem/30501523> - first for comparison with zh, then real test
8338 static const char * appleLocsMJ[] = { "zh-CN", "en-US" };
8339 static const char * prefLangsMJ[] = { "zh", "zh_AC" };
8340 static const char * locsToUseMJ[] = { "zh-CN" };
8341 static const char * appleLocsMK[] = { "yue-CN", "en-US" };
8342 static const char * prefLangsMK[] = { "yue", "yue_AC" };
8343 static const char * locsToUseMK[] = { };
8344 // NOTE: Test MK was changed to expect "yue" NOT to match "yue-CN"-- the default script for "yue" is "Hant", and we don't
8345 // allow cross-script matching (we believe our original fix for rdar://30501523 was mistaken). Tests MK1a and MK1b are
8346 // added to make sure that "yue-CN" DOES still match "yue_CN" and "yue_Hans", even with the change for rdar://66938404.
8347 static const char * prefLangsMK1a[] = { "yue", "yue_Hans" };
8348 static const char * prefLangsMK1b[] = { "yue", "yue_CN" };
8349 static const char * locsToUseMK1[] = { "yue-CN" };
8350 // Per <rdar://problem/30433534>
8351 static const char * appleLocsML[] = { "nl_NL", "es_MX", "fr_FR", "zh_TW", "it_IT", "vi_VN", "fr_CH", "es_CL",
8352 "en_ZA", "ko_KR", "ca_ES", "ro_RO", "en_PH", "en_CA", "en_SG", "en_IN",
8353 "en_NZ", "it_CH", "fr_CA", "da_DK", "de_AT", "pt_BR", "yue_CN", "zh_CN",
8354 "sv_SE", "es_ES", "ar_SA", "hu_HU", "fr_BE", "en_GB", "ja_JP", "zh_HK",
8355 "fi_FI", "tr_TR", "nb_NO", "en_ID", "en_SA", "pl_PL", "ms_MY", "cs_CZ",
8356 "el_GR", "id_ID", "hr_HR", "en_AE", "he_IL", "ru_RU", "wuu_CN", "de_DE",
8357 "de_CH", "en_AU", "nl_BE", "th_TH", "pt_PT", "sk_SK", "en_US", "en_IE",
8358 "es_CO", "uk_UA", "es_US" };
8359 static const char * prefLangsML[] = { "en-JP" };
8360 static const char * locsToUseML[] = { "en_US" };
8361 // Per <rdar://problem/30671866>
8362 static const char * prefLangsML1[] = { "yue-CN", "zh-CN" };
8363 static const char * locsToUseML1[] = { "yue_CN" }; // should we also get "zh-CN" as a second option?
8364 static const char * prefLangsML2[] = { "yue-Hans", "zh-Hans" };
8365 static const char * locsToUseML2[] = { "yue_CN" }; // should we also get "zh-CN" as a second option?
8366 // Per <rdar://problem/32421203>
8367 static const char * appleLocsMM1[] = { "pt-PT" };
8368 static const char * appleLocsMM2[] = { "pt-BR" };
8369 static const char * appleLocsMM3[] = { "pt-PT", "pt-BR" };
8370 static const char * appleLocsMM4[] = { "en", "pt-PT" };
8371 static const char * appleLocsMM5[] = { "en", "pt-BR" };
8372 static const char * appleLocsMM6[] = { "en", "pt-PT", "pt-BR" };
8373 static const char * prefLangsMM1[] = { "pt-PT" };
8374 static const char * prefLangsMM2[] = { "pt-BR" };
8375 static const char * prefLangsMM3[] = { "pt" };
8376 static const char * prefLangsMM4[] = { "pt-PT", "en" };
8377 static const char * prefLangsMM5[] = { "pt-BR", "en" };
8378 static const char * prefLangsMM6[] = { "pt", "en" };
8379 static const char * locsToUseMMptPT[] = { "pt-PT" };
8380 static const char * locsToUseMMptBR[] = { "pt-BR" };
8381 static const char * locsToUseMMen[] = { "en" };
8382 // Per <rdar://problem/32658828>
8383 static const char * appleLocsMN[] = { "en-US", "en-GB" };
8384 static const char * prefLangsMN1[] = { "en-KR" };
8385 static const char * prefLangsMN2[] = { "en-SA" };
8386 static const char * prefLangsMN3[] = { "en-TW" };
8387 static const char * prefLangsMN4[] = { "en-JP" };
8388 static const char * locsToUseMN_U[] = { "en-US" };
8389 // Per <rdar://problem/36010857>
8390 static const char * appleLocsMO[] = { "Dutch", "French", "German", "Italian", "Japanese", "Spanish",
8391 "ar", "ca", "cs", "da", "el", "en_AU", "en_GB", "en_IN",
8392 "es_419", "fi", "fr_CA", "he", "hi", "hr", "hu", "id", "ko",
8393 "ms", "no", "pl", "pt", "pt_PT", "ro", "ru", "sk", "sv",
8394 "th", "tr", "uk", "vi", "zh_CN", "zh_HK", "zh_TW" };
8395 static const char * prefLangsMO1[] = { "en-US" };
8396 static const char * locsToUseMO1[] = { "en_GB" };
8397 // Per <rdar://problem/47494729>
8398 static const char * appleLocsMP[] = { "en-IN", "hi-IN" };
8399 static const char * prefLangsMP[] = { "hi-Latn-IN", "en-IN" };
8400 static const char * locsToUseMP[] = { "en-IN" };
8401 // Per <rdar://problem/34459988&35829322>
8402 static const char * appleLocsMQa[] = { "en_AU", "en_IE", "en_IN", "en_SA", "en_UK", "en_US", "es_AR", "es_CO", "es_ES", "es_MX", "fr_CA", "fr_FR", "it_CH", "it_IT", "zh_CN", "zh_HK", "zh_TW" };
8403 static const char * appleLocsMQb[] = { "en_AU", "en_IE", "en_IN", "en_SA", "en_UK", "en", "es_AR", "es_CO", "es", "es_MX", "fr_CA", "fr", "it_CH", "it", "zh_CN", "zh_HK", "zh_TW" };
8404 static const char * prefLangsMQ1[] = { "es-BO" };
8405 static const char * locsToUseMQ1[] = { "es_MX" };
8406 static const char * prefLangsMQ2[] = { "it-VA" };
8407 static const char * locsToUseMQ2a[] = { "it_IT" };
8408 static const char * locsToUseMQ2b[] = { "it" };
8409 // Per <rdar://problem/50913699>
8410 static const char * appleLocsMRa[] = { "en", "hi" };
8411 static const char * appleLocsMRb[] = { "en", "hi", "hi_Latn" };
8412 static const char * prefLangsMRx[] = { "hi_Latn_IN", "en_IN", "hi_IN" };
8413 static const char * prefLangsMRy[] = { "hi_Latn", "en", "hi" };
8414 static const char * locsToUseMRa[] = { "en" };
8415 static const char * locsToUseMRb[] = { "hi_Latn", "en" };
8416 // For <rdar://problem/50280505>
8417 static const char * appleLocsMSa[] = { "en", "en_GB" };
8418 static const char * appleLocsMSb[] = { "en", "en_GB", "en_AU" };
8419 static const char * prefLangsMSx[] = { "en_NZ" };
8420 static const char * prefLangsMSy[] = { "en_NZ", "en_AU" };
8421 static const char * locsToUseMSa[] = { "en_GB", "en" };
8422 static const char * locsToUseMSb[] = { "en_AU", "en_GB", "en" };
8423 // For <rdar://problem/55885283>
8424 static const char * appleLocsMT[] = { "ca-ES", "fi", "nl", "en-US", "hu", "pt-BR", "pl-PL", "it",
8425 "ru", "el", "el-GR", "ca", "de-DE", "sv-SE", "tr", "pl",
8426 "sv", "tr-TR", "da", "en", "nb", "pt-PT", "nb-NO",
8427 "es-ES@collation=traditional", "sl-SI", "cs", "hu-HU",
8428 "cs-CZ", "sk", "sl", "de", "da-DK", "es-MX", "vi", "nl-NL",
8429 "es", "fi-FI", "fr", "it-IT", "es-ES", "fr-CA", "vi-VN",
8430 "pt", "sk-SK", "eu-ES", "ru-RU", "eu", "fr-FR", "unk" };
8431 static const char * prefLangsMTa[] = { "en" };
8432 static const char * prefLangsMTb[] = { "he" };
8433 static const char * locsToUseMTa[] = { "en" };
8434 static const char * locsToUseMTb[] = { };
8435 // For rdar://64350332
8436 static const char * appleLocsMU[] = { "hi", "en-IN" };
8437 static const char * prefLangsMU[] = { "en-US" };
8438 static const char * locsToUseMU[] = { "en-IN" };
8439 // For rdar://59520369
8440 static const char * appleLocsMVa[] = { "zh", "zh-Hans", "zh-Hant" };
8441 static const char * appleLocsMVb[] = { "zh-Hans", "zh", "zh-Hant" };
8442 static const char * prefLangsMVa[] = { "zh-Hans-US" };
8443 static const char * prefLangsMVc[] = { "zh-Hans" };
8444 static const char * locsToUseMV[] = { "zh-Hans", "zh" };
8445 // comment in Developer Forums, not made into a Radar
8446 static const char * appleLocsMW[] = { "fr-CA", "pt-BR", "es-MX", "en-US", "en" };
8447 static const char * prefLangsMW[] = { "es-ES" };
8448 static const char * locsToUseMW[] = { "es-MX" };
8449 // For rdar://64811575
8450 static const char * appleLocsMX[] = { "en", "fr", "de", "zh_CN", "zh_TW", "zh-Hant"};
8451 static const char * prefLangsMX[] = { "zh_HK" };
8452 static const char * locsToUseMX[] = { "zh-Hant" };
8453 // For rdar://59520369
8454 static const char * appleLocsMYa[] = { "en", "ars", "ar" };
8455 static const char * appleLocsMYb[] = { "en", "ar" };
8456 static const char * appleLocsMYc[] = { "en", "ars" };
8457 static const char * prefLangsMYa[] = { "ars_SA" };
8458 static const char * prefLangsMYb[] = { "ar_SA" };
8459 static const char * locsToUseMYa[] = { "ars", "ar" };
8460 static const char * locsToUseMYb[] = { "ars" };
8461 static const char * locsToUseMYc[] = { "ar" };
8462 // For rdar://59520369
8463 static const char * appleLocsMZa[] = { "en", "wuu-Hans", "zh-Hans" };
8464 static const char * appleLocsMZb[] = { "en", "zh-Hans" };
8465 static const char * appleLocsMZc[] = { "en", "wuu-Hans" };
8466 static const char * prefLangsMZa[] = { "wuu_CN" };
8467 static const char * prefLangsMZb[] = { "zh_CN" };
8468 static const char * locsToUseMZa[] = { "wuu-Hans", "zh-Hans" };
8469 static const char * locsToUseMZb[] = { "wuu-Hans" };
8470 static const char * locsToUseMZc[] = { "zh-Hans" };
8471 // For rdar://64916132
8472 static const char * appleLocsMAA[] = { "fr-CH", "ja-JP", "fr-CA" };
8473 static const char * prefLangsMAA[] = { "fr-FR", "ja-JP", "fr-CA" };
8474 static const char * locsToUseMAA[] = { "fr-CA" };
8475 // For rdar://65843542
8476 static const char * appleLocsMAB[] = { "en", "yue", "yue-Hans", "zh-CN", "zh-HK" };
8477 static const char * prefLangsMAB[] = { "zh-Hans-US" };
8478 static const char * locsToUseMAB[] = { "zh-CN" };
8479 // For rdar://66729600
8480 static const char * appleLocsMAC[] = { "en", "en-AU", "en-GB"};
8481 static const char * prefLangsMAC[] = { "en-US", "en-GB" };
8482 static const char * locsToUseMAC[] = { "en" };
8483 static const char * appleLocsMAD[] = { "en", "zh-CN", "en-AU" };
8484 static const char * prefLangsMAD[] = { "en-CN", "zh-CN", "en-AU" };
8485 static const char * locsToUseMAD[] = { "en" };
8486 // For rdar://66403688
8487 static const char * appleLocsMAE[] = { "unk", "zh-Hant", "yue" };
8488 static const char * prefLangsMAE[] = { "zh-Hans" };
8489 static const char * locsToUseMAE[] = { };
8490 // For rdar://68146613
8491 static const char * appleLocsMAF[] = { "zxx", "en_HK", "en_MO" };
8492 static const char * prefLangsMAF[] = { "th_TH" };
8493 static const char * locsToUseMAF[] = { "zxx" };
8494 // For rdar://69272236
8495 static const char * appleLocsMAG[] = { "en_US", "en_GB" };
8496 static const char * prefLangsMAG[] = { "en_BN" };
8497 static const char * locsToUseMAG[] = { "en_GB" };
8498
8499
8500 typedef struct {
8501 const char * name;
8502 const char ** availLocs;
8503 int32_t availLocsCount;
8504 const char ** prefLangs;
8505 int32_t prefLangsCount;
8506 const char ** locsToUse;
8507 int32_t locsToUseCount;
8508 } MultiPrefTest;
8509
8510 static const MultiPrefTest multiTestSets[] = {
8511 { "M1", appleLocsM1, UPRV_LENGTHOF(appleLocsM1), prefLangsM1, UPRV_LENGTHOF(prefLangsM1), locsToUseM1, UPRV_LENGTHOF(locsToUseM1) },
8512 //
8513 { "M2", appleLocsM2, UPRV_LENGTHOF(appleLocsM2), prefLangsM2, UPRV_LENGTHOF(prefLangsM2), locsToUseM2, UPRV_LENGTHOF(locsToUseM2) },
8514 { "M3", appleLocsM3, UPRV_LENGTHOF(appleLocsM3), prefLangsM3, UPRV_LENGTHOF(prefLangsM3), locsToUseM3, UPRV_LENGTHOF(locsToUseM3) },
8515 { "M4", appleLocsM4, UPRV_LENGTHOF(appleLocsM4), prefLangsM4, UPRV_LENGTHOF(prefLangsM4), locsToUseM4, UPRV_LENGTHOF(locsToUseM4) },
8516 //
8517 { "M5", appleLocsM5, UPRV_LENGTHOF(appleLocsM5), prefLangsM5, UPRV_LENGTHOF(prefLangsM5), locsToUseM5, UPRV_LENGTHOF(locsToUseM5) },
8518 { "M6", appleLocsM6, UPRV_LENGTHOF(appleLocsM6), prefLangsM6, UPRV_LENGTHOF(prefLangsM6), locsToUseM6, UPRV_LENGTHOF(locsToUseM6) },
8519 { "M7", appleLocsMx, UPRV_LENGTHOF(appleLocsMx), prefLangsM7, UPRV_LENGTHOF(prefLangsM7), locsToUseM7, UPRV_LENGTHOF(locsToUseM7) },
8520 { "M8", appleLocsMx, UPRV_LENGTHOF(appleLocsMx), prefLangsM8, UPRV_LENGTHOF(prefLangsM8), locsToUseM8, UPRV_LENGTHOF(locsToUseM8) },
8521 { "M9", appleLocsMx, UPRV_LENGTHOF(appleLocsMx), prefLangsM9, UPRV_LENGTHOF(prefLangsM9), locsToUseM9, UPRV_LENGTHOF(locsToUseM9) },
8522 { "MA", appleLocsMx, UPRV_LENGTHOF(appleLocsMx), prefLangsMA, UPRV_LENGTHOF(prefLangsMA), locsToUseMA, UPRV_LENGTHOF(locsToUseMA) },
8523 { "MB", appleLocsMx, UPRV_LENGTHOF(appleLocsMx), prefLangsMB, UPRV_LENGTHOF(prefLangsMB), locsToUseMB, UPRV_LENGTHOF(locsToUseMB) },
8524 { "MC", appleLocsMx, UPRV_LENGTHOF(appleLocsMx), prefLangsMC, UPRV_LENGTHOF(prefLangsMC), locsToUseMC, UPRV_LENGTHOF(locsToUseMC) },
8525 { "MD", appleLocsMx, UPRV_LENGTHOF(appleLocsMx), prefLangsMD, UPRV_LENGTHOF(prefLangsMD), locsToUseMD, UPRV_LENGTHOF(locsToUseMD) },
8526 { "ME", appleLocsME, UPRV_LENGTHOF(appleLocsME), prefLangsME, UPRV_LENGTHOF(prefLangsME), locsToUseME, UPRV_LENGTHOF(locsToUseME) },
8527 { "MF", appleLocsMF, UPRV_LENGTHOF(appleLocsMF), prefLangsMF, UPRV_LENGTHOF(prefLangsMF), locsToUseMF, UPRV_LENGTHOF(locsToUseMF) },
8528 { "MG", appleLocsMG, UPRV_LENGTHOF(appleLocsMG), prefLangsMG, UPRV_LENGTHOF(prefLangsMG), locsToUseMG, UPRV_LENGTHOF(locsToUseMG) },
8529 { "MH", appleLocsMH, UPRV_LENGTHOF(appleLocsMH), prefLangsMH, UPRV_LENGTHOF(prefLangsMH), locsToUseMH, UPRV_LENGTHOF(locsToUseMH) },
8530 { "MI", appleLocsMI, UPRV_LENGTHOF(appleLocsMI), prefLangsMI, UPRV_LENGTHOF(prefLangsMI), locsToUseMI, UPRV_LENGTHOF(locsToUseMI) },
8531 { "MJ", appleLocsMJ, UPRV_LENGTHOF(appleLocsMJ), prefLangsMJ, UPRV_LENGTHOF(prefLangsMJ), locsToUseMJ, UPRV_LENGTHOF(locsToUseMJ) },
8532 { "MK", appleLocsMK, UPRV_LENGTHOF(appleLocsMK), prefLangsMK, UPRV_LENGTHOF(prefLangsMK), locsToUseMK, UPRV_LENGTHOF(locsToUseMK) },
8533 { "MK1a", appleLocsMK, UPRV_LENGTHOF(appleLocsMK), prefLangsMK1a, UPRV_LENGTHOF(prefLangsMK1a), locsToUseMK1, UPRV_LENGTHOF(locsToUseMK1) },
8534 { "MK1b", appleLocsMK, UPRV_LENGTHOF(appleLocsMK), prefLangsMK1b, UPRV_LENGTHOF(prefLangsMK1b), locsToUseMK1, UPRV_LENGTHOF(locsToUseMK1) },
8535 { "ML", appleLocsML, UPRV_LENGTHOF(appleLocsML), prefLangsML, UPRV_LENGTHOF(prefLangsML), locsToUseML, UPRV_LENGTHOF(locsToUseML) },
8536 { "ML1", appleLocsML, UPRV_LENGTHOF(appleLocsML), prefLangsML1, UPRV_LENGTHOF(prefLangsML1), locsToUseML1, UPRV_LENGTHOF(locsToUseML1) },
8537 { "ML2", appleLocsML, UPRV_LENGTHOF(appleLocsML), prefLangsML2, UPRV_LENGTHOF(prefLangsML2), locsToUseML2, UPRV_LENGTHOF(locsToUseML2) },
8538 { "MM11", appleLocsMM1, UPRV_LENGTHOF(appleLocsMM1), prefLangsMM1, UPRV_LENGTHOF(prefLangsMM1), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
8539 { "MM21", appleLocsMM2, UPRV_LENGTHOF(appleLocsMM2), prefLangsMM1, UPRV_LENGTHOF(prefLangsMM1), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
8540 { "MM31", appleLocsMM3, UPRV_LENGTHOF(appleLocsMM3), prefLangsMM1, UPRV_LENGTHOF(prefLangsMM1), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
8541 { "MM41", appleLocsMM4, UPRV_LENGTHOF(appleLocsMM4), prefLangsMM1, UPRV_LENGTHOF(prefLangsMM1), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
8542 { "MM51", appleLocsMM5, UPRV_LENGTHOF(appleLocsMM5), prefLangsMM1, UPRV_LENGTHOF(prefLangsMM1), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
8543 { "MM61", appleLocsMM6, UPRV_LENGTHOF(appleLocsMM6), prefLangsMM1, UPRV_LENGTHOF(prefLangsMM1), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
8544 { "MM12", appleLocsMM1, UPRV_LENGTHOF(appleLocsMM1), prefLangsMM2, UPRV_LENGTHOF(prefLangsMM2), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
8545 { "MM22", appleLocsMM2, UPRV_LENGTHOF(appleLocsMM2), prefLangsMM2, UPRV_LENGTHOF(prefLangsMM2), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
8546 { "MM32", appleLocsMM3, UPRV_LENGTHOF(appleLocsMM3), prefLangsMM2, UPRV_LENGTHOF(prefLangsMM2), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
8547 { "MM42", appleLocsMM4, UPRV_LENGTHOF(appleLocsMM4), prefLangsMM2, UPRV_LENGTHOF(prefLangsMM2), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
8548 { "MM52", appleLocsMM5, UPRV_LENGTHOF(appleLocsMM5), prefLangsMM2, UPRV_LENGTHOF(prefLangsMM2), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
8549 { "MM62", appleLocsMM6, UPRV_LENGTHOF(appleLocsMM6), prefLangsMM2, UPRV_LENGTHOF(prefLangsMM2), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
8550 { "MM13", appleLocsMM1, UPRV_LENGTHOF(appleLocsMM1), prefLangsMM3, UPRV_LENGTHOF(prefLangsMM3), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
8551 { "MM23", appleLocsMM2, UPRV_LENGTHOF(appleLocsMM2), prefLangsMM3, UPRV_LENGTHOF(prefLangsMM3), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
8552 { "MM33", appleLocsMM3, UPRV_LENGTHOF(appleLocsMM3), prefLangsMM3, UPRV_LENGTHOF(prefLangsMM3), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
8553 { "MM43", appleLocsMM4, UPRV_LENGTHOF(appleLocsMM4), prefLangsMM3, UPRV_LENGTHOF(prefLangsMM3), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
8554 { "MM53", appleLocsMM5, UPRV_LENGTHOF(appleLocsMM5), prefLangsMM3, UPRV_LENGTHOF(prefLangsMM3), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
8555 { "MM63", appleLocsMM6, UPRV_LENGTHOF(appleLocsMM6), prefLangsMM3, UPRV_LENGTHOF(prefLangsMM3), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
8556 { "MM14", appleLocsMM1, UPRV_LENGTHOF(appleLocsMM1), prefLangsMM4, UPRV_LENGTHOF(prefLangsMM4), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
8557 { "MM24", appleLocsMM2, UPRV_LENGTHOF(appleLocsMM2), prefLangsMM4, UPRV_LENGTHOF(prefLangsMM4), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
8558 { "MM34", appleLocsMM3, UPRV_LENGTHOF(appleLocsMM3), prefLangsMM4, UPRV_LENGTHOF(prefLangsMM4), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
8559 { "MM44", appleLocsMM4, UPRV_LENGTHOF(appleLocsMM4), prefLangsMM4, UPRV_LENGTHOF(prefLangsMM4), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
8560 { "MM54", appleLocsMM5, UPRV_LENGTHOF(appleLocsMM5), prefLangsMM4, UPRV_LENGTHOF(prefLangsMM4), locsToUseMMen, UPRV_LENGTHOF(locsToUseMMen) }, // want en, see <rdar://problem/22012864>
8561 { "MM64", appleLocsMM6, UPRV_LENGTHOF(appleLocsMM6), prefLangsMM4, UPRV_LENGTHOF(prefLangsMM4), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
8562 { "MM15", appleLocsMM1, UPRV_LENGTHOF(appleLocsMM1), prefLangsMM5, UPRV_LENGTHOF(prefLangsMM5), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
8563 { "MM25", appleLocsMM2, UPRV_LENGTHOF(appleLocsMM2), prefLangsMM5, UPRV_LENGTHOF(prefLangsMM5), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
8564 { "MM35", appleLocsMM3, UPRV_LENGTHOF(appleLocsMM3), prefLangsMM5, UPRV_LENGTHOF(prefLangsMM5), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
8565 { "MM45", appleLocsMM4, UPRV_LENGTHOF(appleLocsMM4), prefLangsMM5, UPRV_LENGTHOF(prefLangsMM5), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
8566 { "MM55", appleLocsMM5, UPRV_LENGTHOF(appleLocsMM5), prefLangsMM5, UPRV_LENGTHOF(prefLangsMM5), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
8567 { "MM65", appleLocsMM6, UPRV_LENGTHOF(appleLocsMM6), prefLangsMM5, UPRV_LENGTHOF(prefLangsMM5), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
8568 { "MM16", appleLocsMM1, UPRV_LENGTHOF(appleLocsMM1), prefLangsMM6, UPRV_LENGTHOF(prefLangsMM6), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
8569 { "MM26", appleLocsMM2, UPRV_LENGTHOF(appleLocsMM2), prefLangsMM6, UPRV_LENGTHOF(prefLangsMM6), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
8570 { "MM36", appleLocsMM3, UPRV_LENGTHOF(appleLocsMM3), prefLangsMM6, UPRV_LENGTHOF(prefLangsMM6), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
8571 { "MM46", appleLocsMM4, UPRV_LENGTHOF(appleLocsMM4), prefLangsMM6, UPRV_LENGTHOF(prefLangsMM6), locsToUseMMptPT, UPRV_LENGTHOF(locsToUseMMptPT) },
8572 { "MM56", appleLocsMM5, UPRV_LENGTHOF(appleLocsMM5), prefLangsMM6, UPRV_LENGTHOF(prefLangsMM6), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
8573 { "MM66", appleLocsMM6, UPRV_LENGTHOF(appleLocsMM6), prefLangsMM6, UPRV_LENGTHOF(prefLangsMM6), locsToUseMMptBR, UPRV_LENGTHOF(locsToUseMMptBR) },
8574 { "MN1", appleLocsMN, UPRV_LENGTHOF(appleLocsMN), prefLangsMN1, UPRV_LENGTHOF(prefLangsMN1), locsToUseMN_U, UPRV_LENGTHOF(locsToUseMN_U) },
8575 { "MN2", appleLocsMN, UPRV_LENGTHOF(appleLocsMN), prefLangsMN2, UPRV_LENGTHOF(prefLangsMN2), locsToUseMN_U, UPRV_LENGTHOF(locsToUseMN_U) },
8576 { "MN3", appleLocsMN, UPRV_LENGTHOF(appleLocsMN), prefLangsMN3, UPRV_LENGTHOF(prefLangsMN3), locsToUseMN_U, UPRV_LENGTHOF(locsToUseMN_U) },
8577 { "MN4", appleLocsMN, UPRV_LENGTHOF(appleLocsMN), prefLangsMN4, UPRV_LENGTHOF(prefLangsMN4), locsToUseMN_U, UPRV_LENGTHOF(locsToUseMN_U) },
8578 { "MO", appleLocsMO, UPRV_LENGTHOF(appleLocsMO), prefLangsMO1, UPRV_LENGTHOF(prefLangsMO1), locsToUseMO1, UPRV_LENGTHOF(locsToUseMO1) },
8579 { "MP", appleLocsMP, UPRV_LENGTHOF(appleLocsMP), prefLangsMP, UPRV_LENGTHOF(prefLangsMP), locsToUseMP, UPRV_LENGTHOF(locsToUseMP) },
8580 { "MQ1a", appleLocsMQa, UPRV_LENGTHOF(appleLocsMQa), prefLangsMQ1, UPRV_LENGTHOF(prefLangsMQ1), locsToUseMQ1, UPRV_LENGTHOF(locsToUseMQ1) },
8581 // { "MQ1b", appleLocsMQb, UPRV_LENGTHOF(appleLocsMQb), prefLangsMQ1, UPRV_LENGTHOF(prefLangsMQ1), locsToUseMQ1, UPRV_LENGTHOF(locsToUseMQ1) }, // still to do for <rdar://problem/34459988>
8582 { "MQ2a", appleLocsMQa, UPRV_LENGTHOF(appleLocsMQa), prefLangsMQ2, UPRV_LENGTHOF(prefLangsMQ2), locsToUseMQ2a, UPRV_LENGTHOF(locsToUseMQ2a) },
8583 { "MQ2b", appleLocsMQb, UPRV_LENGTHOF(appleLocsMQb), prefLangsMQ2, UPRV_LENGTHOF(prefLangsMQ2), locsToUseMQ2b, UPRV_LENGTHOF(locsToUseMQ2b) },
8584 { "MRa", appleLocsMRa, UPRV_LENGTHOF(appleLocsMRa), prefLangsMRx, UPRV_LENGTHOF(prefLangsMRx), locsToUseMRa, UPRV_LENGTHOF(locsToUseMRa) },
8585 { "MRb", appleLocsMRb, UPRV_LENGTHOF(appleLocsMRb), prefLangsMRx, UPRV_LENGTHOF(prefLangsMRx), locsToUseMRb, UPRV_LENGTHOF(locsToUseMRb) },
8586 { "MRa", appleLocsMRa, UPRV_LENGTHOF(appleLocsMRa), prefLangsMRy, UPRV_LENGTHOF(prefLangsMRy), locsToUseMRa, UPRV_LENGTHOF(locsToUseMRa) },
8587 { "MRb", appleLocsMRb, UPRV_LENGTHOF(appleLocsMRb), prefLangsMRy, UPRV_LENGTHOF(prefLangsMRy), locsToUseMRb, UPRV_LENGTHOF(locsToUseMRb) },
8588 { "MSax", appleLocsMSa, UPRV_LENGTHOF(appleLocsMSa), prefLangsMSx, UPRV_LENGTHOF(prefLangsMSx), locsToUseMSa, UPRV_LENGTHOF(locsToUseMSa) },
8589 { "MSay", appleLocsMSa, UPRV_LENGTHOF(appleLocsMSa), prefLangsMSy, UPRV_LENGTHOF(prefLangsMSy), locsToUseMSa, UPRV_LENGTHOF(locsToUseMSa) },
8590 { "MSbx", appleLocsMSb, UPRV_LENGTHOF(appleLocsMSb), prefLangsMSx, UPRV_LENGTHOF(prefLangsMSx), locsToUseMSb, UPRV_LENGTHOF(locsToUseMSb) },
8591 { "MSby", appleLocsMSb, UPRV_LENGTHOF(appleLocsMSb), prefLangsMSy, UPRV_LENGTHOF(prefLangsMSy), locsToUseMSb, UPRV_LENGTHOF(locsToUseMSb) },
8592 { "MTa", appleLocsMT, UPRV_LENGTHOF(appleLocsMT), prefLangsMTa, UPRV_LENGTHOF(prefLangsMTa), locsToUseMTa, UPRV_LENGTHOF(locsToUseMTa) },
8593 { "MTb", appleLocsMT, UPRV_LENGTHOF(appleLocsMT), prefLangsMTb, UPRV_LENGTHOF(prefLangsMTb), locsToUseMTb, UPRV_LENGTHOF(locsToUseMTb) },
8594 { "MU", appleLocsMU, UPRV_LENGTHOF(appleLocsMU), prefLangsMU, UPRV_LENGTHOF(prefLangsMU), locsToUseMU, UPRV_LENGTHOF(locsToUseMU) }, // rdar://64350332
8595 { "MVa", appleLocsMVa, UPRV_LENGTHOF(appleLocsMVa), prefLangsMVa, UPRV_LENGTHOF(prefLangsMVa), locsToUseMV, UPRV_LENGTHOF(locsToUseMV) }, // rdar://59520369
8596 { "MVb", appleLocsMVb, UPRV_LENGTHOF(appleLocsMVb), prefLangsMVa, UPRV_LENGTHOF(prefLangsMVa), locsToUseMV, UPRV_LENGTHOF(locsToUseMV) }, // rdar://59520369
8597 { "MVc", appleLocsMVa, UPRV_LENGTHOF(appleLocsMVa), prefLangsMVc, UPRV_LENGTHOF(prefLangsMVc), locsToUseMV, UPRV_LENGTHOF(locsToUseMV) }, // rdar://59520369
8598 { "MW", appleLocsMW, UPRV_LENGTHOF(appleLocsMW), prefLangsMW, UPRV_LENGTHOF(prefLangsMW), locsToUseMW, UPRV_LENGTHOF(locsToUseMW) }, // rdar://59520369
8599 { "MX", appleLocsMX, UPRV_LENGTHOF(appleLocsMX), prefLangsMX, UPRV_LENGTHOF(prefLangsMX), locsToUseMX, UPRV_LENGTHOF(locsToUseMW) }, // rdar://64811575
8600 { "MYaa", appleLocsMYa, UPRV_LENGTHOF(appleLocsMYa), prefLangsMYa, UPRV_LENGTHOF(prefLangsMYa), locsToUseMYa, UPRV_LENGTHOF(locsToUseMYa) }, // rdar://64497611
8601 { "MYba", appleLocsMYb, UPRV_LENGTHOF(appleLocsMYb), prefLangsMYa, UPRV_LENGTHOF(prefLangsMYa), locsToUseMYc, UPRV_LENGTHOF(locsToUseMYc) }, // rdar://64497611
8602 { "MYca", appleLocsMYc, UPRV_LENGTHOF(appleLocsMYc), prefLangsMYa, UPRV_LENGTHOF(prefLangsMYa), locsToUseMYb, UPRV_LENGTHOF(locsToUseMYb) }, // rdar://64497611
8603 { "MYab", appleLocsMYa, UPRV_LENGTHOF(appleLocsMYa), prefLangsMYb, UPRV_LENGTHOF(prefLangsMYb), locsToUseMYc, UPRV_LENGTHOF(locsToUseMYc) }, // rdar://64497611
8604 { "MYbb", appleLocsMYb, UPRV_LENGTHOF(appleLocsMYb), prefLangsMYb, UPRV_LENGTHOF(prefLangsMYb), locsToUseMYc, UPRV_LENGTHOF(locsToUseMYc) }, // rdar://64497611
8605 { "MYcb", appleLocsMYc, UPRV_LENGTHOF(appleLocsMYc), prefLangsMYb, UPRV_LENGTHOF(prefLangsMYb), locsToUseMYb, UPRV_LENGTHOF(locsToUseMYb) }, // rdar://64497611
8606 { "MZaa", appleLocsMZa, UPRV_LENGTHOF(appleLocsMZa), prefLangsMZa, UPRV_LENGTHOF(prefLangsMZa), locsToUseMZa, UPRV_LENGTHOF(locsToUseMZa) }, // rdar://64497611
8607 { "MZba", appleLocsMZb, UPRV_LENGTHOF(appleLocsMZb), prefLangsMZa, UPRV_LENGTHOF(prefLangsMZa), locsToUseMZc, UPRV_LENGTHOF(locsToUseMZc) }, // rdar://64497611
8608 { "MZca", appleLocsMZc, UPRV_LENGTHOF(appleLocsMZc), prefLangsMZa, UPRV_LENGTHOF(prefLangsMZa), locsToUseMZb, UPRV_LENGTHOF(locsToUseMZb) }, // rdar://64497611
8609 { "MZab", appleLocsMZa, UPRV_LENGTHOF(appleLocsMZa), prefLangsMZb, UPRV_LENGTHOF(prefLangsMZb), locsToUseMZc, UPRV_LENGTHOF(locsToUseMZc) }, // rdar://64497611
8610 { "MZbb", appleLocsMZb, UPRV_LENGTHOF(appleLocsMZb), prefLangsMZb, UPRV_LENGTHOF(prefLangsMZb), locsToUseMZc, UPRV_LENGTHOF(locsToUseMZc) }, // rdar://64497611
8611 { "MZcb", appleLocsMZc, UPRV_LENGTHOF(appleLocsMZc), prefLangsMZb, UPRV_LENGTHOF(prefLangsMZb), locsToUseMZb, UPRV_LENGTHOF(locsToUseMZb) }, // rdar://64497611
8612 { "MAA", appleLocsMAA, UPRV_LENGTHOF(appleLocsMAA), prefLangsMAA, UPRV_LENGTHOF(prefLangsMAA), locsToUseMAA, UPRV_LENGTHOF(locsToUseMAA) }, // rdar://64916132
8613 { "MAB", appleLocsMAB, UPRV_LENGTHOF(appleLocsMAB), prefLangsMAB, UPRV_LENGTHOF(prefLangsMAB), locsToUseMAB, UPRV_LENGTHOF(locsToUseMAB) }, // rdar://65843542
8614 { "MAC", appleLocsMAC, UPRV_LENGTHOF(appleLocsMAC), prefLangsMAC, UPRV_LENGTHOF(prefLangsMAC), locsToUseMAC, UPRV_LENGTHOF(locsToUseMAC) }, // rdar://66729600
8615 { "MAD", appleLocsMAD, UPRV_LENGTHOF(appleLocsMAD), prefLangsMAD, UPRV_LENGTHOF(prefLangsMAD), locsToUseMAD, UPRV_LENGTHOF(locsToUseMAD) }, // rdar://66729600
8616 { "MAE", appleLocsMAE, UPRV_LENGTHOF(appleLocsMAE), prefLangsMAE, UPRV_LENGTHOF(prefLangsMAE), locsToUseMAE, UPRV_LENGTHOF(locsToUseMAE) }, // rdar://66403688
8617 { "MAF", appleLocsMAF, UPRV_LENGTHOF(appleLocsMAF), prefLangsMAF, UPRV_LENGTHOF(prefLangsMAF), locsToUseMAF, UPRV_LENGTHOF(locsToUseMAF) }, // rdar://68146613
8618 { "MAG", appleLocsMAG, UPRV_LENGTHOF(appleLocsMAG), prefLangsMAG, UPRV_LENGTHOF(prefLangsMAG), locsToUseMAG, UPRV_LENGTHOF(locsToUseMAG) }, // rdar://69272236
8619
8620 { NULL, NULL, 0, NULL, 0, NULL, 0 }
8621 };
8622
8623
8624 /* general enums */
8625
8626 enum { kMaxLocalizationsToUse = 8, kPrintArrayBufSize = 128 };
8627
8628 // array, array of pointers to strings to print
8629 // count, count of array elements, may be -1 if array is terminated by a NULL entry
8630 // buf, buffer into which to put concatenated strings
8631 // bufSize, length of buf
8632 static void printStringArray(const char **array, int32_t count, char *buf, int32_t bufSize) {
8633 char * bufPtr = buf;
8634 const char * curEntry;
8635 int32_t idx, countMax = bufSize/16;
8636 if (count < 0 || count > countMax) {
8637 count = countMax;
8638 }
8639 for (idx = 0; idx < count && (curEntry = *array++) != NULL; idx++) {
8640 int32_t len = sprintf(bufPtr, "%s\"%.12s\"", (idx > 0)? ", ": "", curEntry);
8641 if (len <= 0) {
8642 break;
8643 }
8644 bufPtr += len;
8645 }
8646 *bufPtr = 0; /* ensure termination */
8647 }
8648
8649 static UBool equalStringArrays(const char **array1, int32_t count1, const char **array2, int32_t count2) {
8650 const char ** array1Ptr = array1;
8651 const char ** array2Ptr = array2;
8652 int32_t idx;
8653 if (count1 < 0) {
8654 count1 = 0;
8655 while (*array1Ptr++ != NULL) {
8656 count1++;
8657 }
8658 }
8659 if (count2 < 0) {
8660 count2 = 0;
8661 while (*array2Ptr++ != NULL) {
8662 count2++;
8663 }
8664 }
8665 if (count1 != count2) {
8666 return FALSE;
8667 }
8668 for (idx = 0; idx < count1; idx++) {
8669 if (uprv_strcmp(array1[idx], array2[idx]) != 0) {
8670 return FALSE;
8671 }
8672 }
8673 return TRUE;
8674 }
8675
8676 static void TestAppleLocalizationsToUse() {
8677 const AppleLocToUseTestSet * testSetPtr;
8678 const MultiPrefTest * multiSetPtr;
8679 const char * locsToUse[kMaxLocalizationsToUse];
8680 int32_t numLocsToUse;
8681 UErrorCode status;
8682 char printExpected[kPrintArrayBufSize];
8683 char printActual[kPrintArrayBufSize];
8684
8685 for (testSetPtr = altuTestSets; testSetPtr->locAndCountEntriesPtr != NULL; testSetPtr++) {
8686 int32_t iLocSet, iLang;
8687
8688 for (iLocSet = 0; iLocSet < kNumLocSets; iLocSet++) {
8689 for (iLang = 0; iLang < testSetPtr->appleLangAndLocCount; iLang++) {
8690 const char * language = testSetPtr->appleLangAndLocPtr[iLang].language;
8691 const char ** expLocsForSet = testSetPtr->appleLangAndLocPtr[iLang].expLocsForSets[iLocSet];
8692 status = U_ZERO_ERROR;
8693
8694 numLocsToUse = ualoc_localizationsToUse(&language, 1,
8695 testSetPtr->locAndCountEntriesPtr[iLocSet].locs, testSetPtr->locAndCountEntriesPtr[iLocSet].locCount,
8696 locsToUse, kMaxLocalizationsToUse, &status);
8697 if (U_FAILURE(status)) {
8698 log_err("FAIL: ualoc_localizationsToUse testSet %d, locSet %d, lang %s, status %s\n",
8699 testSetPtr-altuTestSets, iLocSet+1, language, u_errorName(status));
8700 } else if (numLocsToUse == 0 && expLocsForSet != NULL) {
8701 printStringArray(expLocsForSet, -1, printExpected, kPrintArrayBufSize);
8702 log_err("FAIL: ualoc_localizationsToUse testSet %d, locSet %d, lang %s, expect {%s}, get no results\n",
8703 testSetPtr-altuTestSets, iLocSet+1, language, printExpected);
8704 } else if (numLocsToUse > 0 && expLocsForSet == NULL) {
8705 printStringArray(locsToUse, numLocsToUse, printActual, kPrintArrayBufSize);
8706 log_err("FAIL: ualoc_localizationsToUse testSet %d, locSet %d, lang %s, expect no results, get {%s}\n",
8707 testSetPtr-altuTestSets, iLocSet+1, language, printActual);
8708 } else if (numLocsToUse > 0 && !equalStringArrays(expLocsForSet, -1, locsToUse, numLocsToUse)) {
8709 printStringArray(expLocsForSet, -1, printExpected, kPrintArrayBufSize);
8710 printStringArray(locsToUse, numLocsToUse, printActual, kPrintArrayBufSize);
8711 log_err("FAIL: ualoc_localizationsToUse testSet %d, locSet %d, lang %s:\n expect {%s}\n get {%s}\n",
8712 testSetPtr-altuTestSets, iLocSet+1, language, printExpected, printActual);
8713 }
8714 }
8715 }
8716 }
8717
8718 for (multiSetPtr = multiTestSets; multiSetPtr->name != NULL; multiSetPtr++) {
8719 status = U_ZERO_ERROR;
8720 numLocsToUse = ualoc_localizationsToUse(multiSetPtr->prefLangs, multiSetPtr->prefLangsCount, multiSetPtr->availLocs, multiSetPtr->availLocsCount, locsToUse, kMaxLocalizationsToUse, &status);
8721 if (U_FAILURE(status)) {
8722 log_err("FAIL: ualoc_localizationsToUse appleLocs%s, langs prefLangs%s, status %s\n", multiSetPtr->name, multiSetPtr->name, u_errorName(status));
8723 } else if (!equalStringArrays(multiSetPtr->locsToUse, multiSetPtr->locsToUseCount, locsToUse, numLocsToUse)) {
8724 printStringArray(multiSetPtr->locsToUse, multiSetPtr->locsToUseCount, printExpected, kPrintArrayBufSize);
8725 printStringArray(locsToUse, numLocsToUse, printActual, kPrintArrayBufSize);
8726 log_err("FAIL: ualoc_localizationsToUse appleLocs%s, langs prefLangs%s:\n expect {%s}\n get {%s}\n",
8727 multiSetPtr->name, multiSetPtr->name, printExpected, printActual);
8728 }
8729 }
8730 }
8731
8732 #endif
8733
8734 // rdar://problem/63313283
8735 static void TestNorwegianDisplayNames(void) {
8736 UChar bokmalInBokmal[50];
8737 UChar bokmalInNynorsk[50];
8738 UChar nynorskInBokmal[50];
8739 UChar nynorskInNynorsk[50];
8740 UErrorCode err = U_ZERO_ERROR;
8741
8742 uloc_getDisplayLanguage("nb", "nb", bokmalInBokmal, 50, &err);
8743 uloc_getDisplayLanguage("nb", "nn", bokmalInNynorsk, 50, &err);
8744 uloc_getDisplayLanguage("nn", "nb", nynorskInBokmal, 50, &err);
8745 uloc_getDisplayLanguage("nn", "nn", nynorskInNynorsk, 50, &err);
8746
8747 if (assertSuccess("Error getting display names", &err)) {
8748 assertUEquals("Bokmal and Nynorsk don't have the same names for Bokmal", bokmalInBokmal, bokmalInNynorsk);
8749 assertUEquals("Bokmal and Nynorsk don't have the same names for Nynorsk", nynorskInBokmal, nynorskInNynorsk);
8750 }
8751 }
8752
8753 // rdar://66154565
8754 static void TestSpecificDisplayNames(void) {
8755
8756 // first column is language whose name we want, second column is language to display it in, third column is expected result
8757 static const char* testLanguages[] = {
8758 "wuu", "sv", "shanghainesiska"
8759 };
8760 int32_t numTests = UPRV_LENGTHOF(testLanguages) / 3;
8761
8762 for (int32_t i = 0; i < numTests; i += 3) {
8763 UErrorCode err = U_ZERO_ERROR;
8764 UChar displayName[200];
8765 char displayNameUTF8[200];
8766 uloc_getDisplayLanguage(testLanguages[i], testLanguages[i + 1], displayName, 200, &err);
8767
8768 if (assertSuccess("Error getting display language", &err)) {
8769 u_strToUTF8(displayNameUTF8, 200, NULL, displayName, -1, &err);
8770 if (assertSuccess("Error translating display name to UTF-8", &err)) {
8771 assertEquals("Display name mismatch", testLanguages[i + 2], displayNameUTF8);
8772 }
8773 }
8774 }
8775 }