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