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