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", 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, "en", ULOC_ACCEPT_VALID, 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_ZERO_ERROR }, /* */
2998 /*9*/{ 9, NULL, "", ULOC_ACCEPT_FAILED, U_ZERO_ERROR }, /* */
2999 /*10*/{10, NULL, "", ULOC_ACCEPT_FAILED, U_BUFFER_OVERFLOW_ERROR }, /* */
3000 /*11*/{11, NULL, "", ULOC_ACCEPT_FAILED, U_BUFFER_OVERFLOW_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, iu-ca;q=0.84, iu;q=0.82, ja-jp;q=0.79, mt;q=0.97, de-de;q=0.74, de;q=0.71, es;q=0.68, it-it;q=0.66, it;q=0.63, vi-vn;q=0.61, vi;q=0.58, nl-nl;q=0.55, nl;q=0.53, th-th-traditional;q=.01",
3005 /*1*/ "ja;q=0.5, en;q=0.8, tlh",
3006 /*2*/ "en-wf, de-lx;q=0.8",
3007 /*3*/ "mga-ie;q=0.9, tlh",
3008 /*4*/ "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
3009 "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
3010 "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
3011 "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
3012 "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
3013 "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, "
3014 "xxx-yyy;q=.01, xxx-yyy;q=.01, xxx-yyy;q=.01, xx-yy;q=.1, "
3015 "es",
3016 /*5*/ "zh-xx;q=0.9, en;q=0.6",
3017 /*6*/ "ja-JA",
3018 /*7*/ "zh-xx;q=0.9",
3019 /*08*/ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3020 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3021 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3022 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", // 156
3023 /*09*/ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3024 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3025 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3026 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB", // 157 (this hits U_STRING_NOT_TERMINATED_WARNING )
3027 /*10*/ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3028 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3029 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3030 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABC", // 158
3031 /*11*/ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3032 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3033 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
3034 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", // 163 bytes
3035 };
3036
3037 for(i=0;i<numTests;i++) {
3038 outResult = -3;
3039 status=U_ZERO_ERROR;
3040 log_verbose("test #%d: http[%s], ICU[%s], expect %s, %s\n",
3041 i, http[tests[i].httpSet], tests[i].icuSet, tests[i].expect, acceptResult(tests[i].res));
3042
3043 available = ures_openAvailableLocales(tests[i].icuSet, &status);
3044 tmp[0]=0;
3045 rc = uloc_acceptLanguageFromHTTP(tmp, 199, &outResult, http[tests[i].httpSet], available, &status);
3046 (void)rc; /* Suppress set but not used warning. */
3047 uenum_close(available);
3048 log_verbose(" got %s, %s [%s]\n", tmp[0]?tmp:"(EMPTY)", acceptResult(outResult), u_errorName(status));
3049 if(status != tests[i].expectStatus) {
3050 log_err_status(status, "FAIL: expected status %s but got %s\n", u_errorName(tests[i].expectStatus), u_errorName(status));
3051 } else if(U_SUCCESS(tests[i].expectStatus)) {
3052 /* don't check content if expected failure */
3053 if(outResult != tests[i].res) {
3054 log_err_status(status, "FAIL: #%d: expected outResult of %s but got %s\n", i,
3055 acceptResult( tests[i].res),
3056 acceptResult( outResult));
3057 log_info("test #%d: http[%s], ICU[%s], expect %s, %s\n",
3058 i, http[tests[i].httpSet], tests[i].icuSet, tests[i].expect,acceptResult(tests[i].res));
3059 }
3060 if((outResult>0)&&uprv_strcmp(tmp, tests[i].expect)) {
3061 log_err_status(status, "FAIL: #%d: expected %s but got %s\n", i, tests[i].expect, tmp);
3062 log_info("test #%d: http[%s], ICU[%s], expect %s, %s\n",
3063 i, http[tests[i].httpSet], tests[i].icuSet, tests[i].expect, acceptResult(tests[i].res));
3064 }
3065 }
3066 }
3067 }
3068
3069 static const char* LOCALE_ALIAS[][2] = {
3070 {"in", "id"},
3071 {"in_ID", "id_ID"},
3072 {"iw", "he"},
3073 {"iw_IL", "he_IL"},
3074 {"ji", "yi"},
3075 {"en_BU", "en_MM"},
3076 {"en_DY", "en_BJ"},
3077 {"en_HV", "en_BF"},
3078 {"en_NH", "en_VU"},
3079 {"en_RH", "en_ZW"},
3080 {"en_TP", "en_TL"},
3081 {"en_ZR", "en_CD"}
3082 };
isLocaleAvailable(UResourceBundle * resIndex,const char * loc)3083 static UBool isLocaleAvailable(UResourceBundle* resIndex, const char* loc){
3084 UErrorCode status = U_ZERO_ERROR;
3085 int32_t len = 0;
3086 ures_getStringByKey(resIndex, loc,&len, &status);
3087 if(U_FAILURE(status)){
3088 return FALSE;
3089 }
3090 return TRUE;
3091 }
3092
TestCalendar()3093 static void TestCalendar() {
3094 #if !UCONFIG_NO_FORMATTING
3095 int i;
3096 UErrorCode status = U_ZERO_ERROR;
3097 UResourceBundle *resIndex = ures_open(NULL,"res_index", &status);
3098 if(U_FAILURE(status)){
3099 log_err_status(status, "Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
3100 return;
3101 }
3102 for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
3103 const char* oldLoc = LOCALE_ALIAS[i][0];
3104 const char* newLoc = LOCALE_ALIAS[i][1];
3105 UCalendar* c1 = NULL;
3106 UCalendar* c2 = NULL;
3107
3108 /*Test function "getLocale(ULocale.VALID_LOCALE)"*/
3109 const char* l1 = ucal_getLocaleByType(c1, ULOC_VALID_LOCALE, &status);
3110 const char* l2 = ucal_getLocaleByType(c2, ULOC_VALID_LOCALE, &status);
3111
3112 if(!isLocaleAvailable(resIndex, newLoc)){
3113 continue;
3114 }
3115 c1 = ucal_open(NULL, -1, oldLoc, UCAL_GREGORIAN, &status);
3116 c2 = ucal_open(NULL, -1, newLoc, UCAL_GREGORIAN, &status);
3117
3118 if (strcmp(newLoc,l1)!=0 || strcmp(l1,l2)!=0 || status!=U_ZERO_ERROR) {
3119 log_err("The locales are not equal!.Old: %s, New: %s \n", oldLoc, newLoc);
3120 }
3121 log_verbose("ucal_getLocaleByType old:%s new:%s\n", l1, l2);
3122 ucal_close(c1);
3123 ucal_close(c2);
3124 }
3125 ures_close(resIndex);
3126 #endif
3127 }
3128
TestDateFormat()3129 static void TestDateFormat() {
3130 #if !UCONFIG_NO_FORMATTING
3131 int i;
3132 UErrorCode status = U_ZERO_ERROR;
3133 UResourceBundle *resIndex = ures_open(NULL,"res_index", &status);
3134 if(U_FAILURE(status)){
3135 log_err_status(status, "Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
3136 return;
3137 }
3138 for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
3139 const char* oldLoc = LOCALE_ALIAS[i][0];
3140 const char* newLoc = LOCALE_ALIAS[i][1];
3141 UDateFormat* df1 = NULL;
3142 UDateFormat* df2 = NULL;
3143 const char* l1 = NULL;
3144 const char* l2 = NULL;
3145
3146 if(!isLocaleAvailable(resIndex, newLoc)){
3147 continue;
3148 }
3149 df1 = udat_open(UDAT_FULL, UDAT_FULL,oldLoc, NULL, 0, NULL, -1, &status);
3150 df2 = udat_open(UDAT_FULL, UDAT_FULL,newLoc, NULL, 0, NULL, -1, &status);
3151 if(U_FAILURE(status)){
3152 log_err("Creation of date format failed %s\n", u_errorName(status));
3153 return;
3154 }
3155 /*Test function "getLocale"*/
3156 l1 = udat_getLocaleByType(df1, ULOC_VALID_LOCALE, &status);
3157 l2 = udat_getLocaleByType(df2, ULOC_VALID_LOCALE, &status);
3158 if(U_FAILURE(status)){
3159 log_err("Fetching the locale by type failed. %s\n", u_errorName(status));
3160 }
3161 if (strcmp(newLoc,l1)!=0 || strcmp(l1,l2)!=0) {
3162 log_err("The locales are not equal!.Old: %s, New: %s \n", oldLoc, newLoc);
3163 }
3164 log_verbose("udat_getLocaleByType old:%s new:%s\n", l1, l2);
3165 udat_close(df1);
3166 udat_close(df2);
3167 }
3168 ures_close(resIndex);
3169 #endif
3170 }
3171
TestCollation()3172 static void TestCollation() {
3173 #if !UCONFIG_NO_COLLATION
3174 int i;
3175 UErrorCode status = U_ZERO_ERROR;
3176 UResourceBundle *resIndex = ures_open(NULL,"res_index", &status);
3177 if(U_FAILURE(status)){
3178 log_err_status(status, "Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
3179 return;
3180 }
3181 for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
3182 const char* oldLoc = LOCALE_ALIAS[i][0];
3183 const char* newLoc = LOCALE_ALIAS[i][1];
3184 UCollator* c1 = NULL;
3185 UCollator* c2 = NULL;
3186 const char* l1 = NULL;
3187 const char* l2 = NULL;
3188
3189 status = U_ZERO_ERROR;
3190 if(!isLocaleAvailable(resIndex, newLoc)){
3191 continue;
3192 }
3193 if(U_FAILURE(status)){
3194 log_err("Creation of collators failed %s\n", u_errorName(status));
3195 return;
3196 }
3197 c1 = ucol_open(oldLoc, &status);
3198 c2 = ucol_open(newLoc, &status);
3199 l1 = ucol_getLocaleByType(c1, ULOC_VALID_LOCALE, &status);
3200 l2 = ucol_getLocaleByType(c2, ULOC_VALID_LOCALE, &status);
3201 if(U_FAILURE(status)){
3202 log_err("Fetching the locale names failed failed %s\n", u_errorName(status));
3203 }
3204 if (strcmp(newLoc,l1)!=0 || strcmp(l1,l2)!=0) {
3205 log_err("The locales are not equal!.Old: %s, New: %s \n", oldLoc, newLoc);
3206 }
3207 log_verbose("ucol_getLocaleByType old:%s new:%s\n", l1, l2);
3208 ucol_close(c1);
3209 ucol_close(c2);
3210 }
3211 ures_close(resIndex);
3212 #endif
3213 }
3214
3215 typedef struct OrientationStructTag {
3216 const char* localeId;
3217 ULayoutType character;
3218 ULayoutType line;
3219 } OrientationStruct;
3220
ULayoutTypeToString(ULayoutType type)3221 static const char* ULayoutTypeToString(ULayoutType type)
3222 {
3223 switch(type)
3224 {
3225 case ULOC_LAYOUT_LTR:
3226 return "ULOC_LAYOUT_LTR";
3227 break;
3228 case ULOC_LAYOUT_RTL:
3229 return "ULOC_LAYOUT_RTL";
3230 break;
3231 case ULOC_LAYOUT_TTB:
3232 return "ULOC_LAYOUT_TTB";
3233 break;
3234 case ULOC_LAYOUT_BTT:
3235 return "ULOC_LAYOUT_BTT";
3236 break;
3237 case ULOC_LAYOUT_UNKNOWN:
3238 break;
3239 }
3240
3241 return "Unknown enum value for ULayoutType!";
3242 }
3243
TestOrientation()3244 static void TestOrientation()
3245 {
3246 static const OrientationStruct toTest [] = {
3247 { "ar", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3248 { "aR", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3249 { "ar_Arab", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3250 { "fa", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3251 { "Fa", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3252 { "he", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3253 { "ps", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3254 { "ur", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3255 { "UR", ULOC_LAYOUT_RTL, ULOC_LAYOUT_TTB },
3256 { "en", ULOC_LAYOUT_LTR, ULOC_LAYOUT_TTB }
3257 };
3258
3259 size_t i = 0;
3260 for (; i < UPRV_LENGTHOF(toTest); ++i) {
3261 UErrorCode statusCO = U_ZERO_ERROR;
3262 UErrorCode statusLO = U_ZERO_ERROR;
3263 const char* const localeId = toTest[i].localeId;
3264 const ULayoutType co = uloc_getCharacterOrientation(localeId, &statusCO);
3265 const ULayoutType expectedCO = toTest[i].character;
3266 const ULayoutType lo = uloc_getLineOrientation(localeId, &statusLO);
3267 const ULayoutType expectedLO = toTest[i].line;
3268 if (U_FAILURE(statusCO)) {
3269 log_err_status(statusCO,
3270 " unexpected failure for uloc_getCharacterOrientation(), with localId \"%s\" and status %s\n",
3271 localeId,
3272 u_errorName(statusCO));
3273 }
3274 else if (co != expectedCO) {
3275 log_err(
3276 " unexpected result for uloc_getCharacterOrientation(), with localeId \"%s\". Expected %s but got result %s\n",
3277 localeId,
3278 ULayoutTypeToString(expectedCO),
3279 ULayoutTypeToString(co));
3280 }
3281 if (U_FAILURE(statusLO)) {
3282 log_err_status(statusLO,
3283 " unexpected failure for uloc_getLineOrientation(), with localId \"%s\" and status %s\n",
3284 localeId,
3285 u_errorName(statusLO));
3286 }
3287 else if (lo != expectedLO) {
3288 log_err(
3289 " unexpected result for uloc_getLineOrientation(), with localeId \"%s\". Expected %s but got result %s\n",
3290 localeId,
3291 ULayoutTypeToString(expectedLO),
3292 ULayoutTypeToString(lo));
3293 }
3294 }
3295 }
3296
TestULocale()3297 static void TestULocale() {
3298 int i;
3299 UErrorCode status = U_ZERO_ERROR;
3300 UResourceBundle *resIndex = ures_open(NULL,"res_index", &status);
3301 if(U_FAILURE(status)){
3302 log_err_status(status, "Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
3303 return;
3304 }
3305 for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
3306 const char* oldLoc = LOCALE_ALIAS[i][0];
3307 const char* newLoc = LOCALE_ALIAS[i][1];
3308 UChar name1[256], name2[256];
3309 char names1[256], names2[256];
3310 int32_t capacity = 256;
3311
3312 status = U_ZERO_ERROR;
3313 if(!isLocaleAvailable(resIndex, newLoc)){
3314 continue;
3315 }
3316 uloc_getDisplayName(oldLoc, ULOC_US, name1, capacity, &status);
3317 if(U_FAILURE(status)){
3318 log_err("uloc_getDisplayName(%s) failed %s\n", oldLoc, u_errorName(status));
3319 }
3320
3321 uloc_getDisplayName(newLoc, ULOC_US, name2, capacity, &status);
3322 if(U_FAILURE(status)){
3323 log_err("uloc_getDisplayName(%s) failed %s\n", newLoc, u_errorName(status));
3324 }
3325
3326 if (u_strcmp(name1, name2)!=0) {
3327 log_err("The locales are not equal!.Old: %s, New: %s \n", oldLoc, newLoc);
3328 }
3329 u_austrcpy(names1, name1);
3330 u_austrcpy(names2, name2);
3331 log_verbose("uloc_getDisplayName old:%s new:%s\n", names1, names2);
3332 }
3333 ures_close(resIndex);
3334
3335 }
3336
TestUResourceBundle()3337 static void TestUResourceBundle() {
3338 const char* us1;
3339 const char* us2;
3340
3341 UResourceBundle* rb1 = NULL;
3342 UResourceBundle* rb2 = NULL;
3343 UErrorCode status = U_ZERO_ERROR;
3344 int i;
3345 UResourceBundle *resIndex = NULL;
3346 if(U_FAILURE(status)){
3347 log_err("Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
3348 return;
3349 }
3350 resIndex = ures_open(NULL,"res_index", &status);
3351 for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
3352
3353 const char* oldLoc = LOCALE_ALIAS[i][0];
3354 const char* newLoc = LOCALE_ALIAS[i][1];
3355 if(!isLocaleAvailable(resIndex, newLoc)){
3356 continue;
3357 }
3358 rb1 = ures_open(NULL, oldLoc, &status);
3359 if (U_FAILURE(status)) {
3360 log_err("ures_open(%s) failed %s\n", oldLoc, u_errorName(status));
3361 }
3362
3363 us1 = ures_getLocaleByType(rb1, ULOC_ACTUAL_LOCALE, &status);
3364
3365 status = U_ZERO_ERROR;
3366 rb2 = ures_open(NULL, newLoc, &status);
3367 if (U_FAILURE(status)) {
3368 log_err("ures_open(%s) failed %s\n", oldLoc, u_errorName(status));
3369 }
3370 us2 = ures_getLocaleByType(rb2, ULOC_ACTUAL_LOCALE, &status);
3371
3372 if (strcmp(us1,newLoc)!=0 || strcmp(us1,us2)!=0 ) {
3373 log_err("The locales are not equal!.Old: %s, New: %s \n", oldLoc, newLoc);
3374 }
3375
3376 log_verbose("ures_getStringByKey old:%s new:%s\n", us1, us2);
3377 ures_close(rb1);
3378 rb1 = NULL;
3379 ures_close(rb2);
3380 rb2 = NULL;
3381 }
3382 ures_close(resIndex);
3383 }
3384
TestDisplayName()3385 static void TestDisplayName() {
3386
3387 UChar oldCountry[256] = {'\0'};
3388 UChar newCountry[256] = {'\0'};
3389 UChar oldLang[256] = {'\0'};
3390 UChar newLang[256] = {'\0'};
3391 char country[256] ={'\0'};
3392 char language[256] ={'\0'};
3393 int32_t capacity = 256;
3394 int i =0;
3395 int j=0;
3396 for (i=0; i<UPRV_LENGTHOF(LOCALE_ALIAS); i++) {
3397 const char* oldLoc = LOCALE_ALIAS[i][0];
3398 const char* newLoc = LOCALE_ALIAS[i][1];
3399 UErrorCode status = U_ZERO_ERROR;
3400 int32_t available = uloc_countAvailable();
3401
3402 for(j=0; j<available; j++){
3403
3404 const char* dispLoc = uloc_getAvailable(j);
3405 int32_t oldCountryLen = uloc_getDisplayCountry(oldLoc,dispLoc, oldCountry, capacity, &status);
3406 int32_t newCountryLen = uloc_getDisplayCountry(newLoc, dispLoc, newCountry, capacity, &status);
3407 int32_t oldLangLen = uloc_getDisplayLanguage(oldLoc, dispLoc, oldLang, capacity, &status);
3408 int32_t newLangLen = uloc_getDisplayLanguage(newLoc, dispLoc, newLang, capacity, &status );
3409
3410 int32_t countryLen = uloc_getCountry(newLoc, country, capacity, &status);
3411 int32_t langLen = uloc_getLanguage(newLoc, language, capacity, &status);
3412 /* there is a display name for the current country ID */
3413 if(countryLen != newCountryLen ){
3414 if(u_strncmp(oldCountry,newCountry,oldCountryLen)!=0){
3415 log_err("uloc_getDisplayCountry() failed for %s in display locale %s \n", oldLoc, dispLoc);
3416 }
3417 }
3418 /* there is a display name for the current lang ID */
3419 if(langLen!=newLangLen){
3420 if(u_strncmp(oldLang,newLang,oldLangLen)){
3421 log_err("uloc_getDisplayLanguage() failed for %s in display locale %s \n", oldLoc, dispLoc); }
3422 }
3423 }
3424 }
3425 }
3426
TestGetLocaleForLCID()3427 static void TestGetLocaleForLCID() {
3428 int32_t i, length, lengthPre;
3429 const char* testLocale = 0;
3430 UErrorCode status = U_ZERO_ERROR;
3431 char temp2[40], temp3[40];
3432 uint32_t lcid;
3433
3434 lcid = uloc_getLCID("en_US");
3435 if (lcid != 0x0409) {
3436 log_err(" uloc_getLCID(\"en_US\") = %d, expected 0x0409\n", lcid);
3437 }
3438
3439 lengthPre = uloc_getLocaleForLCID(lcid, temp2, 4, &status);
3440 if (status != U_BUFFER_OVERFLOW_ERROR) {
3441 log_err(" unexpected result from uloc_getLocaleForLCID with small buffer: %s\n", u_errorName(status));
3442 }
3443 else {
3444 status = U_ZERO_ERROR;
3445 }
3446
3447 length = uloc_getLocaleForLCID(lcid, temp2, UPRV_LENGTHOF(temp2), &status);
3448 if (U_FAILURE(status)) {
3449 log_err(" unexpected result from uloc_getLocaleForLCID(0x0409): %s\n", u_errorName(status));
3450 status = U_ZERO_ERROR;
3451 }
3452
3453 if (length != lengthPre) {
3454 log_err(" uloc_getLocaleForLCID(0x0409): returned length %d does not match preflight length %d\n", length, lengthPre);
3455 }
3456
3457 length = uloc_getLocaleForLCID(0x12345, temp2, UPRV_LENGTHOF(temp2), &status);
3458 if (U_SUCCESS(status)) {
3459 log_err(" unexpected result from uloc_getLocaleForLCID(0x12345): %s, status %s\n", temp2, u_errorName(status));
3460 }
3461 status = U_ZERO_ERROR;
3462
3463 log_verbose("Testing getLocaleForLCID vs. locale data\n");
3464 for (i = 0; i < LOCALE_SIZE; i++) {
3465
3466 testLocale=rawData2[NAME][i];
3467
3468 log_verbose("Testing %s ......\n", testLocale);
3469
3470 sscanf(rawData2[LCID][i], "%x", &lcid);
3471 length = uloc_getLocaleForLCID(lcid, temp2, UPRV_LENGTHOF(temp2), &status);
3472 if (U_FAILURE(status)) {
3473 log_err(" unexpected failure of uloc_getLocaleForLCID(%#04x), status %s\n", lcid, u_errorName(status));
3474 status = U_ZERO_ERROR;
3475 continue;
3476 }
3477
3478 if (length != (int32_t)uprv_strlen(temp2)) {
3479 log_err(" returned length %d not correct for uloc_getLocaleForLCID(%#04x), expected %d\n", length, lcid, uprv_strlen(temp2));
3480 }
3481
3482 /* Compare language, country, script */
3483 length = uloc_getLanguage(temp2, temp3, UPRV_LENGTHOF(temp3), &status);
3484 if (U_FAILURE(status)) {
3485 log_err(" couldn't get language in uloc_getLocaleForLCID(%#04x) = %s, status %s\n", lcid, temp2, u_errorName(status));
3486 status = U_ZERO_ERROR;
3487 }
3488 else if (uprv_strcmp(temp3, rawData2[LANG][i]) && !(uprv_strcmp(temp3, "nn") == 0 && uprv_strcmp(rawData2[VAR][i], "NY") == 0)) {
3489 log_err(" language doesn't match expected %s in in uloc_getLocaleForLCID(%#04x) = %s\n", rawData2[LANG][i], lcid, temp2);
3490 }
3491
3492 length = uloc_getScript(temp2, temp3, UPRV_LENGTHOF(temp3), &status);
3493 if (U_FAILURE(status)) {
3494 log_err(" couldn't get script in uloc_getLocaleForLCID(%#04x) = %s, status %s\n", lcid, temp2, u_errorName(status));
3495 status = U_ZERO_ERROR;
3496 }
3497 else if (uprv_strcmp(temp3, rawData2[SCRIPT][i])) {
3498 log_err(" script doesn't match expected %s in in uloc_getLocaleForLCID(%#04x) = %s\n", rawData2[SCRIPT][i], lcid, temp2);
3499 }
3500
3501 length = uloc_getCountry(temp2, temp3, UPRV_LENGTHOF(temp3), &status);
3502 if (U_FAILURE(status)) {
3503 log_err(" couldn't get country in uloc_getLocaleForLCID(%#04x) = %s, status %s\n", lcid, temp2, u_errorName(status));
3504 status = U_ZERO_ERROR;
3505 }
3506 else if (uprv_strlen(rawData2[CTRY][i]) && uprv_strcmp(temp3, rawData2[CTRY][i])) {
3507 log_err(" country doesn't match expected %s in in uloc_getLocaleForLCID(%#04x) = %s\n", rawData2[CTRY][i], lcid, temp2);
3508 }
3509 }
3510
3511 }
3512
3513 const char* const basic_maximize_data[][2] = {
3514 {
3515 "zu_Zzzz_Zz",
3516 "zu_Latn_ZA",
3517 }, {
3518 "ZU_Zz",
3519 "zu_Latn_ZA"
3520 }, {
3521 "zu_LATN",
3522 "zu_Latn_ZA"
3523 }, {
3524 "en_Zz",
3525 "en_Latn_US"
3526 }, {
3527 "en_us",
3528 "en_Latn_US"
3529 }, {
3530 "en_Kore",
3531 "en_Kore_US"
3532 }, {
3533 "en_Kore_Zz",
3534 "en_Kore_US"
3535 }, {
3536 "en_Kore_ZA",
3537 "en_Kore_ZA"
3538 }, {
3539 "en_Kore_ZA_POSIX",
3540 "en_Kore_ZA_POSIX"
3541 }, {
3542 "en_Gujr",
3543 "en_Gujr_US"
3544 }, {
3545 "en_ZA",
3546 "en_Latn_ZA"
3547 }, {
3548 "en_Gujr_Zz",
3549 "en_Gujr_US"
3550 }, {
3551 "en_Gujr_ZA",
3552 "en_Gujr_ZA"
3553 }, {
3554 "en_Gujr_ZA_POSIX",
3555 "en_Gujr_ZA_POSIX"
3556 }, {
3557 "en_US_POSIX_1901",
3558 "en_Latn_US_POSIX_1901"
3559 }, {
3560 "en_Latn__POSIX_1901",
3561 "en_Latn_US_POSIX_1901"
3562 }, {
3563 "en__POSIX_1901",
3564 "en_Latn_US_POSIX_1901"
3565 }, {
3566 "de__POSIX_1901",
3567 "de_Latn_DE_POSIX_1901"
3568 }, {
3569 "en_US_BOSTON",
3570 "en_Latn_US_BOSTON"
3571 }, {
3572 "th@calendar=buddhist",
3573 "th_Thai_TH@calendar=buddhist"
3574 }, {
3575 "ar_ZZ",
3576 "ar_Arab_EG"
3577 }, {
3578 "zh",
3579 "zh_Hans_CN"
3580 }, {
3581 "zh_TW",
3582 "zh_Hant_TW"
3583 }, {
3584 "zh_HK",
3585 "zh_Hant_HK"
3586 }, {
3587 "zh_Hant",
3588 "zh_Hant_TW"
3589 }, {
3590 "zh_Zzzz_CN",
3591 "zh_Hans_CN"
3592 }, {
3593 "und_US",
3594 "en_Latn_US"
3595 }, {
3596 "und_HK",
3597 "zh_Hant_HK"
3598 }, {
3599 "zzz",
3600 ""
3601 }, {
3602 "de_u_co_phonebk",
3603 "de_Latn_DE_U_CO_PHONEBK"
3604 }, {
3605 "de_Latn_u_co_phonebk",
3606 "de_Latn_DE_U_CO_PHONEBK"
3607 }, {
3608 "de_Latn_DE_u_co_phonebk",
3609 "de_Latn_DE_U_CO_PHONEBK"
3610 }, {
3611 "_Arab@em=emoji",
3612 "ar_Arab_EG@em=emoji"
3613 }, {
3614 "_Latn@em=emoji",
3615 "en_Latn_US@em=emoji"
3616 }, {
3617 "_Latn_DE@em=emoji",
3618 "de_Latn_DE@em=emoji"
3619 }, {
3620 "_Zzzz_DE@em=emoji",
3621 "de_Latn_DE@em=emoji"
3622 }, {
3623 "_DE@em=emoji",
3624 "de_Latn_DE@em=emoji"
3625 }
3626 };
3627
3628 const char* const basic_minimize_data[][2] = {
3629 {
3630 "en_Latn_US",
3631 "en"
3632 }, {
3633 "en_Latn_US_POSIX_1901",
3634 "en__POSIX_1901"
3635 }, {
3636 "EN_Latn_US_POSIX_1901",
3637 "en__POSIX_1901"
3638 }, {
3639 "en_Zzzz_US_POSIX_1901",
3640 "en__POSIX_1901"
3641 }, {
3642 "de_Latn_DE_POSIX_1901",
3643 "de__POSIX_1901"
3644 }, {
3645 "",
3646 ""
3647 }, {
3648 "en_Latn_US@calendar=gregorian",
3649 "en@calendar=gregorian"
3650 }
3651 };
3652
3653 const char* const full_data[][3] = {
3654 {
3655 /* "FROM", */
3656 /* "ADD-LIKELY", */
3657 /* "REMOVE-LIKELY" */
3658 /* }, { */
3659 "aa",
3660 "aa_Latn_ET",
3661 "aa"
3662 }, {
3663 "af",
3664 "af_Latn_ZA",
3665 "af"
3666 }, {
3667 "ak",
3668 "ak_Latn_GH",
3669 "ak"
3670 }, {
3671 "am",
3672 "am_Ethi_ET",
3673 "am"
3674 }, {
3675 "ar",
3676 "ar_Arab_EG",
3677 "ar"
3678 }, {
3679 "as",
3680 "as_Beng_IN",
3681 "as"
3682 }, {
3683 "az",
3684 "az_Latn_AZ",
3685 "az"
3686 }, {
3687 "be",
3688 "be_Cyrl_BY",
3689 "be"
3690 }, {
3691 "bg",
3692 "bg_Cyrl_BG",
3693 "bg"
3694 }, {
3695 "bn",
3696 "bn_Beng_BD",
3697 "bn"
3698 }, {
3699 "bo",
3700 "bo_Tibt_CN",
3701 "bo"
3702 }, {
3703 "bs",
3704 "bs_Latn_BA",
3705 "bs"
3706 }, {
3707 "ca",
3708 "ca_Latn_ES",
3709 "ca"
3710 }, {
3711 "ch",
3712 "ch_Latn_GU",
3713 "ch"
3714 }, {
3715 "chk",
3716 "chk_Latn_FM",
3717 "chk"
3718 }, {
3719 "cs",
3720 "cs_Latn_CZ",
3721 "cs"
3722 }, {
3723 "cy",
3724 "cy_Latn_GB",
3725 "cy"
3726 }, {
3727 "da",
3728 "da_Latn_DK",
3729 "da"
3730 }, {
3731 "de",
3732 "de_Latn_DE",
3733 "de"
3734 }, {
3735 "dv",
3736 "dv_Thaa_MV",
3737 "dv"
3738 }, {
3739 "dz",
3740 "dz_Tibt_BT",
3741 "dz"
3742 }, {
3743 "ee",
3744 "ee_Latn_GH",
3745 "ee"
3746 }, {
3747 "el",
3748 "el_Grek_GR",
3749 "el"
3750 }, {
3751 "en",
3752 "en_Latn_US",
3753 "en"
3754 }, {
3755 "es",
3756 "es_Latn_ES",
3757 "es"
3758 }, {
3759 "et",
3760 "et_Latn_EE",
3761 "et"
3762 }, {
3763 "eu",
3764 "eu_Latn_ES",
3765 "eu"
3766 }, {
3767 "fa",
3768 "fa_Arab_IR",
3769 "fa"
3770 }, {
3771 "fi",
3772 "fi_Latn_FI",
3773 "fi"
3774 }, {
3775 "fil",
3776 "fil_Latn_PH",
3777 "fil"
3778 }, {
3779 "fo",
3780 "fo_Latn_FO",
3781 "fo"
3782 }, {
3783 "fr",
3784 "fr_Latn_FR",
3785 "fr"
3786 }, {
3787 "fur",
3788 "fur_Latn_IT",
3789 "fur"
3790 }, {
3791 "ga",
3792 "ga_Latn_IE",
3793 "ga"
3794 }, {
3795 "gaa",
3796 "gaa_Latn_GH",
3797 "gaa"
3798 }, {
3799 "gl",
3800 "gl_Latn_ES",
3801 "gl"
3802 }, {
3803 "gn",
3804 "gn_Latn_PY",
3805 "gn"
3806 }, {
3807 "gu",
3808 "gu_Gujr_IN",
3809 "gu"
3810 }, {
3811 "ha",
3812 "ha_Latn_NG",
3813 "ha"
3814 }, {
3815 "haw",
3816 "haw_Latn_US",
3817 "haw"
3818 }, {
3819 "he",
3820 "he_Hebr_IL",
3821 "he"
3822 }, {
3823 "hi",
3824 "hi_Deva_IN",
3825 "hi"
3826 }, {
3827 "hr",
3828 "hr_Latn_HR",
3829 "hr"
3830 }, {
3831 "ht",
3832 "ht_Latn_HT",
3833 "ht"
3834 }, {
3835 "hu",
3836 "hu_Latn_HU",
3837 "hu"
3838 }, {
3839 "hy",
3840 "hy_Armn_AM",
3841 "hy"
3842 }, {
3843 "id",
3844 "id_Latn_ID",
3845 "id"
3846 }, {
3847 "ig",
3848 "ig_Latn_NG",
3849 "ig"
3850 }, {
3851 "ii",
3852 "ii_Yiii_CN",
3853 "ii"
3854 }, {
3855 "is",
3856 "is_Latn_IS",
3857 "is"
3858 }, {
3859 "it",
3860 "it_Latn_IT",
3861 "it"
3862 }, {
3863 "ja",
3864 "ja_Jpan_JP",
3865 "ja"
3866 }, {
3867 "ka",
3868 "ka_Geor_GE",
3869 "ka"
3870 }, {
3871 "kaj",
3872 "kaj_Latn_NG",
3873 "kaj"
3874 }, {
3875 "kam",
3876 "kam_Latn_KE",
3877 "kam"
3878 }, {
3879 "kk",
3880 "kk_Cyrl_KZ",
3881 "kk"
3882 }, {
3883 "kl",
3884 "kl_Latn_GL",
3885 "kl"
3886 }, {
3887 "km",
3888 "km_Khmr_KH",
3889 "km"
3890 }, {
3891 "kn",
3892 "kn_Knda_IN",
3893 "kn"
3894 }, {
3895 "ko",
3896 "ko_Kore_KR",
3897 "ko"
3898 }, {
3899 "kok",
3900 "kok_Deva_IN",
3901 "kok"
3902 }, {
3903 "kpe",
3904 "kpe_Latn_LR",
3905 "kpe"
3906 }, {
3907 "ku",
3908 "ku_Latn_TR",
3909 "ku"
3910 }, {
3911 "ky",
3912 "ky_Cyrl_KG",
3913 "ky"
3914 }, {
3915 "la",
3916 "la_Latn_VA",
3917 "la"
3918 }, {
3919 "ln",
3920 "ln_Latn_CD",
3921 "ln"
3922 }, {
3923 "lo",
3924 "lo_Laoo_LA",
3925 "lo"
3926 }, {
3927 "lt",
3928 "lt_Latn_LT",
3929 "lt"
3930 }, {
3931 "lv",
3932 "lv_Latn_LV",
3933 "lv"
3934 }, {
3935 "mg",
3936 "mg_Latn_MG",
3937 "mg"
3938 }, {
3939 "mh",
3940 "mh_Latn_MH",
3941 "mh"
3942 }, {
3943 "mk",
3944 "mk_Cyrl_MK",
3945 "mk"
3946 }, {
3947 "ml",
3948 "ml_Mlym_IN",
3949 "ml"
3950 }, {
3951 "mn",
3952 "mn_Cyrl_MN",
3953 "mn"
3954 }, {
3955 "mr",
3956 "mr_Deva_IN",
3957 "mr"
3958 }, {
3959 "ms",
3960 "ms_Latn_MY",
3961 "ms"
3962 }, {
3963 "mt",
3964 "mt_Latn_MT",
3965 "mt"
3966 }, {
3967 "my",
3968 "my_Mymr_MM",
3969 "my"
3970 }, {
3971 "na",
3972 "na_Latn_NR",
3973 "na"
3974 }, {
3975 "ne",
3976 "ne_Deva_NP",
3977 "ne"
3978 }, {
3979 "niu",
3980 "niu_Latn_NU",
3981 "niu"
3982 }, {
3983 "nl",
3984 "nl_Latn_NL",
3985 "nl"
3986 }, {
3987 "nn",
3988 "nn_Latn_NO",
3989 "nn"
3990 }, {
3991 "nr",
3992 "nr_Latn_ZA",
3993 "nr"
3994 }, {
3995 "nso",
3996 "nso_Latn_ZA",
3997 "nso"
3998 }, {
3999 "ny",
4000 "ny_Latn_MW",
4001 "ny"
4002 }, {
4003 "om",
4004 "om_Latn_ET",
4005 "om"
4006 }, {
4007 "or",
4008 "or_Orya_IN",
4009 "or"
4010 }, {
4011 "pa",
4012 "pa_Guru_IN",
4013 "pa"
4014 }, {
4015 "pa_Arab",
4016 "pa_Arab_PK",
4017 "pa_PK"
4018 }, {
4019 "pa_PK",
4020 "pa_Arab_PK",
4021 "pa_PK"
4022 }, {
4023 "pap",
4024 "pap_Latn_AW",
4025 "pap"
4026 }, {
4027 "pau",
4028 "pau_Latn_PW",
4029 "pau"
4030 }, {
4031 "pl",
4032 "pl_Latn_PL",
4033 "pl"
4034 }, {
4035 "ps",
4036 "ps_Arab_AF",
4037 "ps"
4038 }, {
4039 "pt",
4040 "pt_Latn_BR",
4041 "pt"
4042 }, {
4043 "rn",
4044 "rn_Latn_BI",
4045 "rn"
4046 }, {
4047 "ro",
4048 "ro_Latn_RO",
4049 "ro"
4050 }, {
4051 "ru",
4052 "ru_Cyrl_RU",
4053 "ru"
4054 }, {
4055 "rw",
4056 "rw_Latn_RW",
4057 "rw"
4058 }, {
4059 "sa",
4060 "sa_Deva_IN",
4061 "sa"
4062 }, {
4063 "se",
4064 "se_Latn_NO",
4065 "se"
4066 }, {
4067 "sg",
4068 "sg_Latn_CF",
4069 "sg"
4070 }, {
4071 "si",
4072 "si_Sinh_LK",
4073 "si"
4074 }, {
4075 "sid",
4076 "sid_Latn_ET",
4077 "sid"
4078 }, {
4079 "sk",
4080 "sk_Latn_SK",
4081 "sk"
4082 }, {
4083 "sl",
4084 "sl_Latn_SI",
4085 "sl"
4086 }, {
4087 "sm",
4088 "sm_Latn_WS",
4089 "sm"
4090 }, {
4091 "so",
4092 "so_Latn_SO",
4093 "so"
4094 }, {
4095 "sq",
4096 "sq_Latn_AL",
4097 "sq"
4098 }, {
4099 "sr",
4100 "sr_Cyrl_RS",
4101 "sr"
4102 }, {
4103 "ss",
4104 "ss_Latn_ZA",
4105 "ss"
4106 }, {
4107 "st",
4108 "st_Latn_ZA",
4109 "st"
4110 }, {
4111 "sv",
4112 "sv_Latn_SE",
4113 "sv"
4114 }, {
4115 "sw",
4116 "sw_Latn_TZ",
4117 "sw"
4118 }, {
4119 "ta",
4120 "ta_Taml_IN",
4121 "ta"
4122 }, {
4123 "te",
4124 "te_Telu_IN",
4125 "te"
4126 }, {
4127 "tet",
4128 "tet_Latn_TL",
4129 "tet"
4130 }, {
4131 "tg",
4132 "tg_Cyrl_TJ",
4133 "tg"
4134 }, {
4135 "th",
4136 "th_Thai_TH",
4137 "th"
4138 }, {
4139 "ti",
4140 "ti_Ethi_ET",
4141 "ti"
4142 }, {
4143 "tig",
4144 "tig_Ethi_ER",
4145 "tig"
4146 }, {
4147 "tk",
4148 "tk_Latn_TM",
4149 "tk"
4150 }, {
4151 "tkl",
4152 "tkl_Latn_TK",
4153 "tkl"
4154 }, {
4155 "tn",
4156 "tn_Latn_ZA",
4157 "tn"
4158 }, {
4159 "to",
4160 "to_Latn_TO",
4161 "to"
4162 }, {
4163 "tpi",
4164 "tpi_Latn_PG",
4165 "tpi"
4166 }, {
4167 "tr",
4168 "tr_Latn_TR",
4169 "tr"
4170 }, {
4171 "ts",
4172 "ts_Latn_ZA",
4173 "ts"
4174 }, {
4175 "tt",
4176 "tt_Cyrl_RU",
4177 "tt"
4178 }, {
4179 "tvl",
4180 "tvl_Latn_TV",
4181 "tvl"
4182 }, {
4183 "ty",
4184 "ty_Latn_PF",
4185 "ty"
4186 }, {
4187 "uk",
4188 "uk_Cyrl_UA",
4189 "uk"
4190 }, {
4191 "und",
4192 "en_Latn_US",
4193 "en"
4194 }, {
4195 "und_AD",
4196 "ca_Latn_AD",
4197 "ca_AD"
4198 }, {
4199 "und_AE",
4200 "ar_Arab_AE",
4201 "ar_AE"
4202 }, {
4203 "und_AF",
4204 "fa_Arab_AF",
4205 "fa_AF"
4206 }, {
4207 "und_AL",
4208 "sq_Latn_AL",
4209 "sq"
4210 }, {
4211 "und_AM",
4212 "hy_Armn_AM",
4213 "hy"
4214 }, {
4215 "und_AO",
4216 "pt_Latn_AO",
4217 "pt_AO"
4218 }, {
4219 "und_AR",
4220 "es_Latn_AR",
4221 "es_AR"
4222 }, {
4223 "und_AS",
4224 "sm_Latn_AS",
4225 "sm_AS"
4226 }, {
4227 "und_AT",
4228 "de_Latn_AT",
4229 "de_AT"
4230 }, {
4231 "und_AW",
4232 "nl_Latn_AW",
4233 "nl_AW"
4234 }, {
4235 "und_AX",
4236 "sv_Latn_AX",
4237 "sv_AX"
4238 }, {
4239 "und_AZ",
4240 "az_Latn_AZ",
4241 "az"
4242 }, {
4243 "und_Arab",
4244 "ar_Arab_EG",
4245 "ar"
4246 }, {
4247 "und_Arab_IN",
4248 "ur_Arab_IN",
4249 "ur_IN"
4250 }, {
4251 "und_Arab_PK",
4252 "ur_Arab_PK",
4253 "ur"
4254 }, {
4255 "und_Arab_SN",
4256 "ar_Arab_SN",
4257 "ar_SN"
4258 }, {
4259 "und_Armn",
4260 "hy_Armn_AM",
4261 "hy"
4262 }, {
4263 "und_BA",
4264 "bs_Latn_BA",
4265 "bs"
4266 }, {
4267 "und_BD",
4268 "bn_Beng_BD",
4269 "bn"
4270 }, {
4271 "und_BE",
4272 "nl_Latn_BE",
4273 "nl_BE"
4274 }, {
4275 "und_BF",
4276 "fr_Latn_BF",
4277 "fr_BF"
4278 }, {
4279 "und_BG",
4280 "bg_Cyrl_BG",
4281 "bg"
4282 }, {
4283 "und_BH",
4284 "ar_Arab_BH",
4285 "ar_BH"
4286 }, {
4287 "und_BI",
4288 "rn_Latn_BI",
4289 "rn"
4290 }, {
4291 "und_BJ",
4292 "fr_Latn_BJ",
4293 "fr_BJ"
4294 }, {
4295 "und_BN",
4296 "ms_Latn_BN",
4297 "ms_BN"
4298 }, {
4299 "und_BO",
4300 "es_Latn_BO",
4301 "es_BO"
4302 }, {
4303 "und_BR",
4304 "pt_Latn_BR",
4305 "pt"
4306 }, {
4307 "und_BT",
4308 "dz_Tibt_BT",
4309 "dz"
4310 }, {
4311 "und_BY",
4312 "be_Cyrl_BY",
4313 "be"
4314 }, {
4315 "und_Beng",
4316 "bn_Beng_BD",
4317 "bn"
4318 }, {
4319 "und_Beng_IN",
4320 "bn_Beng_IN",
4321 "bn_IN"
4322 }, {
4323 "und_CD",
4324 "sw_Latn_CD",
4325 "sw_CD"
4326 }, {
4327 "und_CF",
4328 "fr_Latn_CF",
4329 "fr_CF"
4330 }, {
4331 "und_CG",
4332 "fr_Latn_CG",
4333 "fr_CG"
4334 }, {
4335 "und_CH",
4336 "de_Latn_CH",
4337 "de_CH"
4338 }, {
4339 "und_CI",
4340 "fr_Latn_CI",
4341 "fr_CI"
4342 }, {
4343 "und_CL",
4344 "es_Latn_CL",
4345 "es_CL"
4346 }, {
4347 "und_CM",
4348 "fr_Latn_CM",
4349 "fr_CM"
4350 }, {
4351 "und_CN",
4352 "zh_Hans_CN",
4353 "zh"
4354 }, {
4355 "und_CO",
4356 "es_Latn_CO",
4357 "es_CO"
4358 }, {
4359 "und_CR",
4360 "es_Latn_CR",
4361 "es_CR"
4362 }, {
4363 "und_CU",
4364 "es_Latn_CU",
4365 "es_CU"
4366 }, {
4367 "und_CV",
4368 "pt_Latn_CV",
4369 "pt_CV"
4370 }, {
4371 "und_CY",
4372 "el_Grek_CY",
4373 "el_CY"
4374 }, {
4375 "und_CZ",
4376 "cs_Latn_CZ",
4377 "cs"
4378 }, {
4379 "und_Cher",
4380 "chr_Cher_US",
4381 "chr"
4382 }, {
4383 "und_Cyrl",
4384 "ru_Cyrl_RU",
4385 "ru"
4386 }, {
4387 "und_Cyrl_KZ",
4388 "ru_Cyrl_KZ",
4389 "ru_KZ"
4390 }, {
4391 "und_DE",
4392 "de_Latn_DE",
4393 "de"
4394 }, {
4395 "und_DJ",
4396 "aa_Latn_DJ",
4397 "aa_DJ"
4398 }, {
4399 "und_DK",
4400 "da_Latn_DK",
4401 "da"
4402 }, {
4403 "und_DO",
4404 "es_Latn_DO",
4405 "es_DO"
4406 }, {
4407 "und_DZ",
4408 "ar_Arab_DZ",
4409 "ar_DZ"
4410 }, {
4411 "und_Deva",
4412 "hi_Deva_IN",
4413 "hi"
4414 }, {
4415 "und_EC",
4416 "es_Latn_EC",
4417 "es_EC"
4418 }, {
4419 "und_EE",
4420 "et_Latn_EE",
4421 "et"
4422 }, {
4423 "und_EG",
4424 "ar_Arab_EG",
4425 "ar"
4426 }, {
4427 "und_EH",
4428 "ar_Arab_EH",
4429 "ar_EH"
4430 }, {
4431 "und_ER",
4432 "ti_Ethi_ER",
4433 "ti_ER"
4434 }, {
4435 "und_ES",
4436 "es_Latn_ES",
4437 "es"
4438 }, {
4439 "und_ET",
4440 "am_Ethi_ET",
4441 "am"
4442 }, {
4443 "und_Ethi",
4444 "am_Ethi_ET",
4445 "am"
4446 }, {
4447 "und_Ethi_ER",
4448 "am_Ethi_ER",
4449 "am_ER"
4450 }, {
4451 "und_FI",
4452 "fi_Latn_FI",
4453 "fi"
4454 }, {
4455 "und_FM",
4456 "en_Latn_FM",
4457 "en_FM"
4458 }, {
4459 "und_FO",
4460 "fo_Latn_FO",
4461 "fo"
4462 }, {
4463 "und_FR",
4464 "fr_Latn_FR",
4465 "fr"
4466 }, {
4467 "und_GA",
4468 "fr_Latn_GA",
4469 "fr_GA"
4470 }, {
4471 "und_GE",
4472 "ka_Geor_GE",
4473 "ka"
4474 }, {
4475 "und_GF",
4476 "fr_Latn_GF",
4477 "fr_GF"
4478 }, {
4479 "und_GL",
4480 "kl_Latn_GL",
4481 "kl"
4482 }, {
4483 "und_GN",
4484 "fr_Latn_GN",
4485 "fr_GN"
4486 }, {
4487 "und_GP",
4488 "fr_Latn_GP",
4489 "fr_GP"
4490 }, {
4491 "und_GQ",
4492 "es_Latn_GQ",
4493 "es_GQ"
4494 }, {
4495 "und_GR",
4496 "el_Grek_GR",
4497 "el"
4498 }, {
4499 "und_GT",
4500 "es_Latn_GT",
4501 "es_GT"
4502 }, {
4503 "und_GU",
4504 "en_Latn_GU",
4505 "en_GU"
4506 }, {
4507 "und_GW",
4508 "pt_Latn_GW",
4509 "pt_GW"
4510 }, {
4511 "und_Geor",
4512 "ka_Geor_GE",
4513 "ka"
4514 }, {
4515 "und_Grek",
4516 "el_Grek_GR",
4517 "el"
4518 }, {
4519 "und_Gujr",
4520 "gu_Gujr_IN",
4521 "gu"
4522 }, {
4523 "und_Guru",
4524 "pa_Guru_IN",
4525 "pa"
4526 }, {
4527 "und_HK",
4528 "zh_Hant_HK",
4529 "zh_HK"
4530 }, {
4531 "und_HN",
4532 "es_Latn_HN",
4533 "es_HN"
4534 }, {
4535 "und_HR",
4536 "hr_Latn_HR",
4537 "hr"
4538 }, {
4539 "und_HT",
4540 "ht_Latn_HT",
4541 "ht"
4542 }, {
4543 "und_HU",
4544 "hu_Latn_HU",
4545 "hu"
4546 }, {
4547 "und_Hani",
4548 "zh_Hani_CN",
4549 "zh_Hani"
4550 }, {
4551 "und_Hans",
4552 "zh_Hans_CN",
4553 "zh"
4554 }, {
4555 "und_Hant",
4556 "zh_Hant_TW",
4557 "zh_TW"
4558 }, {
4559 "und_Hebr",
4560 "he_Hebr_IL",
4561 "he"
4562 }, {
4563 "und_IL",
4564 "he_Hebr_IL",
4565 "he"
4566 }, {
4567 "und_IN",
4568 "hi_Deva_IN",
4569 "hi"
4570 }, {
4571 "und_IQ",
4572 "ar_Arab_IQ",
4573 "ar_IQ"
4574 }, {
4575 "und_IR",
4576 "fa_Arab_IR",
4577 "fa"
4578 }, {
4579 "und_IS",
4580 "is_Latn_IS",
4581 "is"
4582 }, {
4583 "und_IT",
4584 "it_Latn_IT",
4585 "it"
4586 }, {
4587 "und_JO",
4588 "ar_Arab_JO",
4589 "ar_JO"
4590 }, {
4591 "und_JP",
4592 "ja_Jpan_JP",
4593 "ja"
4594 }, {
4595 "und_Jpan",
4596 "ja_Jpan_JP",
4597 "ja"
4598 }, {
4599 "und_KG",
4600 "ky_Cyrl_KG",
4601 "ky"
4602 }, {
4603 "und_KH",
4604 "km_Khmr_KH",
4605 "km"
4606 }, {
4607 "und_KM",
4608 "ar_Arab_KM",
4609 "ar_KM"
4610 }, {
4611 "und_KP",
4612 "ko_Kore_KP",
4613 "ko_KP"
4614 }, {
4615 "und_KR",
4616 "ko_Kore_KR",
4617 "ko"
4618 }, {
4619 "und_KW",
4620 "ar_Arab_KW",
4621 "ar_KW"
4622 }, {
4623 "und_KZ",
4624 "ru_Cyrl_KZ",
4625 "ru_KZ"
4626 }, {
4627 "und_Khmr",
4628 "km_Khmr_KH",
4629 "km"
4630 }, {
4631 "und_Knda",
4632 "kn_Knda_IN",
4633 "kn"
4634 }, {
4635 "und_Kore",
4636 "ko_Kore_KR",
4637 "ko"
4638 }, {
4639 "und_LA",
4640 "lo_Laoo_LA",
4641 "lo"
4642 }, {
4643 "und_LB",
4644 "ar_Arab_LB",
4645 "ar_LB"
4646 }, {
4647 "und_LI",
4648 "de_Latn_LI",
4649 "de_LI"
4650 }, {
4651 "und_LK",
4652 "si_Sinh_LK",
4653 "si"
4654 }, {
4655 "und_LS",
4656 "st_Latn_LS",
4657 "st_LS"
4658 }, {
4659 "und_LT",
4660 "lt_Latn_LT",
4661 "lt"
4662 }, {
4663 "und_LU",
4664 "fr_Latn_LU",
4665 "fr_LU"
4666 }, {
4667 "und_LV",
4668 "lv_Latn_LV",
4669 "lv"
4670 }, {
4671 "und_LY",
4672 "ar_Arab_LY",
4673 "ar_LY"
4674 }, {
4675 "und_Laoo",
4676 "lo_Laoo_LA",
4677 "lo"
4678 }, {
4679 "und_Latn_ES",
4680 "es_Latn_ES",
4681 "es"
4682 }, {
4683 "und_Latn_ET",
4684 "en_Latn_ET",
4685 "en_ET"
4686 }, {
4687 "und_Latn_GB",
4688 "en_Latn_GB",
4689 "en_GB"
4690 }, {
4691 "und_Latn_GH",
4692 "ak_Latn_GH",
4693 "ak"
4694 }, {
4695 "und_Latn_ID",
4696 "id_Latn_ID",
4697 "id"
4698 }, {
4699 "und_Latn_IT",
4700 "it_Latn_IT",
4701 "it"
4702 }, {
4703 "und_Latn_NG",
4704 "en_Latn_NG",
4705 "en_NG"
4706 }, {
4707 "und_Latn_TR",
4708 "tr_Latn_TR",
4709 "tr"
4710 }, {
4711 "und_Latn_ZA",
4712 "en_Latn_ZA",
4713 "en_ZA"
4714 }, {
4715 "und_MA",
4716 "ar_Arab_MA",
4717 "ar_MA"
4718 }, {
4719 "und_MC",
4720 "fr_Latn_MC",
4721 "fr_MC"
4722 }, {
4723 "und_MD",
4724 "ro_Latn_MD",
4725 "ro_MD"
4726 }, {
4727 "und_ME",
4728 "sr_Latn_ME",
4729 "sr_ME"
4730 }, {
4731 "und_MG",
4732 "mg_Latn_MG",
4733 "mg"
4734 }, {
4735 "und_MH",
4736 "en_Latn_MH",
4737 "en_MH"
4738 }, {
4739 "und_MK",
4740 "mk_Cyrl_MK",
4741 "mk"
4742 }, {
4743 "und_ML",
4744 "bm_Latn_ML",
4745 "bm"
4746 }, {
4747 "und_MM",
4748 "my_Mymr_MM",
4749 "my"
4750 }, {
4751 "und_MN",
4752 "mn_Cyrl_MN",
4753 "mn"
4754 }, {
4755 "und_MO",
4756 "zh_Hant_MO",
4757 "zh_MO"
4758 }, {
4759 "und_MQ",
4760 "fr_Latn_MQ",
4761 "fr_MQ"
4762 }, {
4763 "und_MR",
4764 "ar_Arab_MR",
4765 "ar_MR"
4766 }, {
4767 "und_MT",
4768 "mt_Latn_MT",
4769 "mt"
4770 }, {
4771 "und_MV",
4772 "dv_Thaa_MV",
4773 "dv"
4774 }, {
4775 "und_MW",
4776 "en_Latn_MW",
4777 "en_MW"
4778 }, {
4779 "und_MX",
4780 "es_Latn_MX",
4781 "es_MX"
4782 }, {
4783 "und_MY",
4784 "ms_Latn_MY",
4785 "ms"
4786 }, {
4787 "und_MZ",
4788 "pt_Latn_MZ",
4789 "pt_MZ"
4790 }, {
4791 "und_Mlym",
4792 "ml_Mlym_IN",
4793 "ml"
4794 }, {
4795 "und_Mymr",
4796 "my_Mymr_MM",
4797 "my"
4798 }, {
4799 "und_NC",
4800 "fr_Latn_NC",
4801 "fr_NC"
4802 }, {
4803 "und_NE",
4804 "ha_Latn_NE",
4805 "ha_NE"
4806 }, {
4807 "und_NG",
4808 "en_Latn_NG",
4809 "en_NG"
4810 }, {
4811 "und_NI",
4812 "es_Latn_NI",
4813 "es_NI"
4814 }, {
4815 "und_NL",
4816 "nl_Latn_NL",
4817 "nl"
4818 }, {
4819 "und_NO",
4820 "no_Latn_NO", /* Google patch */
4821 "no" /* Google patch */
4822 }, {
4823 "und_NP",
4824 "ne_Deva_NP",
4825 "ne"
4826 }, {
4827 "und_NR",
4828 "en_Latn_NR",
4829 "en_NR"
4830 }, {
4831 "und_NU",
4832 "en_Latn_NU",
4833 "en_NU"
4834 }, {
4835 "und_OM",
4836 "ar_Arab_OM",
4837 "ar_OM"
4838 }, {
4839 "und_Orya",
4840 "or_Orya_IN",
4841 "or"
4842 }, {
4843 "und_PA",
4844 "es_Latn_PA",
4845 "es_PA"
4846 }, {
4847 "und_PE",
4848 "es_Latn_PE",
4849 "es_PE"
4850 }, {
4851 "und_PF",
4852 "fr_Latn_PF",
4853 "fr_PF"
4854 }, {
4855 "und_PG",
4856 "tpi_Latn_PG",
4857 "tpi"
4858 }, {
4859 "und_PH",
4860 "fil_Latn_PH",
4861 "fil"
4862 }, {
4863 "und_PL",
4864 "pl_Latn_PL",
4865 "pl"
4866 }, {
4867 "und_PM",
4868 "fr_Latn_PM",
4869 "fr_PM"
4870 }, {
4871 "und_PR",
4872 "es_Latn_PR",
4873 "es_PR"
4874 }, {
4875 "und_PS",
4876 "ar_Arab_PS",
4877 "ar_PS"
4878 }, {
4879 "und_PT",
4880 "pt_Latn_PT",
4881 "pt_PT"
4882 }, {
4883 "und_PW",
4884 "pau_Latn_PW",
4885 "pau"
4886 }, {
4887 "und_PY",
4888 "gn_Latn_PY",
4889 "gn"
4890 }, {
4891 "und_QA",
4892 "ar_Arab_QA",
4893 "ar_QA"
4894 }, {
4895 "und_RE",
4896 "fr_Latn_RE",
4897 "fr_RE"
4898 }, {
4899 "und_RO",
4900 "ro_Latn_RO",
4901 "ro"
4902 }, {
4903 "und_RS",
4904 "sr_Cyrl_RS",
4905 "sr"
4906 }, {
4907 "und_RU",
4908 "ru_Cyrl_RU",
4909 "ru"
4910 }, {
4911 "und_RW",
4912 "rw_Latn_RW",
4913 "rw"
4914 }, {
4915 "und_SA",
4916 "ar_Arab_SA",
4917 "ar_SA"
4918 }, {
4919 "und_SD",
4920 "ar_Arab_SD",
4921 "ar_SD"
4922 }, {
4923 "und_SE",
4924 "sv_Latn_SE",
4925 "sv"
4926 }, {
4927 "und_SG",
4928 "en_Latn_SG",
4929 "en_SG"
4930 }, {
4931 "und_SI",
4932 "sl_Latn_SI",
4933 "sl"
4934 }, {
4935 "und_SJ",
4936 "no_Latn_SJ", /* Google patch */
4937 "no_SJ" /* Google patch */
4938 }, {
4939 "und_SK",
4940 "sk_Latn_SK",
4941 "sk"
4942 }, {
4943 "und_SM",
4944 "it_Latn_SM",
4945 "it_SM"
4946 }, {
4947 "und_SN",
4948 "fr_Latn_SN",
4949 "fr_SN"
4950 }, {
4951 "und_SO",
4952 "so_Latn_SO",
4953 "so"
4954 }, {
4955 "und_SR",
4956 "nl_Latn_SR",
4957 "nl_SR"
4958 }, {
4959 "und_ST",
4960 "pt_Latn_ST",
4961 "pt_ST"
4962 }, {
4963 "und_SV",
4964 "es_Latn_SV",
4965 "es_SV"
4966 }, {
4967 "und_SY",
4968 "ar_Arab_SY",
4969 "ar_SY"
4970 }, {
4971 "und_Sinh",
4972 "si_Sinh_LK",
4973 "si"
4974 }, {
4975 "und_TD",
4976 "fr_Latn_TD",
4977 "fr_TD"
4978 }, {
4979 "und_TG",
4980 "fr_Latn_TG",
4981 "fr_TG"
4982 }, {
4983 "und_TH",
4984 "th_Thai_TH",
4985 "th"
4986 }, {
4987 "und_TJ",
4988 "tg_Cyrl_TJ",
4989 "tg"
4990 }, {
4991 "und_TK",
4992 "tkl_Latn_TK",
4993 "tkl"
4994 }, {
4995 "und_TL",
4996 "pt_Latn_TL",
4997 "pt_TL"
4998 }, {
4999 "und_TM",
5000 "tk_Latn_TM",
5001 "tk"
5002 }, {
5003 "und_TN",
5004 "ar_Arab_TN",
5005 "ar_TN"
5006 }, {
5007 "und_TO",
5008 "to_Latn_TO",
5009 "to"
5010 }, {
5011 "und_TR",
5012 "tr_Latn_TR",
5013 "tr"
5014 }, {
5015 "und_TV",
5016 "tvl_Latn_TV",
5017 "tvl"
5018 }, {
5019 "und_TW",
5020 "zh_Hant_TW",
5021 "zh_TW"
5022 }, {
5023 "und_Taml",
5024 "ta_Taml_IN",
5025 "ta"
5026 }, {
5027 "und_Telu",
5028 "te_Telu_IN",
5029 "te"
5030 }, {
5031 "und_Thaa",
5032 "dv_Thaa_MV",
5033 "dv"
5034 }, {
5035 "und_Thai",
5036 "th_Thai_TH",
5037 "th"
5038 }, {
5039 "und_Tibt",
5040 "bo_Tibt_CN",
5041 "bo"
5042 }, {
5043 "und_UA",
5044 "uk_Cyrl_UA",
5045 "uk"
5046 }, {
5047 "und_UY",
5048 "es_Latn_UY",
5049 "es_UY"
5050 }, {
5051 "und_UZ",
5052 "uz_Latn_UZ",
5053 "uz"
5054 }, {
5055 "und_VA",
5056 "it_Latn_VA",
5057 "it_VA"
5058 }, {
5059 "und_VE",
5060 "es_Latn_VE",
5061 "es_VE"
5062 }, {
5063 "und_VN",
5064 "vi_Latn_VN",
5065 "vi"
5066 }, {
5067 "und_VU",
5068 "bi_Latn_VU",
5069 "bi"
5070 }, {
5071 "und_WF",
5072 "fr_Latn_WF",
5073 "fr_WF"
5074 }, {
5075 "und_WS",
5076 "sm_Latn_WS",
5077 "sm"
5078 }, {
5079 "und_YE",
5080 "ar_Arab_YE",
5081 "ar_YE"
5082 }, {
5083 "und_YT",
5084 "fr_Latn_YT",
5085 "fr_YT"
5086 }, {
5087 "und_Yiii",
5088 "ii_Yiii_CN",
5089 "ii"
5090 }, {
5091 "ur",
5092 "ur_Arab_PK",
5093 "ur"
5094 }, {
5095 "uz",
5096 "uz_Latn_UZ",
5097 "uz"
5098 }, {
5099 "uz_AF",
5100 "uz_Arab_AF",
5101 "uz_AF"
5102 }, {
5103 "uz_Arab",
5104 "uz_Arab_AF",
5105 "uz_AF"
5106 }, {
5107 "ve",
5108 "ve_Latn_ZA",
5109 "ve"
5110 }, {
5111 "vi",
5112 "vi_Latn_VN",
5113 "vi"
5114 }, {
5115 "wal",
5116 "wal_Ethi_ET",
5117 "wal"
5118 }, {
5119 "wo",
5120 "wo_Latn_SN",
5121 "wo"
5122 }, {
5123 "xh",
5124 "xh_Latn_ZA",
5125 "xh"
5126 }, {
5127 "yo",
5128 "yo_Latn_NG",
5129 "yo"
5130 }, {
5131 "zh",
5132 "zh_Hans_CN",
5133 "zh"
5134 }, {
5135 "zh_HK",
5136 "zh_Hant_HK",
5137 "zh_HK"
5138 }, {
5139 "zh_Hani",
5140 "zh_Hani_CN", /* changed due to cldrbug 6204, may be an error */
5141 "zh_Hani", /* changed due to cldrbug 6204, may be an error */
5142 }, {
5143 "zh_Hant",
5144 "zh_Hant_TW",
5145 "zh_TW"
5146 }, {
5147 "zh_MO",
5148 "zh_Hant_MO",
5149 "zh_MO"
5150 }, {
5151 "zh_TW",
5152 "zh_Hant_TW",
5153 "zh_TW"
5154 }, {
5155 "zu",
5156 "zu_Latn_ZA",
5157 "zu"
5158 }, {
5159 "und",
5160 "en_Latn_US",
5161 "en"
5162 }, {
5163 "und_ZZ",
5164 "en_Latn_US",
5165 "en"
5166 }, {
5167 "und_CN",
5168 "zh_Hans_CN",
5169 "zh"
5170 }, {
5171 "und_TW",
5172 "zh_Hant_TW",
5173 "zh_TW"
5174 }, {
5175 "und_HK",
5176 "zh_Hant_HK",
5177 "zh_HK"
5178 }, {
5179 "und_AQ",
5180 "_Latn_AQ",
5181 "_AQ"
5182 }, {
5183 "und_Zzzz",
5184 "en_Latn_US",
5185 "en"
5186 }, {
5187 "und_Zzzz_ZZ",
5188 "en_Latn_US",
5189 "en"
5190 }, {
5191 "und_Zzzz_CN",
5192 "zh_Hans_CN",
5193 "zh"
5194 }, {
5195 "und_Zzzz_TW",
5196 "zh_Hant_TW",
5197 "zh_TW"
5198 }, {
5199 "und_Zzzz_HK",
5200 "zh_Hant_HK",
5201 "zh_HK"
5202 }, {
5203 "und_Zzzz_AQ",
5204 "_Latn_AQ",
5205 "_AQ"
5206 }, {
5207 "und_Latn",
5208 "en_Latn_US",
5209 "en"
5210 }, {
5211 "und_Latn_ZZ",
5212 "en_Latn_US",
5213 "en"
5214 }, {
5215 "und_Latn_CN",
5216 "za_Latn_CN",
5217 "za"
5218 }, {
5219 "und_Latn_TW",
5220 "trv_Latn_TW",
5221 "trv"
5222 }, {
5223 "und_Latn_HK",
5224 "zh_Latn_HK",
5225 "zh_Latn_HK"
5226 }, {
5227 "und_Latn_AQ",
5228 "_Latn_AQ",
5229 "_AQ"
5230 }, {
5231 "und_Hans",
5232 "zh_Hans_CN",
5233 "zh"
5234 }, {
5235 "und_Hans_ZZ",
5236 "zh_Hans_CN",
5237 "zh"
5238 }, {
5239 "und_Hans_CN",
5240 "zh_Hans_CN",
5241 "zh"
5242 }, {
5243 "und_Hans_TW",
5244 "zh_Hans_TW",
5245 "zh_Hans_TW"
5246 }, {
5247 "und_Hans_HK",
5248 "zh_Hans_HK",
5249 "zh_Hans_HK"
5250 }, {
5251 "und_Hans_AQ",
5252 "zh_Hans_AQ",
5253 "zh_AQ"
5254 }, {
5255 "und_Hant",
5256 "zh_Hant_TW",
5257 "zh_TW"
5258 }, {
5259 "und_Hant_ZZ",
5260 "zh_Hant_TW",
5261 "zh_TW"
5262 }, {
5263 "und_Hant_CN",
5264 "zh_Hant_CN",
5265 "zh_Hant_CN"
5266 }, {
5267 "und_Hant_TW",
5268 "zh_Hant_TW",
5269 "zh_TW"
5270 }, {
5271 "und_Hant_HK",
5272 "zh_Hant_HK",
5273 "zh_HK"
5274 }, {
5275 "und_Hant_AQ",
5276 "zh_Hant_AQ",
5277 "zh_Hant_AQ"
5278 }, {
5279 "und_Moon",
5280 "en_Moon_US",
5281 "en_Moon"
5282 }, {
5283 "und_Moon_ZZ",
5284 "en_Moon_US",
5285 "en_Moon"
5286 }, {
5287 "und_Moon_CN",
5288 "zh_Moon_CN",
5289 "zh_Moon"
5290 }, {
5291 "und_Moon_TW",
5292 "zh_Moon_TW",
5293 "zh_Moon_TW"
5294 }, {
5295 "und_Moon_HK",
5296 "zh_Moon_HK",
5297 "zh_Moon_HK"
5298 }, {
5299 "und_Moon_AQ",
5300 "_Moon_AQ",
5301 "_Moon_AQ"
5302 }, {
5303 "es",
5304 "es_Latn_ES",
5305 "es"
5306 }, {
5307 "es_ZZ",
5308 "es_Latn_ES",
5309 "es"
5310 }, {
5311 "es_CN",
5312 "es_Latn_CN",
5313 "es_CN"
5314 }, {
5315 "es_TW",
5316 "es_Latn_TW",
5317 "es_TW"
5318 }, {
5319 "es_HK",
5320 "es_Latn_HK",
5321 "es_HK"
5322 }, {
5323 "es_AQ",
5324 "es_Latn_AQ",
5325 "es_AQ"
5326 }, {
5327 "es_Zzzz",
5328 "es_Latn_ES",
5329 "es"
5330 }, {
5331 "es_Zzzz_ZZ",
5332 "es_Latn_ES",
5333 "es"
5334 }, {
5335 "es_Zzzz_CN",
5336 "es_Latn_CN",
5337 "es_CN"
5338 }, {
5339 "es_Zzzz_TW",
5340 "es_Latn_TW",
5341 "es_TW"
5342 }, {
5343 "es_Zzzz_HK",
5344 "es_Latn_HK",
5345 "es_HK"
5346 }, {
5347 "es_Zzzz_AQ",
5348 "es_Latn_AQ",
5349 "es_AQ"
5350 }, {
5351 "es_Latn",
5352 "es_Latn_ES",
5353 "es"
5354 }, {
5355 "es_Latn_ZZ",
5356 "es_Latn_ES",
5357 "es"
5358 }, {
5359 "es_Latn_CN",
5360 "es_Latn_CN",
5361 "es_CN"
5362 }, {
5363 "es_Latn_TW",
5364 "es_Latn_TW",
5365 "es_TW"
5366 }, {
5367 "es_Latn_HK",
5368 "es_Latn_HK",
5369 "es_HK"
5370 }, {
5371 "es_Latn_AQ",
5372 "es_Latn_AQ",
5373 "es_AQ"
5374 }, {
5375 "es_Hans",
5376 "es_Hans_ES",
5377 "es_Hans"
5378 }, {
5379 "es_Hans_ZZ",
5380 "es_Hans_ES",
5381 "es_Hans"
5382 }, {
5383 "es_Hans_CN",
5384 "es_Hans_CN",
5385 "es_Hans_CN"
5386 }, {
5387 "es_Hans_TW",
5388 "es_Hans_TW",
5389 "es_Hans_TW"
5390 }, {
5391 "es_Hans_HK",
5392 "es_Hans_HK",
5393 "es_Hans_HK"
5394 }, {
5395 "es_Hans_AQ",
5396 "es_Hans_AQ",
5397 "es_Hans_AQ"
5398 }, {
5399 "es_Hant",
5400 "es_Hant_ES",
5401 "es_Hant"
5402 }, {
5403 "es_Hant_ZZ",
5404 "es_Hant_ES",
5405 "es_Hant"
5406 }, {
5407 "es_Hant_CN",
5408 "es_Hant_CN",
5409 "es_Hant_CN"
5410 }, {
5411 "es_Hant_TW",
5412 "es_Hant_TW",
5413 "es_Hant_TW"
5414 }, {
5415 "es_Hant_HK",
5416 "es_Hant_HK",
5417 "es_Hant_HK"
5418 }, {
5419 "es_Hant_AQ",
5420 "es_Hant_AQ",
5421 "es_Hant_AQ"
5422 }, {
5423 "es_Moon",
5424 "es_Moon_ES",
5425 "es_Moon"
5426 }, {
5427 "es_Moon_ZZ",
5428 "es_Moon_ES",
5429 "es_Moon"
5430 }, {
5431 "es_Moon_CN",
5432 "es_Moon_CN",
5433 "es_Moon_CN"
5434 }, {
5435 "es_Moon_TW",
5436 "es_Moon_TW",
5437 "es_Moon_TW"
5438 }, {
5439 "es_Moon_HK",
5440 "es_Moon_HK",
5441 "es_Moon_HK"
5442 }, {
5443 "es_Moon_AQ",
5444 "es_Moon_AQ",
5445 "es_Moon_AQ"
5446 }, {
5447 "zh",
5448 "zh_Hans_CN",
5449 "zh"
5450 }, {
5451 "zh_ZZ",
5452 "zh_Hans_CN",
5453 "zh"
5454 }, {
5455 "zh_CN",
5456 "zh_Hans_CN",
5457 "zh"
5458 }, {
5459 "zh_TW",
5460 "zh_Hant_TW",
5461 "zh_TW"
5462 }, {
5463 "zh_HK",
5464 "zh_Hant_HK",
5465 "zh_HK"
5466 }, {
5467 "zh_AQ",
5468 "zh_Hans_AQ",
5469 "zh_AQ"
5470 }, {
5471 "zh_Zzzz",
5472 "zh_Hans_CN",
5473 "zh"
5474 }, {
5475 "zh_Zzzz_ZZ",
5476 "zh_Hans_CN",
5477 "zh"
5478 }, {
5479 "zh_Zzzz_CN",
5480 "zh_Hans_CN",
5481 "zh"
5482 }, {
5483 "zh_Zzzz_TW",
5484 "zh_Hant_TW",
5485 "zh_TW"
5486 }, {
5487 "zh_Zzzz_HK",
5488 "zh_Hant_HK",
5489 "zh_HK"
5490 }, {
5491 "zh_Zzzz_AQ",
5492 "zh_Hans_AQ",
5493 "zh_AQ"
5494 }, {
5495 "zh_Latn",
5496 "zh_Latn_CN",
5497 "zh_Latn"
5498 }, {
5499 "zh_Latn_ZZ",
5500 "zh_Latn_CN",
5501 "zh_Latn"
5502 }, {
5503 "zh_Latn_CN",
5504 "zh_Latn_CN",
5505 "zh_Latn"
5506 }, {
5507 "zh_Latn_TW",
5508 "zh_Latn_TW",
5509 "zh_Latn_TW"
5510 }, {
5511 "zh_Latn_HK",
5512 "zh_Latn_HK",
5513 "zh_Latn_HK"
5514 }, {
5515 "zh_Latn_AQ",
5516 "zh_Latn_AQ",
5517 "zh_Latn_AQ"
5518 }, {
5519 "zh_Hans",
5520 "zh_Hans_CN",
5521 "zh"
5522 }, {
5523 "zh_Hans_ZZ",
5524 "zh_Hans_CN",
5525 "zh"
5526 }, {
5527 "zh_Hans_TW",
5528 "zh_Hans_TW",
5529 "zh_Hans_TW"
5530 }, {
5531 "zh_Hans_HK",
5532 "zh_Hans_HK",
5533 "zh_Hans_HK"
5534 }, {
5535 "zh_Hans_AQ",
5536 "zh_Hans_AQ",
5537 "zh_AQ"
5538 }, {
5539 "zh_Hant",
5540 "zh_Hant_TW",
5541 "zh_TW"
5542 }, {
5543 "zh_Hant_ZZ",
5544 "zh_Hant_TW",
5545 "zh_TW"
5546 }, {
5547 "zh_Hant_CN",
5548 "zh_Hant_CN",
5549 "zh_Hant_CN"
5550 }, {
5551 "zh_Hant_AQ",
5552 "zh_Hant_AQ",
5553 "zh_Hant_AQ"
5554 }, {
5555 "zh_Moon",
5556 "zh_Moon_CN",
5557 "zh_Moon"
5558 }, {
5559 "zh_Moon_ZZ",
5560 "zh_Moon_CN",
5561 "zh_Moon"
5562 }, {
5563 "zh_Moon_CN",
5564 "zh_Moon_CN",
5565 "zh_Moon"
5566 }, {
5567 "zh_Moon_TW",
5568 "zh_Moon_TW",
5569 "zh_Moon_TW"
5570 }, {
5571 "zh_Moon_HK",
5572 "zh_Moon_HK",
5573 "zh_Moon_HK"
5574 }, {
5575 "zh_Moon_AQ",
5576 "zh_Moon_AQ",
5577 "zh_Moon_AQ"
5578 }, {
5579 "art",
5580 "",
5581 ""
5582 }, {
5583 "art_ZZ",
5584 "",
5585 ""
5586 }, {
5587 "art_CN",
5588 "",
5589 ""
5590 }, {
5591 "art_TW",
5592 "",
5593 ""
5594 }, {
5595 "art_HK",
5596 "",
5597 ""
5598 }, {
5599 "art_AQ",
5600 "",
5601 ""
5602 }, {
5603 "art_Zzzz",
5604 "",
5605 ""
5606 }, {
5607 "art_Zzzz_ZZ",
5608 "",
5609 ""
5610 }, {
5611 "art_Zzzz_CN",
5612 "",
5613 ""
5614 }, {
5615 "art_Zzzz_TW",
5616 "",
5617 ""
5618 }, {
5619 "art_Zzzz_HK",
5620 "",
5621 ""
5622 }, {
5623 "art_Zzzz_AQ",
5624 "",
5625 ""
5626 }, {
5627 "art_Latn",
5628 "",
5629 ""
5630 }, {
5631 "art_Latn_ZZ",
5632 "",
5633 ""
5634 }, {
5635 "art_Latn_CN",
5636 "",
5637 ""
5638 }, {
5639 "art_Latn_TW",
5640 "",
5641 ""
5642 }, {
5643 "art_Latn_HK",
5644 "",
5645 ""
5646 }, {
5647 "art_Latn_AQ",
5648 "",
5649 ""
5650 }, {
5651 "art_Hans",
5652 "",
5653 ""
5654 }, {
5655 "art_Hans_ZZ",
5656 "",
5657 ""
5658 }, {
5659 "art_Hans_CN",
5660 "",
5661 ""
5662 }, {
5663 "art_Hans_TW",
5664 "",
5665 ""
5666 }, {
5667 "art_Hans_HK",
5668 "",
5669 ""
5670 }, {
5671 "art_Hans_AQ",
5672 "",
5673 ""
5674 }, {
5675 "art_Hant",
5676 "",
5677 ""
5678 }, {
5679 "art_Hant_ZZ",
5680 "",
5681 ""
5682 }, {
5683 "art_Hant_CN",
5684 "",
5685 ""
5686 }, {
5687 "art_Hant_TW",
5688 "",
5689 ""
5690 }, {
5691 "art_Hant_HK",
5692 "",
5693 ""
5694 }, {
5695 "art_Hant_AQ",
5696 "",
5697 ""
5698 }, {
5699 "art_Moon",
5700 "",
5701 ""
5702 }, {
5703 "art_Moon_ZZ",
5704 "",
5705 ""
5706 }, {
5707 "art_Moon_CN",
5708 "",
5709 ""
5710 }, {
5711 "art_Moon_TW",
5712 "",
5713 ""
5714 }, {
5715 "art_Moon_HK",
5716 "",
5717 ""
5718 }, {
5719 "art_Moon_AQ",
5720 "",
5721 ""
5722 }, {
5723 "de@collation=phonebook",
5724 "de_Latn_DE@collation=phonebook",
5725 "de@collation=phonebook"
5726 }
5727 };
5728
5729 typedef struct errorDataTag {
5730 const char* tag;
5731 const char* expected;
5732 UErrorCode uerror;
5733 int32_t bufferSize;
5734 } errorData;
5735
5736 const errorData maximizeErrors[] = {
5737 {
5738 "enfueiujhytdf",
5739 NULL,
5740 U_ILLEGAL_ARGUMENT_ERROR,
5741 -1
5742 },
5743 {
5744 "en_THUJIOGIURJHGJFURYHFJGURYYYHHGJURHG",
5745 NULL,
5746 U_ILLEGAL_ARGUMENT_ERROR,
5747 -1
5748 },
5749 {
5750 "en_THUJIOGIURJHGJFURYHFJGURYYYHHGJURHG",
5751 NULL,
5752 U_ILLEGAL_ARGUMENT_ERROR,
5753 -1
5754 },
5755 {
5756 "en_Latn_US_POSIX@currency=EURO",
5757 "en_Latn_US_POSIX@currency=EURO",
5758 U_BUFFER_OVERFLOW_ERROR,
5759 29
5760 },
5761 {
5762 "en_Latn_US_POSIX@currency=EURO",
5763 "en_Latn_US_POSIX@currency=EURO",
5764 U_STRING_NOT_TERMINATED_WARNING,
5765 30
5766 }
5767 };
5768
5769 const errorData minimizeErrors[] = {
5770 {
5771 "enfueiujhytdf",
5772 NULL,
5773 U_ILLEGAL_ARGUMENT_ERROR,
5774 -1
5775 },
5776 {
5777 "en_THUJIOGIURJHGJFURYHFJGURYYYHHGJURHG",
5778 NULL,
5779 U_ILLEGAL_ARGUMENT_ERROR,
5780 -1
5781 },
5782 {
5783 "en_Latn_US_POSIX@currency=EURO",
5784 "en__POSIX@currency=EURO",
5785 U_BUFFER_OVERFLOW_ERROR,
5786 22
5787 },
5788 {
5789 "en_Latn_US_POSIX@currency=EURO",
5790 "en__POSIX@currency=EURO",
5791 U_STRING_NOT_TERMINATED_WARNING,
5792 23
5793 }
5794 };
5795
getExpectedReturnValue(const errorData * data)5796 static int32_t getExpectedReturnValue(const errorData* data)
5797 {
5798 if (data->uerror == U_BUFFER_OVERFLOW_ERROR ||
5799 data->uerror == U_STRING_NOT_TERMINATED_WARNING)
5800 {
5801 return (int32_t)strlen(data->expected);
5802 }
5803 else
5804 {
5805 return -1;
5806 }
5807 }
5808
getBufferSize(const errorData * data,int32_t actualSize)5809 static int32_t getBufferSize(const errorData* data, int32_t actualSize)
5810 {
5811 if (data->expected == NULL)
5812 {
5813 return actualSize;
5814 }
5815 else if (data->bufferSize < 0)
5816 {
5817 return (int32_t)strlen(data->expected) + 1;
5818 }
5819 else
5820 {
5821 return data->bufferSize;
5822 }
5823 }
5824
TestLikelySubtags()5825 static void TestLikelySubtags()
5826 {
5827 char buffer[ULOC_FULLNAME_CAPACITY + ULOC_KEYWORD_AND_VALUES_CAPACITY + 1];
5828 int32_t i = 0;
5829
5830 for (; i < UPRV_LENGTHOF(basic_maximize_data); ++i)
5831 {
5832 UErrorCode status = U_ZERO_ERROR;
5833 const char* const minimal = basic_maximize_data[i][0];
5834 const char* const maximal = basic_maximize_data[i][1];
5835
5836 /* const int32_t length = */
5837 uloc_addLikelySubtags(
5838 minimal,
5839 buffer,
5840 sizeof(buffer),
5841 &status);
5842 if (U_FAILURE(status)) {
5843 log_err_status(status, " unexpected failure of uloc_addLikelySubtags(), minimal \"%s\" status %s\n", minimal, u_errorName(status));
5844 status = U_ZERO_ERROR;
5845 }
5846 else if (uprv_strlen(maximal) == 0) {
5847 if (uprv_stricmp(minimal, buffer) != 0) {
5848 log_err(" unexpected maximal value \"%s\" in uloc_addLikelySubtags(), minimal \"%s\" = \"%s\"\n", maximal, minimal, buffer);
5849 }
5850 }
5851 else if (uprv_stricmp(maximal, buffer) != 0) {
5852 log_err(" maximal doesn't match expected %s in uloc_addLikelySubtags(), minimal \"%s\" = %s\n", maximal, minimal, buffer);
5853 }
5854 }
5855
5856 for (i = 0; i < UPRV_LENGTHOF(basic_minimize_data); ++i) {
5857
5858 UErrorCode status = U_ZERO_ERROR;
5859 const char* const maximal = basic_minimize_data[i][0];
5860 const char* const minimal = basic_minimize_data[i][1];
5861
5862 /* const int32_t length = */
5863 uloc_minimizeSubtags(
5864 maximal,
5865 buffer,
5866 sizeof(buffer),
5867 &status);
5868
5869 if (U_FAILURE(status)) {
5870 log_err_status(status, " unexpected failure of uloc_MinimizeSubtags(), maximal \"%s\" status %s\n", maximal, u_errorName(status));
5871 status = U_ZERO_ERROR;
5872 }
5873 else if (uprv_strlen(minimal) == 0) {
5874 if (uprv_stricmp(maximal, buffer) != 0) {
5875 log_err(" unexpected minimal value \"%s\" in uloc_minimizeSubtags(), maximal \"%s\" = \"%s\"\n", minimal, maximal, buffer);
5876 }
5877 }
5878 else if (uprv_stricmp(minimal, buffer) != 0) {
5879 log_err(" minimal doesn't match expected %s in uloc_MinimizeSubtags(), maximal \"%s\" = %s\n", minimal, maximal, buffer);
5880 }
5881 }
5882
5883 for (i = 0; i < UPRV_LENGTHOF(full_data); ++i) {
5884
5885 UErrorCode status = U_ZERO_ERROR;
5886 const char* const minimal = full_data[i][0];
5887 const char* const maximal = full_data[i][1];
5888
5889 /* const int32_t length = */
5890 uloc_addLikelySubtags(
5891 minimal,
5892 buffer,
5893 sizeof(buffer),
5894 &status);
5895 if (U_FAILURE(status)) {
5896 log_err_status(status, " unexpected failure of uloc_addLikelySubtags(), minimal \"%s\" status \"%s\"\n", minimal, u_errorName(status));
5897 status = U_ZERO_ERROR;
5898 }
5899 else if (uprv_strlen(maximal) == 0) {
5900 if (uprv_stricmp(minimal, buffer) != 0) {
5901 log_err(" unexpected maximal value \"%s\" in uloc_addLikelySubtags(), minimal \"%s\" = \"%s\"\n", maximal, minimal, buffer);
5902 }
5903 }
5904 else if (uprv_stricmp(maximal, buffer) != 0) {
5905 log_err(" maximal doesn't match expected \"%s\" in uloc_addLikelySubtags(), minimal \"%s\" = \"%s\"\n", maximal, minimal, buffer);
5906 }
5907 }
5908
5909 for (i = 0; i < UPRV_LENGTHOF(full_data); ++i) {
5910
5911 UErrorCode status = U_ZERO_ERROR;
5912 const char* const maximal = full_data[i][1];
5913 const char* const minimal = full_data[i][2];
5914
5915 if (strlen(maximal) > 0) {
5916
5917 /* const int32_t length = */
5918 uloc_minimizeSubtags(
5919 maximal,
5920 buffer,
5921 sizeof(buffer),
5922 &status);
5923
5924 if (U_FAILURE(status)) {
5925 log_err_status(status, " unexpected failure of uloc_minimizeSubtags(), maximal \"%s\" status %s\n", maximal, u_errorName(status));
5926 status = U_ZERO_ERROR;
5927 }
5928 else if (uprv_strlen(minimal) == 0) {
5929 if (uprv_stricmp(maximal, buffer) != 0) {
5930 log_err(" unexpected minimal value \"%s\" in uloc_minimizeSubtags(), maximal \"%s\" = \"%s\"\n", minimal, maximal, buffer);
5931 }
5932 }
5933 else if (uprv_stricmp(minimal, buffer) != 0) {
5934 log_err(" minimal doesn't match expected %s in uloc_MinimizeSubtags(), maximal \"%s\" = %s\n", minimal, maximal, buffer);
5935 }
5936 }
5937 }
5938
5939 for (i = 0; i < UPRV_LENGTHOF(maximizeErrors); ++i) {
5940
5941 UErrorCode status = U_ZERO_ERROR;
5942 const char* const minimal = maximizeErrors[i].tag;
5943 const char* const maximal = maximizeErrors[i].expected;
5944 const UErrorCode expectedStatus = maximizeErrors[i].uerror;
5945 const int32_t expectedLength = getExpectedReturnValue(&maximizeErrors[i]);
5946 const int32_t bufferSize = getBufferSize(&maximizeErrors[i], sizeof(buffer));
5947
5948 const int32_t length =
5949 uloc_addLikelySubtags(
5950 minimal,
5951 buffer,
5952 bufferSize,
5953 &status);
5954
5955 if (status == U_ZERO_ERROR) {
5956 log_err(" unexpected U_ZERO_ERROR for uloc_addLikelySubtags(), minimal \"%s\" expected status %s\n", minimal, u_errorName(expectedStatus));
5957 status = U_ZERO_ERROR;
5958 }
5959 else if (status != expectedStatus) {
5960 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));
5961 }
5962 else if (length != expectedLength) {
5963 log_err(" unexpected length for uloc_addLikelySubtags(), minimal \"%s\" expected length %d, but got %d\n", minimal, expectedLength, length);
5964 }
5965 else if (status == U_BUFFER_OVERFLOW_ERROR || status == U_STRING_NOT_TERMINATED_WARNING) {
5966 if (uprv_strnicmp(maximal, buffer, bufferSize) != 0) {
5967 log_err(" maximal doesn't match expected %s in uloc_addLikelySubtags(), minimal \"%s\" = %*s\n",
5968 maximal, minimal, (int)sizeof(buffer), buffer);
5969 }
5970 }
5971 }
5972
5973 for (i = 0; i < UPRV_LENGTHOF(minimizeErrors); ++i) {
5974
5975 UErrorCode status = U_ZERO_ERROR;
5976 const char* const maximal = minimizeErrors[i].tag;
5977 const char* const minimal = minimizeErrors[i].expected;
5978 const UErrorCode expectedStatus = minimizeErrors[i].uerror;
5979 const int32_t expectedLength = getExpectedReturnValue(&minimizeErrors[i]);
5980 const int32_t bufferSize = getBufferSize(&minimizeErrors[i], sizeof(buffer));
5981
5982 const int32_t length =
5983 uloc_minimizeSubtags(
5984 maximal,
5985 buffer,
5986 bufferSize,
5987 &status);
5988
5989 if (status == U_ZERO_ERROR) {
5990 log_err(" unexpected U_ZERO_ERROR for uloc_minimizeSubtags(), maximal \"%s\" expected status %s\n", maximal, u_errorName(expectedStatus));
5991 status = U_ZERO_ERROR;
5992 }
5993 else if (status != expectedStatus) {
5994 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));
5995 }
5996 else if (length != expectedLength) {
5997 log_err(" unexpected length for uloc_minimizeSubtags(), maximal \"%s\" expected length %d, but got %d\n", maximal, expectedLength, length);
5998 }
5999 else if (status == U_BUFFER_OVERFLOW_ERROR || status == U_STRING_NOT_TERMINATED_WARNING) {
6000 if (uprv_strnicmp(minimal, buffer, bufferSize) != 0) {
6001 log_err(" minimal doesn't match expected \"%s\" in uloc_minimizeSubtags(), minimal \"%s\" = \"%*s\"\n",
6002 minimal, maximal, (int)sizeof(buffer), buffer);
6003 }
6004 }
6005 }
6006 }
6007
6008 const char* const locale_to_langtag[][3] = {
6009 {"", "und", "und"},
6010 {"en", "en", "en"},
6011 {"en_US", "en-US", "en-US"},
6012 {"iw_IL", "he-IL", "he-IL"},
6013 {"sr_Latn_SR", "sr-Latn-SR", "sr-Latn-SR"},
6014 {"en__POSIX", "en-u-va-posix", "en-u-va-posix"},
6015 {"en_POSIX", "en-u-va-posix", "en-u-va-posix"},
6016 {"en_US_POSIX_VAR", "en-US-posix-x-lvariant-var", NULL}, /* variant POSIX_VAR is processed as regular variant */
6017 {"en_US_VAR_POSIX", "en-US-x-lvariant-var-posix", NULL}, /* variant VAR_POSIX is processed as regular variant */
6018 {"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 */
6019 {"en_US_POSIX@ca=japanese", "en-US-u-ca-japanese-va-posix", "en-US-u-ca-japanese-va-posix"},
6020 {"und_555", "und-555", "und-555"},
6021 {"123", "und", NULL},
6022 {"%$#&", "und", NULL},
6023 {"_Latn", "und-Latn", "und-Latn"},
6024 {"_DE", "und-DE", "und-DE"},
6025 {"und_FR", "und-FR", "und-FR"},
6026 {"th_TH_TH", "th-TH-x-lvariant-th", NULL},
6027 {"bogus", "bogus", "bogus"},
6028 {"foooobarrr", "und", NULL},
6029 {"aa_BB_CYRL", "aa-BB-x-lvariant-cyrl", NULL},
6030 {"en_US_1234", "en-US-1234", "en-US-1234"},
6031 {"en_US_VARIANTA_VARIANTB", "en-US-varianta-variantb", "en-US-varianta-variantb"},
6032 {"ja__9876_5432", "ja-9876-5432", "ja-9876-5432"},
6033 {"zh_Hant__VAR", "zh-Hant-x-lvariant-var", NULL},
6034 {"es__BADVARIANT_GOODVAR", "es-goodvar", NULL},
6035 {"en@calendar=gregorian", "en-u-ca-gregory", "en-u-ca-gregory"},
6036 {"de@collation=phonebook;calendar=gregorian", "de-u-ca-gregory-co-phonebk", "de-u-ca-gregory-co-phonebk"},
6037 {"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"},
6038 {"en@timezone=America/New_York;calendar=japanese", "en-u-ca-japanese-tz-usnyc", "en-u-ca-japanese-tz-usnyc"},
6039 {"en@timezone=US/Eastern", "en-u-tz-usnyc", "en-u-tz-usnyc"},
6040 {"en@x=x-y-z;a=a-b-c", "en-x-x-y-z", NULL},
6041 {"it@collation=badcollationtype;colStrength=identical;cu=usd-eur", "it-u-cu-usd-eur-ks-identic", NULL},
6042 {"en_US_POSIX", "en-US-u-va-posix", "en-US-u-va-posix"},
6043 {"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"},
6044 {"@x=elmer", "x-elmer", "x-elmer"},
6045 {"en@x=elmer", "en-x-elmer", "en-x-elmer"},
6046 {"@x=elmer;a=exta", "und-a-exta-x-elmer", "und-a-exta-x-elmer"},
6047 {"en_US@attribute=attr1-attr2;calendar=gregorian", "en-US-u-attr1-attr2-ca-gregory", "en-US-u-attr1-attr2-ca-gregory"},
6048 /* #12671 */
6049 {"en@a=bar;attribute=baz", "en-a-bar-u-baz", "en-a-bar-u-baz"},
6050 {"en@a=bar;attribute=baz;x=u-foo", "en-a-bar-u-baz-x-u-foo", "en-a-bar-u-baz-x-u-foo"},
6051 {"en@attribute=baz", "en-u-baz", "en-u-baz"},
6052 {"en@attribute=baz;calendar=islamic-civil", "en-u-baz-ca-islamic-civil", "en-u-baz-ca-islamic-civil"},
6053 {"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"},
6054 {"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"},
6055 {"en@9=efg;a=baz", "en-9-efg-a-baz", "en-9-efg-a-baz"},
6056
6057 // Before ICU 64, ICU locale canonicalization had some additional mappings.
6058 // They were removed for ICU-20187 "drop support for long-obsolete locale ID variants".
6059 // The following now uses standard canonicalization.
6060 {"az_AZ_CYRL", "az-AZ-x-lvariant-cyrl", NULL},
6061
6062 {NULL, NULL, NULL}
6063 };
6064
TestToLanguageTag(void)6065 static void TestToLanguageTag(void) {
6066 char langtag[256];
6067 int32_t i;
6068 UErrorCode status;
6069 int32_t len;
6070 const char *inloc;
6071 const char *expected;
6072
6073 for (i = 0; locale_to_langtag[i][0] != NULL; i++) {
6074 inloc = locale_to_langtag[i][0];
6075
6076 /* testing non-strict mode */
6077 status = U_ZERO_ERROR;
6078 langtag[0] = 0;
6079 expected = locale_to_langtag[i][1];
6080
6081 len = uloc_toLanguageTag(inloc, langtag, sizeof(langtag), FALSE, &status);
6082 (void)len; /* Suppress set but not used warning. */
6083 if (U_FAILURE(status)) {
6084 if (expected != NULL) {
6085 log_err("Error returned by uloc_toLanguageTag for locale id [%s] - error: %s\n",
6086 inloc, u_errorName(status));
6087 }
6088 } else {
6089 if (expected == NULL) {
6090 log_err("Error should be returned by uloc_toLanguageTag for locale id [%s], but [%s] is returned without errors\n",
6091 inloc, langtag);
6092 } else if (uprv_strcmp(langtag, expected) != 0) {
6093 log_data_err("uloc_toLanguageTag returned language tag [%s] for input locale [%s] - expected: [%s]. Are you missing data?\n",
6094 langtag, inloc, expected);
6095 }
6096 }
6097
6098 /* testing strict mode */
6099 status = U_ZERO_ERROR;
6100 langtag[0] = 0;
6101 expected = locale_to_langtag[i][2];
6102
6103 len = uloc_toLanguageTag(inloc, langtag, sizeof(langtag), TRUE, &status);
6104 if (U_FAILURE(status)) {
6105 if (expected != NULL) {
6106 log_data_err("Error returned by uloc_toLanguageTag {strict} for locale id [%s] - error: %s Are you missing data?\n",
6107 inloc, u_errorName(status));
6108 }
6109 } else {
6110 if (expected == NULL) {
6111 log_err("Error should be returned by uloc_toLanguageTag {strict} for locale id [%s], but [%s] is returned without errors\n",
6112 inloc, langtag);
6113 } else if (uprv_strcmp(langtag, expected) != 0) {
6114 log_err("uloc_toLanguageTag {strict} returned language tag [%s] for input locale [%s] - expected: [%s]\n",
6115 langtag, inloc, expected);
6116 }
6117 }
6118 }
6119 }
6120
TestBug20132(void)6121 static void TestBug20132(void) {
6122 char langtag[256];
6123 UErrorCode status;
6124 int32_t len;
6125
6126 static const char inloc[] = "en-C";
6127 static const char expected[] = "en-x-lvariant-c";
6128 const int32_t expected_len = (int32_t)uprv_strlen(expected);
6129
6130 /* Before ICU-20132 was fixed, calling uloc_toLanguageTag() with a too small
6131 * buffer would not immediately return the buffer size actually needed, but
6132 * instead require several iterations before getting the correct size. */
6133
6134 status = U_ZERO_ERROR;
6135 len = uloc_toLanguageTag(inloc, langtag, 1, FALSE, &status);
6136
6137 if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) {
6138 log_data_err("Error returned by uloc_toLanguageTag for locale id [%s] - error: %s Are you missing data?\n",
6139 inloc, u_errorName(status));
6140 }
6141
6142 if (len != expected_len) {
6143 log_err("Bad length returned by uloc_toLanguageTag for locale id [%s]: %i != %i\n", inloc, len, expected_len);
6144 }
6145
6146 status = U_ZERO_ERROR;
6147 len = uloc_toLanguageTag(inloc, langtag, expected_len, FALSE, &status);
6148
6149 if (U_FAILURE(status)) {
6150 log_data_err("Error returned by uloc_toLanguageTag for locale id [%s] - error: %s Are you missing data?\n",
6151 inloc, u_errorName(status));
6152 }
6153
6154 if (len != expected_len) {
6155 log_err("Bad length returned by uloc_toLanguageTag for locale id [%s]: %i != %i\n", inloc, len, expected_len);
6156 } else if (uprv_strncmp(langtag, expected, expected_len) != 0) {
6157 log_data_err("uloc_toLanguageTag returned language tag [%.*s] for input locale [%s] - expected: [%s]. Are you missing data?\n",
6158 len, langtag, inloc, expected);
6159 }
6160 }
6161
6162 #define FULL_LENGTH -1
6163 static const struct {
6164 const char *bcpID;
6165 const char *locID;
6166 int32_t len;
6167 } langtag_to_locale[] = {
6168 {"en", "en", FULL_LENGTH},
6169 {"en-us", "en_US", FULL_LENGTH},
6170 {"und-US", "_US", FULL_LENGTH},
6171 {"und-latn", "_Latn", FULL_LENGTH},
6172 {"en-US-posix", "en_US_POSIX", FULL_LENGTH},
6173 {"de-de_euro", "de", 2},
6174 {"kok-IN", "kok_IN", FULL_LENGTH},
6175 {"123", "", 0},
6176 {"en_us", "", 0},
6177 {"en-latn-x", "en_Latn", 7},
6178 {"art-lojban", "jbo", FULL_LENGTH},
6179 {"zh-hakka", "hak", FULL_LENGTH},
6180 {"zh-cmn-CH", "cmn_CH", FULL_LENGTH},
6181 {"zh-cmn-CH-u-co-pinyin", "cmn_CH@collation=pinyin", FULL_LENGTH},
6182 {"xxx-yy", "xxx_YY", FULL_LENGTH},
6183 {"fr-234", "fr_234", FULL_LENGTH},
6184 {"i-default", "en@x=i-default", FULL_LENGTH},
6185 {"i-test", "", 0},
6186 {"ja-jp-jp", "ja_JP", 5},
6187 {"bogus", "bogus", FULL_LENGTH},
6188 {"boguslang", "", 0},
6189 {"EN-lATN-us", "en_Latn_US", FULL_LENGTH},
6190 {"und-variant-1234", "__VARIANT_1234", FULL_LENGTH},
6191 {"und-varzero-var1-vartwo", "__VARZERO", 11},
6192 {"en-u-ca-gregory", "en@calendar=gregorian", FULL_LENGTH},
6193 {"en-U-cu-USD", "en@currency=usd", FULL_LENGTH},
6194 {"en-US-u-va-posix", "en_US_POSIX", FULL_LENGTH},
6195 {"en-us-u-ca-gregory-va-posix", "en_US_POSIX@calendar=gregorian", FULL_LENGTH},
6196 {"en-us-posix-u-va-posix", "en_US_POSIX@va=posix", FULL_LENGTH},
6197 {"en-us-u-va-posix2", "en_US@va=posix2", FULL_LENGTH},
6198 {"en-us-vari1-u-va-posix", "en_US_VARI1@va=posix", FULL_LENGTH},
6199 {"ar-x-1-2-3", "ar@x=1-2-3", FULL_LENGTH},
6200 {"fr-u-nu-latn-cu-eur", "fr@currency=eur;numbers=latn", FULL_LENGTH},
6201 {"de-k-kext-u-co-phonebk-nu-latn", "de@collation=phonebook;k=kext;numbers=latn", FULL_LENGTH},
6202 {"ja-u-cu-jpy-ca-jp", "ja@calendar=yes;currency=jpy;jp=yes", FULL_LENGTH},
6203 {"en-us-u-tz-usnyc", "en_US@timezone=America/New_York", FULL_LENGTH},
6204 {"und-a-abc-def", "und@a=abc-def", FULL_LENGTH},
6205 {"zh-u-ca-chinese-x-u-ca-chinese", "zh@calendar=chinese;x=u-ca-chinese", FULL_LENGTH},
6206 {"x-elmer", "@x=elmer", FULL_LENGTH},
6207 {"en-US-u-attr1-attr2-ca-gregory", "en_US@attribute=attr1-attr2;calendar=gregorian", FULL_LENGTH},
6208 {"sr-u-kn", "sr@colnumeric=yes", FULL_LENGTH},
6209 {"de-u-kn-co-phonebk", "de@collation=phonebook;colnumeric=yes", FULL_LENGTH},
6210 {"en-u-attr2-attr1-kn-kb", "en@attribute=attr1-attr2;colbackwards=yes;colnumeric=yes", FULL_LENGTH},
6211 {"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},
6212 {"de-u-xc-xphonebk-co-phonebk-ca-buddhist-mo-very-lo-extensi-xd-that-de-should-vc-probably-xz-killthebuffer",
6213 "de@calendar=buddhist;collation=phonebook;de=should;lo=extensi;mo=very;vc=probably;xc=xphonebk;xd=that;xz=yes", 91},
6214 {"de-1901-1901", "de__1901", 7},
6215 {"de-DE-1901-1901", "de_DE_1901", 10},
6216 {"en-a-bbb-a-ccc", "en@a=bbb", 8},
6217 /* #12761 */
6218 {"en-a-bar-u-baz", "en@a=bar;attribute=baz", FULL_LENGTH},
6219 {"en-a-bar-u-baz-x-u-foo", "en@a=bar;attribute=baz;x=u-foo", FULL_LENGTH},
6220 {"en-u-baz", "en@attribute=baz", FULL_LENGTH},
6221 {"en-u-baz-ca-islamic-civil", "en@attribute=baz;calendar=islamic-civil", FULL_LENGTH},
6222 {"en-a-bar-u-ca-islamic-civil-x-u-foo", "en@a=bar;calendar=islamic-civil;x=u-foo", FULL_LENGTH},
6223 {"en-a-bar-u-baz-ca-islamic-civil-x-u-foo", "en@a=bar;attribute=baz;calendar=islamic-civil;x=u-foo", FULL_LENGTH},
6224 {"und-Arab-u-em-emoji", "_Arab@em=emoji", FULL_LENGTH},
6225 {"und-Latn-u-em-emoji", "_Latn@em=emoji", FULL_LENGTH},
6226 {"und-Latn-DE-u-em-emoji", "_Latn_DE@em=emoji", FULL_LENGTH},
6227 {"und-Zzzz-DE-u-em-emoji", "_Zzzz_DE@em=emoji", FULL_LENGTH},
6228 {"und-DE-u-em-emoji", "_DE@em=emoji", FULL_LENGTH},
6229 // #20098
6230 {"hant-cmn-cn", "hant", 4},
6231 {"zh-cmn-TW", "cmn_TW", FULL_LENGTH},
6232 {"zh-x_t-ab", "zh", 2},
6233 {"zh-hans-cn-u-ca-x_t-u", "zh_Hans_CN@calendar=yes", 15},
6234 /* #20140 dupe keys in U-extension */
6235 {"zh-u-ca-chinese-ca-gregory", "zh@calendar=chinese", FULL_LENGTH},
6236 {"zh-u-ca-gregory-co-pinyin-ca-chinese", "zh@calendar=gregorian;collation=pinyin", FULL_LENGTH},
6237 {"de-latn-DE-1901-u-co-phonebk-co-pinyin-ca-gregory", "de_Latn_DE_1901@calendar=gregorian;collation=phonebook", FULL_LENGTH},
6238 {"th-u-kf-nu-thai-kf-false", "th@colcasefirst=yes;numbers=thai", FULL_LENGTH},
6239 /* #9562 IANA language tag data update */
6240 {"en-gb-oed", "en_GB_OXENDICT", FULL_LENGTH},
6241 {"i-navajo", "nv", FULL_LENGTH},
6242 {"i-navajo-a-foo", "nv@a=foo", FULL_LENGTH},
6243 {"i-navajo-latn-us", "nv_Latn_US", FULL_LENGTH},
6244 {"sgn-br", "bzs", FULL_LENGTH},
6245 {"sgn-br-u-co-phonebk", "bzs@collation=phonebook", FULL_LENGTH},
6246 {"ja-latn-hepburn-heploc", "ja_Latn__ALALC97", FULL_LENGTH},
6247 {"ja-latn-hepburn-heploc-u-ca-japanese", "ja_Latn__ALALC97@calendar=japanese", FULL_LENGTH},
6248 {"en-a-bcde-0-fgh", "en@0=fgh;a=bcde", FULL_LENGTH},
6249 };
6250
TestForLanguageTag(void)6251 static void TestForLanguageTag(void) {
6252 char locale[256];
6253 int32_t i;
6254 UErrorCode status;
6255 int32_t parsedLen;
6256 int32_t expParsedLen;
6257
6258 for (i = 0; i < UPRV_LENGTHOF(langtag_to_locale); i++) {
6259 status = U_ZERO_ERROR;
6260 locale[0] = 0;
6261 expParsedLen = langtag_to_locale[i].len;
6262 if (expParsedLen == FULL_LENGTH) {
6263 expParsedLen = (int32_t)uprv_strlen(langtag_to_locale[i].bcpID);
6264 }
6265 uloc_forLanguageTag(langtag_to_locale[i].bcpID, locale, sizeof(locale), &parsedLen, &status);
6266 if (U_FAILURE(status)) {
6267 log_err_status(status, "Error returned by uloc_forLanguageTag for language tag [%s] - error: %s\n",
6268 langtag_to_locale[i].bcpID, u_errorName(status));
6269 } else {
6270 if (uprv_strcmp(langtag_to_locale[i].locID, locale) != 0) {
6271 log_data_err("uloc_forLanguageTag returned locale [%s] for input language tag [%s] - expected: [%s]\n",
6272 locale, langtag_to_locale[i].bcpID, langtag_to_locale[i].locID);
6273 }
6274 if (parsedLen != expParsedLen) {
6275 log_err("uloc_forLanguageTag parsed length of %d for input language tag [%s] - expected parsed length: %d\n",
6276 parsedLen, langtag_to_locale[i].bcpID, expParsedLen);
6277 }
6278 }
6279 }
6280 }
6281
6282 static const struct {
6283 const char *input;
6284 const char *canonical;
6285 } langtag_to_canonical[] = {
6286 {"de-DD", "de-DE"},
6287 {"de-DD-u-co-phonebk", "de-DE-u-co-phonebk"},
6288 {"jw-id", "jv-ID"},
6289 {"jw-id-u-ca-islamic-civil", "jv-ID-u-ca-islamic-civil"},
6290 {"mo-md", "ro-MD"},
6291 {"my-bu-u-nu-mymr", "my-MM-u-nu-mymr"},
6292 {"yuu-ru", "yug-RU"},
6293 };
6294
6295
TestLangAndRegionCanonicalize(void)6296 static void TestLangAndRegionCanonicalize(void) {
6297 char locale[256];
6298 char canonical[256];
6299 int32_t i;
6300 UErrorCode status;
6301 for (i = 0; i < UPRV_LENGTHOF(langtag_to_canonical); i++) {
6302 status = U_ZERO_ERROR;
6303 const char* input = langtag_to_canonical[i].input;
6304 uloc_forLanguageTag(input, locale, sizeof(locale), NULL, &status);
6305 uloc_toLanguageTag(locale, canonical, sizeof(canonical), TRUE, &status);
6306 if (U_FAILURE(status)) {
6307 log_err_status(status, "Error returned by uloc_forLanguageTag or uloc_toLanguageTag "
6308 "for language tag [%s] - error: %s\n", input, u_errorName(status));
6309 } else {
6310 const char* expected_canonical = langtag_to_canonical[i].canonical;
6311 if (uprv_strcmp(expected_canonical, canonical) != 0) {
6312 log_data_err("input language tag [%s] is canonicalized to [%s] - expected: [%s]\n",
6313 input, canonical, expected_canonical);
6314 }
6315 }
6316 }
6317 }
6318
TestToUnicodeLocaleKey(void)6319 static void TestToUnicodeLocaleKey(void)
6320 {
6321 /* $IN specifies the result should be the input pointer itself */
6322 static const char* DATA[][2] = {
6323 {"calendar", "ca"},
6324 {"CALEndar", "ca"}, /* difference casing */
6325 {"ca", "ca"}, /* bcp key itself */
6326 {"kv", "kv"}, /* no difference between legacy and bcp */
6327 {"foo", NULL}, /* unknown, bcp ill-formed */
6328 {"ZZ", "$IN"}, /* unknown, bcp well-formed - */
6329 {NULL, NULL}
6330 };
6331
6332 int32_t i;
6333 for (i = 0; DATA[i][0] != NULL; i++) {
6334 const char* keyword = DATA[i][0];
6335 const char* expected = DATA[i][1];
6336 const char* bcpKey = NULL;
6337
6338 bcpKey = uloc_toUnicodeLocaleKey(keyword);
6339 if (expected == NULL) {
6340 if (bcpKey != NULL) {
6341 log_err("toUnicodeLocaleKey: keyword=%s => %s, expected=NULL\n", keyword, bcpKey);
6342 }
6343 } else if (bcpKey == NULL) {
6344 log_data_err("toUnicodeLocaleKey: keyword=%s => NULL, expected=%s\n", keyword, expected);
6345 } else if (uprv_strcmp(expected, "$IN") == 0) {
6346 if (bcpKey != keyword) {
6347 log_err("toUnicodeLocaleKey: keyword=%s => %s, expected=%s(input pointer)\n", keyword, bcpKey, keyword);
6348 }
6349 } else if (uprv_strcmp(bcpKey, expected) != 0) {
6350 log_err("toUnicodeLocaleKey: keyword=%s => %s, expected=%s\n", keyword, bcpKey, expected);
6351 }
6352 }
6353 }
6354
TestBug20321UnicodeLocaleKey(void)6355 static void TestBug20321UnicodeLocaleKey(void)
6356 {
6357 // key = alphanum alpha ;
6358 static const char* invalid[] = {
6359 "a0",
6360 "00",
6361 "a@",
6362 "0@",
6363 "@a",
6364 "@a",
6365 "abc",
6366 "0bc",
6367 };
6368 for (int i = 0; i < UPRV_LENGTHOF(invalid); i++) {
6369 const char* bcpKey = NULL;
6370 bcpKey = uloc_toUnicodeLocaleKey(invalid[i]);
6371 if (bcpKey != NULL) {
6372 log_err("toUnicodeLocaleKey: keyword=%s => %s, expected=NULL\n", invalid[i], bcpKey);
6373 }
6374 }
6375 static const char* valid[] = {
6376 "aa",
6377 "0a",
6378 };
6379 for (int i = 0; i < UPRV_LENGTHOF(valid); i++) {
6380 const char* bcpKey = NULL;
6381 bcpKey = uloc_toUnicodeLocaleKey(valid[i]);
6382 if (bcpKey == NULL) {
6383 log_err("toUnicodeLocaleKey: keyword=%s => NULL, expected!=NULL\n", valid[i]);
6384 }
6385 }
6386 }
6387
TestToLegacyKey(void)6388 static void TestToLegacyKey(void)
6389 {
6390 /* $IN specifies the result should be the input pointer itself */
6391 static const char* DATA[][2] = {
6392 {"kb", "colbackwards"},
6393 {"kB", "colbackwards"}, /* different casing */
6394 {"Collation", "collation"}, /* keyword itself with different casing */
6395 {"kv", "kv"}, /* no difference between legacy and bcp */
6396 {"foo", "$IN"}, /* unknown, bcp ill-formed */
6397 {"ZZ", "$IN"}, /* unknown, bcp well-formed */
6398 {"e=mc2", NULL}, /* unknown, bcp/legacy ill-formed */
6399 {NULL, NULL}
6400 };
6401
6402 int32_t i;
6403 for (i = 0; DATA[i][0] != NULL; i++) {
6404 const char* keyword = DATA[i][0];
6405 const char* expected = DATA[i][1];
6406 const char* legacyKey = NULL;
6407
6408 legacyKey = uloc_toLegacyKey(keyword);
6409 if (expected == NULL) {
6410 if (legacyKey != NULL) {
6411 log_err("toLegacyKey: keyword=%s => %s, expected=NULL\n", keyword, legacyKey);
6412 }
6413 } else if (legacyKey == NULL) {
6414 log_err("toLegacyKey: keyword=%s => NULL, expected=%s\n", keyword, expected);
6415 } else if (uprv_strcmp(expected, "$IN") == 0) {
6416 if (legacyKey != keyword) {
6417 log_err("toLegacyKey: keyword=%s => %s, expected=%s(input pointer)\n", keyword, legacyKey, keyword);
6418 }
6419 } else if (uprv_strcmp(legacyKey, expected) != 0) {
6420 log_data_err("toUnicodeLocaleKey: keyword=%s, %s, expected=%s\n", keyword, legacyKey, expected);
6421 }
6422 }
6423 }
6424
TestToUnicodeLocaleType(void)6425 static void TestToUnicodeLocaleType(void)
6426 {
6427 /* $IN specifies the result should be the input pointer itself */
6428 static const char* DATA[][3] = {
6429 {"tz", "Asia/Kolkata", "inccu"},
6430 {"calendar", "gregorian", "gregory"},
6431 {"ca", "gregorian", "gregory"},
6432 {"ca", "Gregorian", "gregory"},
6433 {"ca", "buddhist", "buddhist"},
6434 {"Calendar", "Japanese", "japanese"},
6435 {"calendar", "Islamic-Civil", "islamic-civil"},
6436 {"calendar", "islamicc", "islamic-civil"}, /* bcp type alias */
6437 {"colalternate", "NON-IGNORABLE", "noignore"},
6438 {"colcaselevel", "yes", "true"},
6439 {"rg", "GBzzzz", "$IN"},
6440 {"tz", "america/new_york", "usnyc"},
6441 {"tz", "Asia/Kolkata", "inccu"},
6442 {"timezone", "navajo", "usden"},
6443 {"ca", "aaaa", "$IN"}, /* unknown type, well-formed type */
6444 {"ca", "gregory-japanese-islamic", "$IN"}, /* unknown type, well-formed type */
6445 {"zz", "gregorian", NULL}, /* unknown key, ill-formed type */
6446 {"co", "foo-", NULL}, /* unknown type, ill-formed type */
6447 {"variableTop", "00A0", "$IN"}, /* valid codepoints type */
6448 {"variableTop", "wxyz", "$IN"}, /* invalid codepoints type - return as is for now */
6449 {"kr", "space-punct", "space-punct"}, /* valid reordercode type */
6450 {"kr", "digit-spacepunct", NULL}, /* invalid (bcp ill-formed) reordercode type */
6451 {NULL, NULL, NULL}
6452 };
6453
6454 int32_t i;
6455 for (i = 0; DATA[i][0] != NULL; i++) {
6456 const char* keyword = DATA[i][0];
6457 const char* value = DATA[i][1];
6458 const char* expected = DATA[i][2];
6459 const char* bcpType = NULL;
6460
6461 bcpType = uloc_toUnicodeLocaleType(keyword, value);
6462 if (expected == NULL) {
6463 if (bcpType != NULL) {
6464 log_err("toUnicodeLocaleType: keyword=%s, value=%s => %s, expected=NULL\n", keyword, value, bcpType);
6465 }
6466 } else if (bcpType == NULL) {
6467 log_data_err("toUnicodeLocaleType: keyword=%s, value=%s => NULL, expected=%s\n", keyword, value, expected);
6468 } else if (uprv_strcmp(expected, "$IN") == 0) {
6469 if (bcpType != value) {
6470 log_err("toUnicodeLocaleType: keyword=%s, value=%s => %s, expected=%s(input pointer)\n", keyword, value, bcpType, value);
6471 }
6472 } else if (uprv_strcmp(bcpType, expected) != 0) {
6473 log_data_err("toUnicodeLocaleType: keyword=%s, value=%s => %s, expected=%s\n", keyword, value, bcpType, expected);
6474 }
6475 }
6476 }
6477
TestToLegacyType(void)6478 static void TestToLegacyType(void)
6479 {
6480 /* $IN specifies the result should be the input pointer itself */
6481 static const char* DATA[][3] = {
6482 {"calendar", "gregory", "gregorian"},
6483 {"ca", "gregory", "gregorian"},
6484 {"ca", "Gregory", "gregorian"},
6485 {"ca", "buddhist", "buddhist"},
6486 {"Calendar", "Japanese", "japanese"},
6487 {"calendar", "Islamic-Civil", "islamic-civil"},
6488 {"calendar", "islamicc", "islamic-civil"}, /* bcp type alias */
6489 {"colalternate", "noignore", "non-ignorable"},
6490 {"colcaselevel", "true", "yes"},
6491 {"rg", "gbzzzz", "gbzzzz"},
6492 {"tz", "usnyc", "America/New_York"},
6493 {"tz", "inccu", "Asia/Calcutta"},
6494 {"timezone", "usden", "America/Denver"},
6495 {"timezone", "usnavajo", "America/Denver"}, /* bcp type alias */
6496 {"colstrength", "quarternary", "quaternary"}, /* type alias */
6497 {"ca", "aaaa", "$IN"}, /* unknown type */
6498 {"calendar", "gregory-japanese-islamic", "$IN"}, /* unknown type, well-formed type */
6499 {"zz", "gregorian", "$IN"}, /* unknown key, bcp ill-formed type */
6500 {"ca", "gregorian-calendar", "$IN"}, /* known key, bcp ill-formed type */
6501 {"co", "e=mc2", NULL}, /* known key, ill-formed bcp/legacy type */
6502 {"variableTop", "00A0", "$IN"}, /* valid codepoints type */
6503 {"variableTop", "wxyz", "$IN"}, /* invalid codepoints type - return as is for now */
6504 {"kr", "space-punct", "space-punct"}, /* valid reordercode type */
6505 {"kr", "digit-spacepunct", "digit-spacepunct"}, /* invalid reordercode type, but ok for legacy syntax */
6506 {NULL, NULL, NULL}
6507 };
6508
6509 int32_t i;
6510 for (i = 0; DATA[i][0] != NULL; i++) {
6511 const char* keyword = DATA[i][0];
6512 const char* value = DATA[i][1];
6513 const char* expected = DATA[i][2];
6514 const char* legacyType = NULL;
6515
6516 legacyType = uloc_toLegacyType(keyword, value);
6517 if (expected == NULL) {
6518 if (legacyType != NULL) {
6519 log_err("toLegacyType: keyword=%s, value=%s => %s, expected=NULL\n", keyword, value, legacyType);
6520 }
6521 } else if (legacyType == NULL) {
6522 log_err("toLegacyType: keyword=%s, value=%s => NULL, expected=%s\n", keyword, value, expected);
6523 } else if (uprv_strcmp(expected, "$IN") == 0) {
6524 if (legacyType != value) {
6525 log_err("toLegacyType: keyword=%s, value=%s => %s, expected=%s(input pointer)\n", keyword, value, legacyType, value);
6526 }
6527 } else if (uprv_strcmp(legacyType, expected) != 0) {
6528 log_data_err("toLegacyType: keyword=%s, value=%s => %s, expected=%s\n", keyword, value, legacyType, expected);
6529 } else {
6530 log_verbose("toLegacyType: keyword=%s, value=%s => %s\n", keyword, value, legacyType);
6531 }
6532 }
6533 }
6534
6535
6536
test_unicode_define(const char * namech,char ch,const char * nameu,UChar uch)6537 static void test_unicode_define(const char *namech, char ch, const char *nameu, UChar uch)
6538 {
6539 UChar asUch[1];
6540 asUch[0]=0;
6541 log_verbose("Testing whether %s[\\x%02x,'%c'] == %s[U+%04X]\n", namech, ch,(int)ch, nameu, (int) uch);
6542 u_charsToUChars(&ch, asUch, 1);
6543 if(asUch[0] != uch) {
6544 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);
6545 } else {
6546 log_verbose(" .. OK, == U+%04X\n", (int)asUch[0]);
6547 }
6548 }
6549
6550 #define TEST_UNICODE_DEFINE(x,y) test_unicode_define(#x, (char)(x), #y, (UChar)(y))
6551
TestUnicodeDefines(void)6552 static void TestUnicodeDefines(void) {
6553 TEST_UNICODE_DEFINE(ULOC_KEYWORD_SEPARATOR, ULOC_KEYWORD_SEPARATOR_UNICODE);
6554 TEST_UNICODE_DEFINE(ULOC_KEYWORD_ASSIGN, ULOC_KEYWORD_ASSIGN_UNICODE);
6555 TEST_UNICODE_DEFINE(ULOC_KEYWORD_ITEM_SEPARATOR, ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE);
6556 }
6557
TestIsRightToLeft()6558 static void TestIsRightToLeft() {
6559 // API test only. More test cases in intltest/LocaleTest.
6560 if(uloc_isRightToLeft("root") || !uloc_isRightToLeft("EN-HEBR")) {
6561 log_err("uloc_isRightToLeft() failed");
6562 }
6563 }
6564
6565 typedef struct {
6566 const char * badLocaleID;
6567 const char * displayLocale;
6568 const char * expectedName;
6569 UErrorCode expectedStatus;
6570 } BadLocaleItem;
6571
6572 static const BadLocaleItem badLocaleItems[] = {
6573 { "-9223372036854775808", "en", "Unknown language (9223372036854775808)", U_USING_DEFAULT_WARNING },
6574 /* add more in the future */
6575 { NULL, NULL, NULL, U_ZERO_ERROR } /* terminator */
6576 };
6577
6578 enum { kUBufDispNameMax = 128, kBBufDispNameMax = 256 };
6579
TestBadLocaleIDs()6580 static void TestBadLocaleIDs() {
6581 const BadLocaleItem* itemPtr;
6582 for (itemPtr = badLocaleItems; itemPtr->badLocaleID != NULL; itemPtr++) {
6583 UChar ubufExpect[kUBufDispNameMax], ubufGet[kUBufDispNameMax];
6584 UErrorCode status = U_ZERO_ERROR;
6585 int32_t ulenExpect = u_unescape(itemPtr->expectedName, ubufExpect, kUBufDispNameMax);
6586 int32_t ulenGet = uloc_getDisplayName(itemPtr->badLocaleID, itemPtr->displayLocale, ubufGet, kUBufDispNameMax, &status);
6587 if (status != itemPtr->expectedStatus ||
6588 (U_SUCCESS(status) && (ulenGet != ulenExpect || u_strncmp(ubufGet, ubufExpect, ulenExpect) != 0))) {
6589 char bbufExpect[kBBufDispNameMax], bbufGet[kBBufDispNameMax];
6590 u_austrncpy(bbufExpect, ubufExpect, ulenExpect);
6591 u_austrncpy(bbufGet, ubufGet, ulenGet);
6592 log_err("FAIL: For localeID %s, displayLocale %s, calling uloc_getDisplayName:\n"
6593 " expected status %-26s, name (len %2d): %s\n"
6594 " got status %-26s, name (len %2d): %s\n",
6595 itemPtr->badLocaleID, itemPtr->displayLocale,
6596 u_errorName(itemPtr->expectedStatus), ulenExpect, bbufExpect,
6597 u_errorName(status), ulenGet, bbufGet );
6598 }
6599 }
6600 }
6601
6602 // Test case for ICU-20370.
6603 // The issue shows as an Addresss Sanitizer failure.
TestBug20370()6604 static void TestBug20370() {
6605 const char *localeID = "x-privatebutreallylongtagfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar";
6606 uint32_t lcid = uloc_getLCID(localeID);
6607 if (lcid != 0) {
6608 log_err("FAIL: Expected LCID value of 0 for invalid localeID input.");
6609 }
6610 }
6611
6612 // Test case for ICU-20149
6613 // Handle the duplicate U extension attribute
TestBug20149()6614 static void TestBug20149() {
6615 const char *localeID = "zh-u-foo-foo-co-pinyin";
6616 char locale[256];
6617 UErrorCode status = U_ZERO_ERROR;
6618 int32_t parsedLen;
6619 locale[0] = '\0';
6620 uloc_forLanguageTag(localeID, locale, sizeof(locale), &parsedLen, &status);
6621 if (U_FAILURE(status) ||
6622 0 !=strcmp("zh@attribute=foo;collation=pinyin", locale)) {
6623 log_err("ERROR: in uloc_forLanguageTag %s return %s\n", myErrorName(status), locale);
6624 }
6625 }
6626