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