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