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 #include <algorithm>
10 #include <functional>
11 #include <iterator>
12 #include <set>
13 #include <utility>
14
15 #include "loctest.h"
16 #include "unicode/localebuilder.h"
17 #include "unicode/localpointer.h"
18 #include "unicode/decimfmt.h"
19 #include "unicode/ucurr.h"
20 #include "unicode/smpdtfmt.h"
21 #include "unicode/strenum.h"
22 #include "unicode/dtfmtsym.h"
23 #include "unicode/brkiter.h"
24 #include "unicode/coll.h"
25 #include "unicode/ustring.h"
26 #include "unicode/std_string.h"
27 #include "charstr.h"
28 #include "cmemory.h"
29 #include "cstring.h"
30 #include <stdio.h>
31 #include <string.h>
32 #include "putilimp.h"
33 #include "hash.h"
34 #include "locmap.h"
35
36 static const char* const rawData[33][8] = {
37
38 // language code
39 { "en", "fr", "ca", "el", "no", "it", "xx", "zh" },
40 // script code
41 { "", "", "", "", "", "", "", "Hans" },
42 // country code
43 { "US", "FR", "ES", "GR", "NO", "", "YY", "CN" },
44 // variant code
45 { "", "", "", "", "NY", "", "", "" },
46 // full name
47 { "en_US", "fr_FR", "ca_ES", "el_GR", "no_NO_NY", "it", "xx_YY", "zh_Hans_CN" },
48 // ISO-3 language
49 { "eng", "fra", "cat", "ell", "nor", "ita", "", "zho" },
50 // ISO-3 country
51 { "USA", "FRA", "ESP", "GRC", "NOR", "", "", "CHN" },
52 // LCID
53 { "409", "40c", "403", "408", "814", "10", "0", "804" },
54
55 // display language (English)
56 { "English", "French", "Catalan", "Greek", "Norwegian", "Italian", "xx", "Chinese" },
57 // display script (English)
58 { "", "", "", "", "", "", "", "Simplified Han" },
59 // display country (English)
60 { "United States", "France", "Spain", "Greece", "Norway", "", "YY", "China" },
61 // display variant (English)
62 { "", "", "", "", "NY", "", "", ""},
63 // display name (English)
64 // Updated no_NO_NY English display name for new pattern-based algorithm
65 // (part of Euro support).
66 { "English (United States)", "French (France)", "Catalan (Spain)", "Greek (Greece)", "Norwegian (Norway, NY)", "Italian", "xx (YY)", "Chinese (Simplified, China)" },
67
68 // display language (French)
69 { "anglais", "fran\\u00E7ais", "catalan", "grec", "norv\\u00E9gien", "italien", "xx", "chinois" },
70 // display script (French)
71 { "", "", "", "", "", "", "", "sinogrammes simplifi\\u00E9s" },
72 // display country (French)
73 { "\\u00C9tats-Unis", "France", "Espagne", "Gr\\u00E8ce", "Norv\\u00E8ge", "", "YY", "Chine" },
74 // display variant (French)
75 { "", "", "", "", "NY", "", "", "" },
76 // display name (French)
77 //{ "anglais (Etats-Unis)", "francais (France)", "catalan (Espagne)", "grec (Grece)", "norvegien (Norvege,Nynorsk)", "italien", "xx (YY)" },
78 { "anglais (\\u00C9tats-Unis)", "fran\\u00E7ais (France)", "catalan (Espagne)", "grec (Gr\\u00E8ce)", "norv\\u00E9gien (Norv\\u00E8ge, NY)", "italien", "xx (YY)", "chinois (simplifi\\u00E9, Chine)" },
79
80
81 /* display language (Catalan) */
82 { "angl\\u00E8s", "franc\\u00E8s", "catal\\u00E0", "grec", "noruec", "itali\\u00E0", "", "xin\\u00E8s" },
83 /* display script (Catalan) */
84 { "", "", "", "", "", "", "", "han simplificat" },
85 /* display country (Catalan) */
86 { "Estats Units", "Fran\\u00E7a", "Espanya", "Gr\\u00E8cia", "Noruega", "", "", "Xina" },
87 /* display variant (Catalan) */
88 { "", "", "", "", "NY", "", "" },
89 /* display name (Catalan) */
90 { "angl\\u00E8s (Estats Units)", "franc\\u00E8s (Fran\\u00E7a)", "catal\\u00E0 (Espanya)", "grec (Gr\\u00E8cia)", "noruec (Noruega, NY)", "itali\\u00E0", "", "xin\\u00E8s (simplificat, Xina)" },
91
92 // display language (Greek)[actual values listed below]
93 { "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac",
94 "\\u0393\\u03b1\\u03bb\\u03bb\\u03b9\\u03ba\\u03ac",
95 "\\u039a\\u03b1\\u03c4\\u03b1\\u03bb\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac",
96 "\\u0395\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac",
97 "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac",
98 "\\u0399\\u03c4\\u03b1\\u03bb\\u03b9\\u03ba\\u03ac",
99 "",
100 "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC"
101 },
102 // display script (Greek)
103 { "", "", "", "", "", "", "", "\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03bf \\u03a7\\u03b1\\u03bd" },
104 // display country (Greek)[actual values listed below]
105 { "\\u0397\\u03BD\\u03C9\\u03BC\\u03AD\\u03BD\\u03B5\\u03C2 \\u03A0\\u03BF\\u03BB\\u03B9\\u03C4\\u03B5\\u03AF\\u03B5\\u03C2",
106 "\\u0393\\u03b1\\u03bb\\u03bb\\u03af\\u03b1",
107 "\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1",
108 "\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1",
109 "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1",
110 "",
111 "",
112 "\\u039A\\u03AF\\u03BD\\u03B1"
113 },
114 // display variant (Greek)
115 { "", "", "", "", "NY", "", "" },
116 // display name (Greek)[actual values listed below]
117 { "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac (\\u0397\\u03BD\\u03C9\\u03BC\\u03AD\\u03BD\\u03B5\\u03C2 \\u03A0\\u03BF\\u03BB\\u03B9\\u03C4\\u03B5\\u03AF\\u03B5\\u03C2)",
118 "\\u0393\\u03b1\\u03bb\\u03bb\\u03b9\\u03ba\\u03ac (\\u0393\\u03b1\\u03bb\\u03bb\\u03af\\u03b1)",
119 "\\u039a\\u03b1\\u03c4\\u03b1\\u03bb\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1)",
120 "\\u0395\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac (\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1)",
121 "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac (\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1, NY)",
122 "\\u0399\\u03c4\\u03b1\\u03bb\\u03b9\\u03ba\\u03ac",
123 "",
124 "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC (\\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03bf, \\u039A\\u03AF\\u03BD\\u03B1)"
125 },
126
127 // display language (<root>)
128 { "English", "French", "Catalan", "Greek", "Norwegian", "Italian", "xx", "" },
129 // display script (<root>)
130 { "", "", "", "", "", "", "", ""},
131 // display country (<root>)
132 { "United States", "France", "Spain", "Greece", "Norway", "", "YY", "" },
133 // display variant (<root>)
134 { "", "", "", "", "Nynorsk", "", "", ""},
135 // display name (<root>)
136 //{ "English (United States)", "French (France)", "Catalan (Spain)", "Greek (Greece)", "Norwegian (Norway,Nynorsk)", "Italian", "xx (YY)" },
137 { "English (United States)", "French (France)", "Catalan (Spain)", "Greek (Greece)", "Norwegian (Norway,NY)", "Italian", "xx (YY)", "" }
138 };
139
140
141 /*
142 Usage:
143 test_assert( Test (should be TRUE) )
144
145 Example:
146 test_assert(i==3);
147
148 the macro is ugly but makes the tests pretty.
149 */
150
151 #define test_assert(test) UPRV_BLOCK_MACRO_BEGIN { \
152 if(!(test)) \
153 errln("FAIL: " #test " was not true. In " __FILE__ " on line %d", __LINE__ ); \
154 else \
155 logln("PASS: asserted " #test); \
156 } UPRV_BLOCK_MACRO_END
157
158 /*
159 Usage:
160 test_assert_print( Test (should be TRUE), printable )
161
162 Example:
163 test_assert(i==3, toString(i));
164
165 the macro is ugly but makes the tests pretty.
166 */
167
168 #define test_assert_print(test,print) UPRV_BLOCK_MACRO_BEGIN { \
169 if(!(test)) \
170 errln("FAIL: " #test " was not true. " + UnicodeString(print) ); \
171 else \
172 logln("PASS: asserted " #test "-> " + UnicodeString(print)); \
173 } UPRV_BLOCK_MACRO_END
174
175
176 #define test_dumpLocale(l) UPRV_BLOCK_MACRO_BEGIN { \
177 logln(#l " = " + UnicodeString(l.getName(), "")); \
178 } UPRV_BLOCK_MACRO_END
179
LocaleTest()180 LocaleTest::LocaleTest()
181 : dataTable(NULL)
182 {
183 setUpDataTable();
184 }
185
~LocaleTest()186 LocaleTest::~LocaleTest()
187 {
188 if (dataTable != 0) {
189 for (int32_t i = 0; i < 33; i++) {
190 delete []dataTable[i];
191 }
192 delete []dataTable;
193 dataTable = 0;
194 }
195 }
196
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)197 void LocaleTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
198 {
199 TESTCASE_AUTO_BEGIN;
200 TESTCASE_AUTO(TestBug11421); // Must run early in list to trigger failure.
201 TESTCASE_AUTO(TestBasicGetters);
202 TESTCASE_AUTO(TestSimpleResourceInfo);
203 TESTCASE_AUTO(TestDisplayNames);
204 TESTCASE_AUTO(TestSimpleObjectStuff);
205 TESTCASE_AUTO(TestPOSIXParsing);
206 TESTCASE_AUTO(TestGetAvailableLocales);
207 TESTCASE_AUTO(TestDataDirectory);
208 TESTCASE_AUTO(TestISO3Fallback);
209 TESTCASE_AUTO(TestGetLangsAndCountries);
210 TESTCASE_AUTO(TestSimpleDisplayNames);
211 TESTCASE_AUTO(TestUninstalledISO3Names);
212 TESTCASE_AUTO(TestAtypicalLocales);
213 #if !UCONFIG_NO_FORMATTING
214 TESTCASE_AUTO(TestThaiCurrencyFormat);
215 TESTCASE_AUTO(TestEuroSupport);
216 #endif
217 TESTCASE_AUTO(TestToString);
218 #if !UCONFIG_NO_FORMATTING
219 TESTCASE_AUTO(Test4139940);
220 TESTCASE_AUTO(Test4143951);
221 #endif
222 TESTCASE_AUTO(Test4147315);
223 TESTCASE_AUTO(Test4147317);
224 TESTCASE_AUTO(Test4147552);
225 TESTCASE_AUTO(TestVariantParsing);
226 TESTCASE_AUTO(Test20639_DeprecatesISO3Language);
227 #if !UCONFIG_NO_FORMATTING
228 TESTCASE_AUTO(Test4105828);
229 #endif
230 TESTCASE_AUTO(TestSetIsBogus);
231 TESTCASE_AUTO(TestParallelAPIValues);
232 TESTCASE_AUTO(TestAddLikelySubtags);
233 TESTCASE_AUTO(TestMinimizeSubtags);
234 TESTCASE_AUTO(TestAddLikelyAndMinimizeSubtags);
235 TESTCASE_AUTO(TestKeywordVariants);
236 TESTCASE_AUTO(TestCreateUnicodeKeywords);
237 TESTCASE_AUTO(TestKeywordVariantParsing);
238 TESTCASE_AUTO(TestCreateKeywordSet);
239 TESTCASE_AUTO(TestCreateKeywordSetEmpty);
240 TESTCASE_AUTO(TestCreateUnicodeKeywordSet);
241 TESTCASE_AUTO(TestCreateUnicodeKeywordSetEmpty);
242 TESTCASE_AUTO(TestGetKeywordValueStdString);
243 TESTCASE_AUTO(TestGetUnicodeKeywordValueStdString);
244 TESTCASE_AUTO(TestSetKeywordValue);
245 TESTCASE_AUTO(TestSetKeywordValueStringPiece);
246 TESTCASE_AUTO(TestSetUnicodeKeywordValueStringPiece);
247 TESTCASE_AUTO(TestGetBaseName);
248 #if !UCONFIG_NO_FILE_IO
249 TESTCASE_AUTO(TestGetLocale);
250 #endif
251 TESTCASE_AUTO(TestVariantWithOutCountry);
252 TESTCASE_AUTO(TestCanonicalization);
253 TESTCASE_AUTO(TestCurrencyByDate);
254 TESTCASE_AUTO(TestGetVariantWithKeywords);
255 TESTCASE_AUTO(TestIsRightToLeft);
256 TESTCASE_AUTO(TestBug13277);
257 TESTCASE_AUTO(TestBug13554);
258 TESTCASE_AUTO(TestBug20410);
259 TESTCASE_AUTO(TestBug20900);
260 TESTCASE_AUTO(TestConstructorAcceptsBCP47);
261 TESTCASE_AUTO(TestForLanguageTag);
262 TESTCASE_AUTO(TestToLanguageTag);
263 TESTCASE_AUTO(TestToLanguageTagOmitTrue);
264 TESTCASE_AUTO(TestMoveAssign);
265 TESTCASE_AUTO(TestMoveCtor);
266 TESTCASE_AUTO(TestBug20407iVariantPreferredValue);
267 TESTCASE_AUTO(TestBug13417VeryLongLanguageTag);
268 TESTCASE_AUTO(TestBug11053UnderlineTimeZone);
269 TESTCASE_AUTO(TestUnd);
270 TESTCASE_AUTO(TestUndScript);
271 TESTCASE_AUTO(TestUndRegion);
272 TESTCASE_AUTO(TestUndCAPI);
273 TESTCASE_AUTO(TestRangeIterator);
274 TESTCASE_AUTO(TestPointerConvertingIterator);
275 TESTCASE_AUTO(TestTagConvertingIterator);
276 TESTCASE_AUTO(TestCapturingTagConvertingIterator);
277 TESTCASE_AUTO(TestSetUnicodeKeywordValueInLongLocale);
278 TESTCASE_AUTO(TestSetUnicodeKeywordValueNullInLongLocale);
279 TESTCASE_AUTO(TestCanonicalize);
280 TESTCASE_AUTO_END;
281 }
282
TestBasicGetters()283 void LocaleTest::TestBasicGetters() {
284 UnicodeString temp;
285
286 int32_t i;
287 for (i = 0; i <= MAX_LOCALES; i++) {
288 Locale testLocale("");
289 if (rawData[SCRIPT][i] && rawData[SCRIPT][i][0] != 0) {
290 testLocale = Locale(rawData[LANG][i], rawData[SCRIPT][i], rawData[CTRY][i], rawData[VAR][i]);
291 }
292 else {
293 testLocale = Locale(rawData[LANG][i], rawData[CTRY][i], rawData[VAR][i]);
294 }
295 logln("Testing " + (UnicodeString)testLocale.getName() + "...");
296
297 if ( (temp=testLocale.getLanguage()) != (dataTable[LANG][i]))
298 errln(" Language code mismatch: " + temp + " versus "
299 + dataTable[LANG][i]);
300 if ( (temp=testLocale.getScript()) != (dataTable[SCRIPT][i]))
301 errln(" Script code mismatch: " + temp + " versus "
302 + dataTable[SCRIPT][i]);
303 if ( (temp=testLocale.getCountry()) != (dataTable[CTRY][i]))
304 errln(" Country code mismatch: " + temp + " versus "
305 + dataTable[CTRY][i]);
306 if ( (temp=testLocale.getVariant()) != (dataTable[VAR][i]))
307 errln(" Variant code mismatch: " + temp + " versus "
308 + dataTable[VAR][i]);
309 if ( (temp=testLocale.getName()) != (dataTable[NAME][i]))
310 errln(" Locale name mismatch: " + temp + " versus "
311 + dataTable[NAME][i]);
312 }
313
314 logln("Same thing without variant codes...");
315 for (i = 0; i <= MAX_LOCALES; i++) {
316 Locale testLocale("");
317 if (rawData[SCRIPT][i] && rawData[SCRIPT][i][0] != 0) {
318 testLocale = Locale(rawData[LANG][i], rawData[SCRIPT][i], rawData[CTRY][i]);
319 }
320 else {
321 testLocale = Locale(rawData[LANG][i], rawData[CTRY][i]);
322 }
323 logln("Testing " + (temp=testLocale.getName()) + "...");
324
325 if ( (temp=testLocale.getLanguage()) != (dataTable[LANG][i]))
326 errln("Language code mismatch: " + temp + " versus "
327 + dataTable[LANG][i]);
328 if ( (temp=testLocale.getScript()) != (dataTable[SCRIPT][i]))
329 errln("Script code mismatch: " + temp + " versus "
330 + dataTable[SCRIPT][i]);
331 if ( (temp=testLocale.getCountry()) != (dataTable[CTRY][i]))
332 errln("Country code mismatch: " + temp + " versus "
333 + dataTable[CTRY][i]);
334 if (testLocale.getVariant()[0] != 0)
335 errln("Variant code mismatch: something versus \"\"");
336 }
337
338 logln("Testing long language names and getters");
339 Locale test8 = Locale::createFromName("x-klingon-latn-zx.utf32be@special");
340
341 temp = test8.getLanguage();
342 if (temp != UnicodeString("x-klingon") )
343 errln("Language code mismatch: " + temp + " versus \"x-klingon\"");
344
345 temp = test8.getScript();
346 if (temp != UnicodeString("Latn") )
347 errln("Script code mismatch: " + temp + " versus \"Latn\"");
348
349 temp = test8.getCountry();
350 if (temp != UnicodeString("ZX") )
351 errln("Country code mismatch: " + temp + " versus \"ZX\"");
352
353 temp = test8.getVariant();
354 //if (temp != UnicodeString("SPECIAL") )
355 // errln("Variant code mismatch: " + temp + " versus \"SPECIAL\"");
356 // As of 3.0, the "@special" will *not* be parsed by uloc_getName()
357 if (temp != UnicodeString("") )
358 errln("Variant code mismatch: " + temp + " versus \"\"");
359
360 if (Locale::getDefault() != Locale::createFromName(NULL))
361 errln("Locale::getDefault() == Locale::createFromName(NULL)");
362
363 /*----------*/
364 // NOTE: There used to be a special test for locale names that had language or
365 // country codes that were longer than two letters. The new version of Locale
366 // doesn't support anything that isn't an officially recognized language or
367 // country code, so we no longer support this feature.
368
369 Locale bogusLang("THISISABOGUSLANGUAGE"); // Jitterbug 2864: language code too long
370 if(!bogusLang.isBogus()) {
371 errln("Locale(\"THISISABOGUSLANGUAGE\").isBogus()==FALSE");
372 }
373
374 bogusLang=Locale("eo");
375 if( bogusLang.isBogus() ||
376 strcmp(bogusLang.getLanguage(), "eo")!=0 ||
377 *bogusLang.getCountry()!=0 ||
378 *bogusLang.getVariant()!=0 ||
379 strcmp(bogusLang.getName(), "eo")!=0
380 ) {
381 errln("assignment to bogus Locale does not unbogus it or sets bad data");
382 }
383
384 Locale a("eo_DE@currency=DEM");
385 Locale *pb=a.clone();
386 if(pb==&a || *pb!=a) {
387 errln("Locale.clone() failed");
388 }
389 delete pb;
390 }
391
TestParallelAPIValues()392 void LocaleTest::TestParallelAPIValues() {
393 logln("Test synchronization between C and C++ API");
394 if (strcmp(Locale::getChinese().getName(), ULOC_CHINESE) != 0) {
395 errln("Differences for ULOC_CHINESE Locale");
396 }
397 if (strcmp(Locale::getEnglish().getName(), ULOC_ENGLISH) != 0) {
398 errln("Differences for ULOC_ENGLISH Locale");
399 }
400 if (strcmp(Locale::getFrench().getName(), ULOC_FRENCH) != 0) {
401 errln("Differences for ULOC_FRENCH Locale");
402 }
403 if (strcmp(Locale::getGerman().getName(), ULOC_GERMAN) != 0) {
404 errln("Differences for ULOC_GERMAN Locale");
405 }
406 if (strcmp(Locale::getItalian().getName(), ULOC_ITALIAN) != 0) {
407 errln("Differences for ULOC_ITALIAN Locale");
408 }
409 if (strcmp(Locale::getJapanese().getName(), ULOC_JAPANESE) != 0) {
410 errln("Differences for ULOC_JAPANESE Locale");
411 }
412 if (strcmp(Locale::getKorean().getName(), ULOC_KOREAN) != 0) {
413 errln("Differences for ULOC_KOREAN Locale");
414 }
415 if (strcmp(Locale::getSimplifiedChinese().getName(), ULOC_SIMPLIFIED_CHINESE) != 0) {
416 errln("Differences for ULOC_SIMPLIFIED_CHINESE Locale");
417 }
418 if (strcmp(Locale::getTraditionalChinese().getName(), ULOC_TRADITIONAL_CHINESE) != 0) {
419 errln("Differences for ULOC_TRADITIONAL_CHINESE Locale");
420 }
421
422
423 if (strcmp(Locale::getCanada().getName(), ULOC_CANADA) != 0) {
424 errln("Differences for ULOC_CANADA Locale");
425 }
426 if (strcmp(Locale::getCanadaFrench().getName(), ULOC_CANADA_FRENCH) != 0) {
427 errln("Differences for ULOC_CANADA_FRENCH Locale");
428 }
429 if (strcmp(Locale::getChina().getName(), ULOC_CHINA) != 0) {
430 errln("Differences for ULOC_CHINA Locale");
431 }
432 if (strcmp(Locale::getPRC().getName(), ULOC_PRC) != 0) {
433 errln("Differences for ULOC_PRC Locale");
434 }
435 if (strcmp(Locale::getFrance().getName(), ULOC_FRANCE) != 0) {
436 errln("Differences for ULOC_FRANCE Locale");
437 }
438 if (strcmp(Locale::getGermany().getName(), ULOC_GERMANY) != 0) {
439 errln("Differences for ULOC_GERMANY Locale");
440 }
441 if (strcmp(Locale::getItaly().getName(), ULOC_ITALY) != 0) {
442 errln("Differences for ULOC_ITALY Locale");
443 }
444 if (strcmp(Locale::getJapan().getName(), ULOC_JAPAN) != 0) {
445 errln("Differences for ULOC_JAPAN Locale");
446 }
447 if (strcmp(Locale::getKorea().getName(), ULOC_KOREA) != 0) {
448 errln("Differences for ULOC_KOREA Locale");
449 }
450 if (strcmp(Locale::getTaiwan().getName(), ULOC_TAIWAN) != 0) {
451 errln("Differences for ULOC_TAIWAN Locale");
452 }
453 if (strcmp(Locale::getUK().getName(), ULOC_UK) != 0) {
454 errln("Differences for ULOC_UK Locale");
455 }
456 if (strcmp(Locale::getUS().getName(), ULOC_US) != 0) {
457 errln("Differences for ULOC_US Locale");
458 }
459 }
460
461
TestSimpleResourceInfo()462 void LocaleTest::TestSimpleResourceInfo() {
463 UnicodeString temp;
464 char temp2[20];
465 UErrorCode err = U_ZERO_ERROR;
466 int32_t i = 0;
467
468 for (i = 0; i <= MAX_LOCALES; i++) {
469 Locale testLocale(rawData[LANG][i], rawData[CTRY][i], rawData[VAR][i]);
470 logln("Testing " + (temp=testLocale.getName()) + "...");
471
472 if ( (temp=testLocale.getISO3Language()) != (dataTable[LANG3][i]))
473 errln(" ISO-3 language code mismatch: " + temp
474 + " versus " + dataTable[LANG3][i]);
475 if ( (temp=testLocale.getISO3Country()) != (dataTable[CTRY3][i]))
476 errln(" ISO-3 country code mismatch: " + temp
477 + " versus " + dataTable[CTRY3][i]);
478
479 sprintf(temp2, "%x", (int)testLocale.getLCID());
480 if (UnicodeString(temp2) != dataTable[LCID][i])
481 errln((UnicodeString)" LCID mismatch: " + temp2 + " versus "
482 + dataTable[LCID][i]);
483
484 if(U_FAILURE(err))
485 {
486 errln((UnicodeString)"Some error on number " + i + u_errorName(err));
487 }
488 err = U_ZERO_ERROR;
489 }
490
491 Locale locale("en");
492 if(strcmp(locale.getName(), "en") != 0||
493 strcmp(locale.getLanguage(), "en") != 0) {
494 errln("construction of Locale(en) failed\n");
495 }
496 /*-----*/
497
498 }
499
500 /*
501 * Jitterbug 2439 -- markus 20030425
502 *
503 * The lookup of display names must not fall back through the default
504 * locale because that yields useless results.
505 */
506 void
TestDisplayNames()507 LocaleTest::TestDisplayNames()
508 {
509 Locale english("en", "US");
510 Locale french("fr", "FR");
511 Locale croatian("ca", "ES");
512 Locale greek("el", "GR");
513
514 logln(" In locale = en_US...");
515 doTestDisplayNames(english, DLANG_EN);
516 logln(" In locale = fr_FR...");
517 doTestDisplayNames(french, DLANG_FR);
518 logln(" In locale = ca_ES...");
519 doTestDisplayNames(croatian, DLANG_CA);
520 logln(" In locale = el_GR...");
521 doTestDisplayNames(greek, DLANG_EL);
522
523 UnicodeString s;
524 UErrorCode status = U_ZERO_ERROR;
525
526 #if !UCONFIG_NO_FORMATTING
527 DecimalFormatSymbols symb(status);
528 /* Check to see if ICU supports this locale */
529 if (symb.getLocale(ULOC_VALID_LOCALE, status) != Locale("root")) {
530 /* test that the default locale has a display name for its own language */
531 /* Currently, there is no language information in the "tl" data file so this test will fail if default locale is "tl" */
532 if (uprv_strcmp(Locale().getLanguage(), "tl") != 0) {
533 Locale().getDisplayLanguage(Locale(), s);
534 if(s.length()<=3 && s.charAt(0)<=0x7f) {
535 /* check <=3 to reject getting the language code as a display name */
536 dataerrln("unable to get a display string for the language of the default locale: " + s);
537 }
538
539 /*
540 * API coverage improvements: call
541 * Locale::getDisplayLanguage(UnicodeString &) and
542 * Locale::getDisplayCountry(UnicodeString &)
543 */
544 s.remove();
545 Locale().getDisplayLanguage(s);
546 if(s.length()<=3 && s.charAt(0)<=0x7f) {
547 dataerrln("unable to get a display string for the language of the default locale [2]: " + s);
548 }
549 }
550 }
551 else {
552 logln("Default locale %s is unsupported by ICU\n", Locale().getName());
553 }
554 s.remove();
555 #endif
556
557 french.getDisplayCountry(s);
558 if(s.isEmpty()) {
559 errln("unable to get any default-locale display string for the country of fr_FR\n");
560 }
561 s.remove();
562 Locale("zh", "Hant").getDisplayScript(s);
563 if(s.isEmpty()) {
564 errln("unable to get any default-locale display string for the country of zh_Hant\n");
565 }
566 }
567
TestSimpleObjectStuff()568 void LocaleTest::TestSimpleObjectStuff() {
569 Locale test1("aa", "AA");
570 Locale test2("aa", "AA");
571 Locale test3(test1);
572 Locale test4("zz", "ZZ");
573 Locale test5("aa", "AA", "");
574 Locale test6("aa", "AA", "ANTARES");
575 Locale test7("aa", "AA", "JUPITER");
576 Locale test8 = Locale::createFromName("aa-aa-jupiTER"); // was "aa-aa.utf8@jupiter" but in 3.0 getName won't normalize that
577
578 // now list them all for debugging usage.
579 test_dumpLocale(test1);
580 test_dumpLocale(test2);
581 test_dumpLocale(test3);
582 test_dumpLocale(test4);
583 test_dumpLocale(test5);
584 test_dumpLocale(test6);
585 test_dumpLocale(test7);
586 test_dumpLocale(test8);
587
588 // Make sure things compare to themselves!
589 test_assert(test1 == test1);
590 test_assert(test2 == test2);
591 test_assert(test3 == test3);
592 test_assert(test4 == test4);
593 test_assert(test5 == test5);
594 test_assert(test6 == test6);
595 test_assert(test7 == test7);
596 test_assert(test8 == test8);
597
598 // make sure things are not equal to themselves.
599 test_assert(!(test1 != test1));
600 test_assert(!(test2 != test2));
601 test_assert(!(test3 != test3));
602 test_assert(!(test4 != test4));
603 test_assert(!(test5 != test5));
604 test_assert(!(test6 != test6));
605 test_assert(!(test7 != test7));
606 test_assert(!(test8 != test8));
607
608 // make sure things that are equal to each other don't show up as unequal.
609 test_assert(!(test1 != test2));
610 test_assert(!(test2 != test1));
611 test_assert(!(test1 != test3));
612 test_assert(!(test2 != test3));
613 test_assert(test5 == test1);
614 test_assert(test6 != test2);
615 test_assert(test6 != test5);
616
617 test_assert(test6 != test7);
618
619 // test for things that shouldn't compare equal.
620 test_assert(!(test1 == test4));
621 test_assert(!(test2 == test4));
622 test_assert(!(test3 == test4));
623
624 test_assert(test7 == test8);
625
626 // test for hash codes to be the same.
627 int32_t hash1 = test1.hashCode();
628 int32_t hash2 = test2.hashCode();
629 int32_t hash3 = test3.hashCode();
630
631 test_assert(hash1 == hash2);
632 test_assert(hash1 == hash3);
633 test_assert(hash2 == hash3);
634
635 // test that the assignment operator works.
636 test4 = test1;
637 logln("test4=test1;");
638 test_dumpLocale(test4);
639 test_assert(test4 == test4);
640
641 test_assert(!(test1 != test4));
642 test_assert(!(test2 != test4));
643 test_assert(!(test3 != test4));
644 test_assert(test1 == test4);
645 test_assert(test4 == test1);
646
647 // test assignments with a variant
648 logln("test7 = test6");
649 test7 = test6;
650 test_dumpLocale(test7);
651 test_assert(test7 == test7);
652 test_assert(test7 == test6);
653 test_assert(test7 != test5);
654
655 logln("test6 = test1");
656 test6=test1;
657 test_dumpLocale(test6);
658 test_assert(test6 != test7);
659 test_assert(test6 == test1);
660 test_assert(test6 == test6);
661 }
662
663 // A class which exposes constructors that are implemented in terms of the POSIX parsing code.
664 class POSIXLocale : public Locale
665 {
666 public:
POSIXLocale(const UnicodeString & l)667 POSIXLocale(const UnicodeString& l)
668 :Locale()
669 {
670 char *ch;
671 ch = new char[l.length() + 1];
672 ch[l.extract(0, 0x7fffffff, ch, "")] = 0;
673 setFromPOSIXID(ch);
674 delete [] ch;
675 }
POSIXLocale(const char * l)676 POSIXLocale(const char *l)
677 :Locale()
678 {
679 setFromPOSIXID(l);
680 }
681 };
682
TestPOSIXParsing()683 void LocaleTest::TestPOSIXParsing()
684 {
685 POSIXLocale test1("ab_AB");
686 POSIXLocale test2(UnicodeString("ab_AB"));
687 Locale test3("ab","AB");
688
689 POSIXLocale test4("ab_AB_Antares");
690 POSIXLocale test5(UnicodeString("ab_AB_Antares"));
691 Locale test6("ab", "AB", "Antares");
692
693 test_dumpLocale(test1);
694 test_dumpLocale(test2);
695 test_dumpLocale(test3);
696 test_dumpLocale(test4);
697 test_dumpLocale(test5);
698 test_dumpLocale(test6);
699
700 test_assert(test1 == test1);
701
702 test_assert(test1 == test2);
703 test_assert(test2 == test3);
704 test_assert(test3 == test1);
705
706 test_assert(test4 == test5);
707 test_assert(test5 == test6);
708 test_assert(test6 == test4);
709
710 test_assert(test1 != test4);
711 test_assert(test5 != test3);
712 test_assert(test5 != test2);
713
714 int32_t hash1 = test1.hashCode();
715 int32_t hash2 = test2.hashCode();
716 int32_t hash3 = test3.hashCode();
717
718 test_assert(hash1 == hash2);
719 test_assert(hash2 == hash3);
720 test_assert(hash3 == hash1);
721 }
722
TestGetAvailableLocales()723 void LocaleTest::TestGetAvailableLocales()
724 {
725 int32_t locCount = 0;
726 const Locale* locList = Locale::getAvailableLocales(locCount);
727
728 if (locCount == 0)
729 dataerrln("getAvailableLocales() returned an empty list!");
730 else {
731 logln(UnicodeString("Number of locales returned = ") + locCount);
732 UnicodeString temp;
733 for(int32_t i = 0; i < locCount; ++i)
734 logln(locList[i].getName());
735 }
736 // I have no idea how to test this function...
737 }
738
739 // This test isn't applicable anymore - getISO3Language is
740 // independent of the data directory
TestDataDirectory()741 void LocaleTest::TestDataDirectory()
742 {
743 /*
744 char oldDirectory[80];
745 const char* temp;
746 UErrorCode err = U_ZERO_ERROR;
747 UnicodeString testValue;
748
749 temp = Locale::getDataDirectory();
750 strcpy(oldDirectory, temp);
751 logln(UnicodeString("oldDirectory = ") + oldDirectory);
752
753 Locale test(Locale::US);
754 test.getISO3Language(testValue);
755 logln("first fetch of language retrieved " + testValue);
756 if (testValue != "eng")
757 errln("Initial check of ISO3 language failed: expected \"eng\", got \"" + testValue + "\"");
758
759 {
760 char *path;
761 path=IntlTest::getTestDirectory();
762 Locale::setDataDirectory( path );
763 }
764
765 test.getISO3Language(testValue);
766 logln("second fetch of language retrieved " + testValue);
767 if (testValue != "xxx")
768 errln("setDataDirectory() failed: expected \"xxx\", got \"" + testValue + "\"");
769
770 Locale::setDataDirectory(oldDirectory);
771 test.getISO3Language(testValue);
772 logln("third fetch of language retrieved " + testValue);
773 if (testValue != "eng")
774 errln("get/setDataDirectory() failed: expected \"eng\", got \"" + testValue + "\"");
775 */
776 }
777
778 //===========================================================
779
doTestDisplayNames(Locale & displayLocale,int32_t compareIndex)780 void LocaleTest::doTestDisplayNames(Locale& displayLocale, int32_t compareIndex) {
781 UnicodeString temp;
782
783 for (int32_t i = 0; i <= MAX_LOCALES; i++) {
784 Locale testLocale("");
785 if (rawData[SCRIPT][i] && rawData[SCRIPT][i][0] != 0) {
786 testLocale = Locale(rawData[LANG][i], rawData[SCRIPT][i], rawData[CTRY][i], rawData[VAR][i]);
787 }
788 else {
789 testLocale = Locale(rawData[LANG][i], rawData[CTRY][i], rawData[VAR][i]);
790 }
791 logln(" Testing " + (temp=testLocale.getName()) + "...");
792
793 UnicodeString testLang;
794 UnicodeString testScript;
795 UnicodeString testCtry;
796 UnicodeString testVar;
797 UnicodeString testName;
798
799 testLocale.getDisplayLanguage(displayLocale, testLang);
800 testLocale.getDisplayScript(displayLocale, testScript);
801 testLocale.getDisplayCountry(displayLocale, testCtry);
802 testLocale.getDisplayVariant(displayLocale, testVar);
803 testLocale.getDisplayName(displayLocale, testName);
804
805 UnicodeString expectedLang;
806 UnicodeString expectedScript;
807 UnicodeString expectedCtry;
808 UnicodeString expectedVar;
809 UnicodeString expectedName;
810
811 expectedLang = dataTable[compareIndex][i];
812 if (expectedLang.length() == 0)
813 expectedLang = dataTable[DLANG_EN][i];
814
815 expectedScript = dataTable[compareIndex + 1][i];
816 if (expectedScript.length() == 0)
817 expectedScript = dataTable[DSCRIPT_EN][i];
818
819 expectedCtry = dataTable[compareIndex + 2][i];
820 if (expectedCtry.length() == 0)
821 expectedCtry = dataTable[DCTRY_EN][i];
822
823 expectedVar = dataTable[compareIndex + 3][i];
824 if (expectedVar.length() == 0)
825 expectedVar = dataTable[DVAR_EN][i];
826
827 expectedName = dataTable[compareIndex + 4][i];
828 if (expectedName.length() == 0)
829 expectedName = dataTable[DNAME_EN][i];
830
831 if (testLang != expectedLang)
832 dataerrln("Display language (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testLang + " expected " + expectedLang);
833 if (testScript != expectedScript)
834 dataerrln("Display script (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testScript + " expected " + expectedScript);
835 if (testCtry != expectedCtry)
836 dataerrln("Display country (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testCtry + " expected " + expectedCtry);
837 if (testVar != expectedVar)
838 dataerrln("Display variant (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testVar + " expected " + expectedVar);
839 if (testName != expectedName)
840 dataerrln("Display name (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testName + " expected " + expectedName);
841 }
842 }
843
844 //---------------------------------------------------
845 // table of valid data
846 //---------------------------------------------------
847
848
849
setUpDataTable()850 void LocaleTest::setUpDataTable()
851 {
852 if (dataTable == 0) {
853 dataTable = new UnicodeString*[33];
854
855 for (int32_t i = 0; i < 33; i++) {
856 dataTable[i] = new UnicodeString[8];
857 for (int32_t j = 0; j < 8; j++) {
858 dataTable[i][j] = CharsToUnicodeString(rawData[i][j]);
859 }
860 }
861 }
862 }
863
864 // ====================
865
866
867 /**
868 * @bug 4011756 4011380
869 */
870 void
TestISO3Fallback()871 LocaleTest::TestISO3Fallback()
872 {
873 Locale test("xx", "YY");
874
875 const char * result;
876
877 result = test.getISO3Language();
878
879 // Conform to C API usage
880
881 if (!result || (result[0] != 0))
882 errln("getISO3Language() on xx_YY returned " + UnicodeString(result) + " instead of \"\"");
883
884 result = test.getISO3Country();
885
886 if (!result || (result[0] != 0))
887 errln("getISO3Country() on xx_YY returned " + UnicodeString(result) + " instead of \"\"");
888 }
889
890 /**
891 * @bug 4106155 4118587
892 */
893 void
TestGetLangsAndCountries()894 LocaleTest::TestGetLangsAndCountries()
895 {
896 // It didn't seem right to just do an exhaustive test of everything here, so I check
897 // for the following things:
898 // 1) Does each list have the right total number of entries?
899 // 2) Does each list contain certain language and country codes we think are important
900 // (the G7 countries, plus a couple others)?
901 // 3) Does each list have every entry formatted correctly? (i.e., two characters,
902 // all lower case for the language codes, all upper case for the country codes)
903 // 4) Is each list in sorted order?
904 int32_t testCount = 0;
905 const char * const * test = Locale::getISOLanguages();
906 const char spotCheck1[ ][4] = { "en", "es", "fr", "de", "it",
907 "ja", "ko", "zh", "th", "he",
908 "id", "iu", "ug", "yi", "za" };
909
910 int32_t i;
911
912 for(testCount = 0;test[testCount];testCount++)
913 ;
914
915 /* TODO: Change this test to be more like the cloctst version? */
916 if (testCount != 597)
917 errln("Expected getISOLanguages() to return 597 languages; it returned %d", testCount);
918 else {
919 for (i = 0; i < 15; i++) {
920 int32_t j;
921 for (j = 0; j < testCount; j++)
922 if (uprv_strcmp(test[j],spotCheck1[i])== 0)
923 break;
924 if (j == testCount || (uprv_strcmp(test[j],spotCheck1[i])!=0))
925 errln("Couldn't find " + (UnicodeString)spotCheck1[i] + " in language list.");
926 }
927 }
928 for (i = 0; i < testCount; i++) {
929 UnicodeString testee(test[i],"");
930 UnicodeString lc(test[i],"");
931 if (testee != lc.toLower())
932 errln(lc + " is not all lower case.");
933 if ( (testee.length() != 2) && (testee.length() != 3))
934 errln(testee + " is not two or three characters long.");
935 if (i > 0 && testee.compare(test[i - 1]) <= 0)
936 errln(testee + " appears in an out-of-order position in the list.");
937 }
938
939 test = Locale::getISOCountries();
940 UnicodeString spotCheck2 [] = { "US", "CA", "GB", "FR", "DE",
941 "IT", "JP", "KR", "CN", "TW",
942 "TH" };
943 int32_t spot2Len = 11;
944 for(testCount=0;test[testCount];testCount++)
945 ;
946
947 if (testCount != 249){
948 errln("Expected getISOCountries to return 249 countries; it returned %d", testCount);
949 }else {
950 for (i = 0; i < spot2Len; i++) {
951 int32_t j;
952 for (j = 0; j < testCount; j++)
953 {
954 UnicodeString testee(test[j],"");
955
956 if (testee == spotCheck2[i])
957 break;
958 }
959 UnicodeString testee(test[j],"");
960 if (j == testCount || testee != spotCheck2[i])
961 errln("Couldn't find " + spotCheck2[i] + " in country list.");
962 }
963 }
964 for (i = 0; i < testCount; i++) {
965 UnicodeString testee(test[i],"");
966 UnicodeString uc(test[i],"");
967 if (testee != uc.toUpper())
968 errln(testee + " is not all upper case.");
969 if (testee.length() != 2)
970 errln(testee + " is not two characters long.");
971 if (i > 0 && testee.compare(test[i - 1]) <= 0)
972 errln(testee + " appears in an out-of-order position in the list.");
973 }
974
975 // This getAvailableLocales and getISO3Language
976 {
977 int32_t numOfLocales;
978 Locale enLoc ("en");
979 const Locale *pLocales = Locale::getAvailableLocales(numOfLocales);
980
981 for (int i = 0; i < numOfLocales; i++) {
982 const Locale &loc(pLocales[i]);
983 UnicodeString name;
984 char szName[200];
985
986 loc.getDisplayName (enLoc, name);
987 name.extract (0, 200, szName, sizeof(szName));
988
989 if (strlen(loc.getISO3Language()) == 0) {
990 errln("getISO3Language() returned an empty string for: " + name);
991 }
992 }
993 }
994 }
995
996 /**
997 * @bug 4118587
998 */
999 void
TestSimpleDisplayNames()1000 LocaleTest::TestSimpleDisplayNames()
1001 {
1002 // This test is different from TestDisplayNames because TestDisplayNames checks
1003 // fallback behavior, combination of language and country names to form locale
1004 // names, and other stuff like that. This test just checks specific language
1005 // and country codes to make sure we have the correct names for them.
1006 char languageCodes[] [4] = { "he", "id", "iu", "ug", "yi", "za" };
1007 UnicodeString languageNames [] = { "Hebrew", "Indonesian", "Inuktitut", "Uyghur", "Yiddish",
1008 "Zhuang" };
1009
1010 for (int32_t i = 0; i < 6; i++) {
1011 UnicodeString test;
1012 Locale l(languageCodes[i], "", "");
1013 l.getDisplayLanguage(Locale::getUS(), test);
1014 if (test != languageNames[i])
1015 dataerrln("Got wrong display name for " + UnicodeString(languageCodes[i]) + ": Expected \"" +
1016 languageNames[i] + "\", got \"" + test + "\".");
1017 }
1018 }
1019
1020 /**
1021 * @bug 4118595
1022 */
1023 void
TestUninstalledISO3Names()1024 LocaleTest::TestUninstalledISO3Names()
1025 {
1026 // This test checks to make sure getISO3Language and getISO3Country work right
1027 // even for locales that are not installed.
1028 const char iso2Languages [][4] = { "am", "ba", "fy", "mr", "rn",
1029 "ss", "tw", "zu" };
1030 const char iso3Languages [][5] = { "amh", "bak", "fry", "mar", "run",
1031 "ssw", "twi", "zul" };
1032
1033 int32_t i;
1034
1035 for (i = 0; i < 8; i++) {
1036 UErrorCode err = U_ZERO_ERROR;
1037
1038 UnicodeString test;
1039 Locale l(iso2Languages[i], "", "");
1040 test = l.getISO3Language();
1041 if((test != iso3Languages[i]) || U_FAILURE(err))
1042 errln("Got wrong ISO3 code for " + UnicodeString(iso2Languages[i]) + ": Expected \"" +
1043 iso3Languages[i] + "\", got \"" + test + "\"." + UnicodeString(u_errorName(err)));
1044 }
1045
1046 char iso2Countries [][4] = { "AF", "BW", "KZ", "MO", "MN",
1047 "SB", "TC", "ZW" };
1048 char iso3Countries [][4] = { "AFG", "BWA", "KAZ", "MAC", "MNG",
1049 "SLB", "TCA", "ZWE" };
1050
1051 for (i = 0; i < 8; i++) {
1052 UErrorCode err = U_ZERO_ERROR;
1053 Locale l("", iso2Countries[i], "");
1054 UnicodeString test(l.getISO3Country(), "");
1055 if (test != iso3Countries[i])
1056 errln("Got wrong ISO3 code for " + UnicodeString(iso2Countries[i]) + ": Expected \"" +
1057 UnicodeString(iso3Countries[i]) + "\", got \"" + test + "\"." + u_errorName(err));
1058 }
1059 }
1060
1061 /**
1062 * @bug 4092475
1063 * I could not reproduce this bug. I'm pretty convinced it was fixed with the
1064 * big locale-data reorg of 10/28/97. The lookup logic for language and country
1065 * display names was also changed at that time in that check-in. --rtg 3/20/98
1066 */
1067 void
TestAtypicalLocales()1068 LocaleTest::TestAtypicalLocales()
1069 {
1070 Locale localesToTest [] = { Locale("de", "CA"),
1071 Locale("ja", "ZA"),
1072 Locale("ru", "MX"),
1073 Locale("en", "FR"),
1074 Locale("es", "DE"),
1075 Locale("", "HR"),
1076 Locale("", "SE"),
1077 Locale("", "DO"),
1078 Locale("", "BE") };
1079
1080 UnicodeString englishDisplayNames [] = { "German (Canada)",
1081 "Japanese (South Africa)",
1082 "Russian (Mexico)",
1083 "English (France)",
1084 "Spanish (Germany)",
1085 "Unknown language (Croatia)",
1086 "Unknown language (Sweden)",
1087 "Unknown language (Dominican Republic)",
1088 "Unknown language (Belgium)" };
1089 UnicodeString frenchDisplayNames []= { "allemand (Canada)",
1090 "japonais (Afrique du Sud)",
1091 "russe (Mexique)",
1092 "anglais (France)",
1093 "espagnol (Allemagne)",
1094 u"langue indéterminée (Croatie)",
1095 u"langue indéterminée (Suède)",
1096 u"langue indéterminée (République dominicaine)",
1097 u"langue indéterminée (Belgique)" };
1098 UnicodeString spanishDisplayNames [] = {
1099 u"alemán (Canadá)",
1100 u"japonés (Sudáfrica)",
1101 u"ruso (México)",
1102 u"inglés (Francia)",
1103 u"español (Alemania)",
1104 "lengua desconocida (Croacia)",
1105 "lengua desconocida (Suecia)",
1106 u"lengua desconocida (República Dominicana)",
1107 u"lengua desconocida (Bélgica)" };
1108 // De-Anglicizing root required the change from
1109 // English display names to ISO Codes - ram 2003/09/26
1110 UnicodeString invDisplayNames [] = { "German (Canada)",
1111 "Japanese (South Africa)",
1112 "Russian (Mexico)",
1113 "English (France)",
1114 "Spanish (Germany)",
1115 "Unknown language (Croatia)",
1116 "Unknown language (Sweden)",
1117 "Unknown language (Dominican Republic)",
1118 "Unknown language (Belgium)" };
1119
1120 int32_t i;
1121 UErrorCode status = U_ZERO_ERROR;
1122 Locale saveLocale;
1123 Locale::setDefault(Locale::getUS(), status);
1124 for (i = 0; i < 9; ++i) {
1125 UnicodeString name;
1126 localesToTest[i].getDisplayName(Locale::getUS(), name);
1127 logln(name);
1128 if (name != englishDisplayNames[i])
1129 {
1130 dataerrln("Lookup in English failed: expected \"" + englishDisplayNames[i]
1131 + "\", got \"" + name + "\"");
1132 logln("Locale name was-> " + (name=localesToTest[i].getName()));
1133 }
1134 }
1135
1136 for (i = 0; i < 9; i++) {
1137 UnicodeString name;
1138 localesToTest[i].getDisplayName(Locale("es", "ES"), name);
1139 logln(name);
1140 if (name != spanishDisplayNames[i])
1141 dataerrln("Lookup in Spanish failed: expected \"" + spanishDisplayNames[i]
1142 + "\", got \"" + name + "\"");
1143 }
1144
1145 for (i = 0; i < 9; i++) {
1146 UnicodeString name;
1147 localesToTest[i].getDisplayName(Locale::getFrance(), name);
1148 logln(name);
1149 if (name != frenchDisplayNames[i])
1150 dataerrln("Lookup in French failed: expected \"" + frenchDisplayNames[i]
1151 + "\", got \"" + name + "\"");
1152 }
1153
1154 for (i = 0; i < 9; i++) {
1155 UnicodeString name;
1156 localesToTest[i].getDisplayName(Locale("inv", "IN"), name);
1157 logln(name + " Locale fallback to be, and data fallback to root");
1158 if (name != invDisplayNames[i])
1159 dataerrln("Lookup in INV failed: expected \"" + prettify(invDisplayNames[i])
1160 + "\", got \"" + prettify(name) + "\"");
1161 localesToTest[i].getDisplayName(Locale("inv", "BD"), name);
1162 logln(name + " Data fallback to root");
1163 if (name != invDisplayNames[i])
1164 dataerrln("Lookup in INV failed: expected \"" + prettify(invDisplayNames[i])
1165 + "\", got \"" + prettify(name )+ "\"");
1166 }
1167 Locale::setDefault(saveLocale, status);
1168 }
1169
1170 #if !UCONFIG_NO_FORMATTING
1171
1172 /**
1173 * @bug 4135752
1174 * This would be better tested by the LocaleDataTest. Will move it when I
1175 * get the LocaleDataTest working again.
1176 */
1177 void
TestThaiCurrencyFormat()1178 LocaleTest::TestThaiCurrencyFormat()
1179 {
1180 UErrorCode status = U_ZERO_ERROR;
1181 DecimalFormat *thaiCurrency = (DecimalFormat*)NumberFormat::createCurrencyInstance(
1182 Locale("th", "TH"), status);
1183 UnicodeString posPrefix(u"\u0E3F");
1184 UnicodeString temp;
1185
1186 if(U_FAILURE(status) || !thaiCurrency)
1187 {
1188 dataerrln("Couldn't get th_TH currency -> " + UnicodeString(u_errorName(status)));
1189 return;
1190 }
1191 if (thaiCurrency->getPositivePrefix(temp) != posPrefix)
1192 errln("Thai currency prefix wrong: expected Baht sign, got \"" +
1193 thaiCurrency->getPositivePrefix(temp) + "\"");
1194 if (thaiCurrency->getPositiveSuffix(temp) != "")
1195 errln("Thai currency suffix wrong: expected \"\", got \"" +
1196 thaiCurrency->getPositiveSuffix(temp) + "\"");
1197
1198 delete thaiCurrency;
1199 }
1200
1201 /**
1202 * @bug 4122371
1203 * Confirm that Euro support works. This test is pretty rudimentary; all it does
1204 * is check that any locales with the EURO variant format a number using the
1205 * Euro currency symbol.
1206 *
1207 * ASSUME: All locales encode the Euro character "\u20AC".
1208 * If this is changed to use the single-character Euro symbol, this
1209 * test must be updated.
1210 *
1211 */
1212 void
TestEuroSupport()1213 LocaleTest::TestEuroSupport()
1214 {
1215 UChar euro = 0x20ac;
1216 const UnicodeString EURO_CURRENCY(&euro, 1, 1); // Look for this UnicodeString in formatted Euro currency
1217 const char* localeArr[] = {
1218 "ca_ES",
1219 "de_AT",
1220 "de_DE",
1221 "de_LU",
1222 "el_GR",
1223 "en_BE",
1224 "en_IE",
1225 "en_GB@currency=EUR",
1226 "en_US@currency=EUR",
1227 "es_ES",
1228 "eu_ES",
1229 "fi_FI",
1230 "fr_BE",
1231 "fr_FR",
1232 "fr_LU",
1233 "ga_IE",
1234 "gl_ES",
1235 "it_IT",
1236 "nl_BE",
1237 "nl_NL",
1238 "pt_PT",
1239 NULL
1240 };
1241 const char** locales = localeArr;
1242
1243 UErrorCode status = U_ZERO_ERROR;
1244
1245 UnicodeString temp;
1246
1247 for (;*locales!=NULL;locales++) {
1248 Locale loc (*locales);
1249 UnicodeString temp;
1250 NumberFormat *nf = NumberFormat::createCurrencyInstance(loc, status);
1251 UnicodeString pos;
1252
1253 if (U_FAILURE(status)) {
1254 dataerrln("Error calling NumberFormat::createCurrencyInstance(%s)", *locales);
1255 continue;
1256 }
1257
1258 nf->format(271828.182845, pos);
1259 UnicodeString neg;
1260 nf->format(-271828.182845, neg);
1261 if (pos.indexOf(EURO_CURRENCY) >= 0 &&
1262 neg.indexOf(EURO_CURRENCY) >= 0) {
1263 logln("Ok: " + (temp=loc.getName()) +
1264 ": " + pos + " / " + neg);
1265 }
1266 else {
1267 errln("Fail: " + (temp=loc.getName()) +
1268 " formats without " + EURO_CURRENCY +
1269 ": " + pos + " / " + neg +
1270 "\n*** THIS FAILURE MAY ONLY MEAN THAT LOCALE DATA HAS CHANGED ***");
1271 }
1272
1273 delete nf;
1274 }
1275
1276 UnicodeString dollarStr("USD", ""), euroStr("EUR", ""), genericStr((UChar)0x00a4), resultStr;
1277 UChar tmp[4];
1278 status = U_ZERO_ERROR;
1279
1280 ucurr_forLocale("en_US", tmp, 4, &status);
1281 resultStr.setTo(tmp);
1282 if (dollarStr != resultStr) {
1283 errcheckln(status, "Fail: en_US didn't return USD - %s", u_errorName(status));
1284 }
1285 ucurr_forLocale("en_US@currency=EUR", tmp, 4, &status);
1286 resultStr.setTo(tmp);
1287 if (euroStr != resultStr) {
1288 errcheckln(status, "Fail: en_US@currency=EUR didn't return EUR - %s", u_errorName(status));
1289 }
1290 ucurr_forLocale("en_GB@currency=EUR", tmp, 4, &status);
1291 resultStr.setTo(tmp);
1292 if (euroStr != resultStr) {
1293 errcheckln(status, "Fail: en_GB@currency=EUR didn't return EUR - %s", u_errorName(status));
1294 }
1295 ucurr_forLocale("en_US_Q", tmp, 4, &status);
1296 resultStr.setTo(tmp);
1297 if (dollarStr != resultStr) {
1298 errcheckln(status, "Fail: en_US_Q didn't fallback to en_US - %s", u_errorName(status));
1299 }
1300 int32_t invalidLen = ucurr_forLocale("en_QQ", tmp, 4, &status);
1301 if (invalidLen || U_SUCCESS(status)) {
1302 errln("Fail: en_QQ didn't return NULL");
1303 }
1304
1305 // The currency keyword value is as long as the destination buffer.
1306 // It should detect the overflow internally, and default to the locale's currency.
1307 tmp[0] = u'¤';
1308 status = U_ZERO_ERROR;
1309 int32_t length = ucurr_forLocale("en_US@currency=euro", tmp, 4, &status);
1310 if (U_FAILURE(status) || dollarStr != UnicodeString(tmp, length)) {
1311 if (U_SUCCESS(status) && tmp[0] == u'¤') {
1312 errln("Fail: ucurr_forLocale(en_US@currency=euro) succeeded without writing output");
1313 } else {
1314 errln("Fail: ucurr_forLocale(en_US@currency=euro) != USD - %s", u_errorName(status));
1315 }
1316 }
1317 }
1318
1319 #endif
1320
1321 /**
1322 * @bug 4139504
1323 * toString() doesn't work with language_VARIANT.
1324 */
1325 void
TestToString()1326 LocaleTest::TestToString() {
1327 Locale DATA [] = {
1328 Locale("xx", "", ""),
1329 Locale("", "YY", ""),
1330 Locale("", "", "ZZ"),
1331 Locale("xx", "YY", ""),
1332 Locale("xx", "", "ZZ"),
1333 Locale("", "YY", "ZZ"),
1334 Locale("xx", "YY", "ZZ"),
1335 };
1336
1337 const char DATA_S [][20] = {
1338 "xx",
1339 "_YY",
1340 "__ZZ",
1341 "xx_YY",
1342 "xx__ZZ",
1343 "_YY_ZZ",
1344 "xx_YY_ZZ",
1345 };
1346
1347 for (int32_t i=0; i < 7; ++i) {
1348 const char *name;
1349 name = DATA[i].getName();
1350
1351 if (strcmp(name, DATA_S[i]) != 0)
1352 {
1353 errln("Fail: Locale.getName(), got:" + UnicodeString(name) + ", expected: " + DATA_S[i]);
1354 }
1355 else
1356 logln("Pass: Locale.getName(), got:" + UnicodeString(name) );
1357 }
1358 }
1359
1360 #if !UCONFIG_NO_FORMATTING
1361
1362 /**
1363 * @bug 4139940
1364 * Couldn't reproduce this bug -- probably was fixed earlier.
1365 *
1366 * ORIGINAL BUG REPORT:
1367 * -- basically, hungarian for monday shouldn't have an \u00f4
1368 * (o circumflex)in it instead it should be an o with 2 inclined
1369 * (right) lines over it..
1370 *
1371 * You may wonder -- why do all this -- why not just add a line to
1372 * LocaleData? Well, I could see by inspection that the locale file had the
1373 * right character in it, so I wanted to check the rest of the pipeline -- a
1374 * very remote possibility, but I wanted to be sure. The other possibility
1375 * is that something is wrong with the font mapping subsystem, but we can't
1376 * test that here.
1377 */
1378 void
Test4139940()1379 LocaleTest::Test4139940()
1380 {
1381 Locale mylocale("hu", "", "");
1382 UDate mydate = date(98,3,13); // A Monday
1383 UErrorCode status = U_ZERO_ERROR;
1384 SimpleDateFormat df_full("EEEE", mylocale, status);
1385 if(U_FAILURE(status)){
1386 dataerrln(UnicodeString("Could not create SimpleDateFormat object for locale hu. Error: ") + UnicodeString(u_errorName(status)));
1387 return;
1388 }
1389 UnicodeString str;
1390 FieldPosition pos(FieldPosition::DONT_CARE);
1391 df_full.format(mydate, str, pos);
1392 // Make sure that o circumflex (\u00F4) is NOT there, and
1393 // o double acute (\u0151) IS.
1394 UChar ocf = 0x00f4;
1395 UChar oda = 0x0151;
1396 if (str.indexOf(oda) < 0 || str.indexOf(ocf) >= 0) {
1397 /* If the default locale is "th" this test will fail because of the buddhist calendar. */
1398 if (strcmp(Locale::getDefault().getLanguage(), "th") != 0) {
1399 errln("Fail: Monday in Hungarian is wrong - oda's index is %d and ocf's is %d",
1400 str.indexOf(oda), str.indexOf(ocf));
1401 } else {
1402 logln(UnicodeString("An error is produce in buddhist calendar."));
1403 }
1404 logln(UnicodeString("String is: ") + str );
1405 }
1406 }
1407
1408 UDate
date(int32_t y,int32_t m,int32_t d,int32_t hr,int32_t min,int32_t sec)1409 LocaleTest::date(int32_t y, int32_t m, int32_t d, int32_t hr, int32_t min, int32_t sec)
1410 {
1411 UErrorCode status = U_ZERO_ERROR;
1412 Calendar *cal = Calendar::createInstance(status);
1413 if (cal == 0)
1414 return 0.0;
1415 cal->clear();
1416 cal->set(1900 + y, m, d, hr, min, sec); // Add 1900 to follow java.util.Date protocol
1417 UDate dt = cal->getTime(status);
1418 if (U_FAILURE(status))
1419 return 0.0;
1420
1421 delete cal;
1422 return dt;
1423 }
1424
1425 /**
1426 * @bug 4143951
1427 * Russian first day of week should be Monday. Confirmed.
1428 */
1429 void
Test4143951()1430 LocaleTest::Test4143951()
1431 {
1432 UErrorCode status = U_ZERO_ERROR;
1433 Calendar *cal = Calendar::createInstance(Locale("ru", "", ""), status);
1434 if(U_SUCCESS(status)) {
1435 if (cal->getFirstDayOfWeek(status) != UCAL_MONDAY) {
1436 dataerrln("Fail: First day of week in Russia should be Monday");
1437 }
1438 }
1439 delete cal;
1440 }
1441
1442 #endif
1443
1444 /**
1445 * @bug 4147315
1446 * java.util.Locale.getISO3Country() works wrong for non ISO-3166 codes.
1447 * Should throw an exception for unknown locales
1448 */
1449 void
Test4147315()1450 LocaleTest::Test4147315()
1451 {
1452 UnicodeString temp;
1453 // Try with codes that are the wrong length but happen to match text
1454 // at a valid offset in the mapping table
1455 Locale locale("xxx", "CCC");
1456
1457 const char *result = locale.getISO3Country();
1458
1459 // Change to conform to C api usage
1460 if((result==NULL)||(result[0] != 0))
1461 errln("ERROR: getISO3Country() returns: " + UnicodeString(result,"") +
1462 " for locale '" + (temp=locale.getName()) + "' rather than exception" );
1463 }
1464
1465 /**
1466 * @bug 4147317
1467 * java.util.Locale.getISO3Language() works wrong for non ISO-3166 codes.
1468 * Should throw an exception for unknown locales
1469 */
1470 void
Test4147317()1471 LocaleTest::Test4147317()
1472 {
1473 UnicodeString temp;
1474 // Try with codes that are the wrong length but happen to match text
1475 // at a valid offset in the mapping table
1476 Locale locale("xxx", "CCC");
1477
1478 const char *result = locale.getISO3Language();
1479
1480 // Change to conform to C api usage
1481 if((result==NULL)||(result[0] != 0))
1482 errln("ERROR: getISO3Language() returns: " + UnicodeString(result,"") +
1483 " for locale '" + (temp=locale.getName()) + "' rather than exception" );
1484 }
1485
1486 /*
1487 * @bug 4147552
1488 */
1489 void
Test4147552()1490 LocaleTest::Test4147552()
1491 {
1492 Locale locales [] = { Locale("no", "NO"),
1493 Locale("no", "NO", "B"),
1494 Locale("no", "NO", "NY")
1495 };
1496
1497 UnicodeString edn("Norwegian (Norway, B)");
1498 UnicodeString englishDisplayNames [] = {
1499 "Norwegian (Norway)",
1500 edn,
1501 // "Norwegian (Norway,B)",
1502 //"Norwegian (Norway,NY)"
1503 "Norwegian (Norway, NY)"
1504 };
1505 UnicodeString ndn("norsk (Norge, B");
1506 UnicodeString norwegianDisplayNames [] = {
1507 "norsk (Norge)",
1508 "norsk (Norge, B)",
1509 //ndn,
1510 "norsk (Noreg, NY)"
1511 //"Norsk (Noreg, Nynorsk)"
1512 };
1513 UErrorCode status = U_ZERO_ERROR;
1514
1515 Locale saveLocale;
1516 Locale::setDefault(Locale::getEnglish(), status);
1517 for (int32_t i = 0; i < 3; ++i) {
1518 Locale loc = locales[i];
1519 UnicodeString temp;
1520 if (loc.getDisplayName(temp) != englishDisplayNames[i])
1521 dataerrln("English display-name mismatch: expected " +
1522 englishDisplayNames[i] + ", got " + loc.getDisplayName(temp));
1523 if (loc.getDisplayName(loc, temp) != norwegianDisplayNames[i])
1524 dataerrln("Norwegian display-name mismatch: expected " +
1525 norwegianDisplayNames[i] + ", got " +
1526 loc.getDisplayName(loc, temp));
1527 }
1528 Locale::setDefault(saveLocale, status);
1529 }
1530
1531 void
TestVariantParsing()1532 LocaleTest::TestVariantParsing()
1533 {
1534 Locale en_US_custom("en", "US", "De Anza_Cupertino_California_United States_Earth");
1535
1536 UnicodeString dispName("English (United States, DE ANZA_CUPERTINO_CALIFORNIA_UNITED STATES_EARTH)");
1537 UnicodeString dispVar("DE ANZA_CUPERTINO_CALIFORNIA_UNITED STATES_EARTH");
1538
1539 UnicodeString got;
1540
1541 en_US_custom.getDisplayVariant(Locale::getUS(), got);
1542 if(got != dispVar) {
1543 errln("FAIL: getDisplayVariant()");
1544 errln("Wanted: " + dispVar);
1545 errln("Got : " + got);
1546 }
1547
1548 en_US_custom.getDisplayName(Locale::getUS(), got);
1549 if(got != dispName) {
1550 dataerrln("FAIL: getDisplayName()");
1551 dataerrln("Wanted: " + dispName);
1552 dataerrln("Got : " + got);
1553 }
1554
1555 Locale shortVariant("fr", "FR", "foo");
1556 shortVariant.getDisplayVariant(got);
1557
1558 if(got != "FOO") {
1559 errln("FAIL: getDisplayVariant()");
1560 errln("Wanted: foo");
1561 errln("Got : " + got);
1562 }
1563
1564 Locale bogusVariant("fr", "FR", "_foo");
1565 bogusVariant.getDisplayVariant(got);
1566
1567 if(got != "FOO") {
1568 errln("FAIL: getDisplayVariant()");
1569 errln("Wanted: foo");
1570 errln("Got : " + got);
1571 }
1572
1573 Locale bogusVariant2("fr", "FR", "foo_");
1574 bogusVariant2.getDisplayVariant(got);
1575
1576 if(got != "FOO") {
1577 errln("FAIL: getDisplayVariant()");
1578 errln("Wanted: foo");
1579 errln("Got : " + got);
1580 }
1581
1582 Locale bogusVariant3("fr", "FR", "_foo_");
1583 bogusVariant3.getDisplayVariant(got);
1584
1585 if(got != "FOO") {
1586 errln("FAIL: getDisplayVariant()");
1587 errln("Wanted: foo");
1588 errln("Got : " + got);
1589 }
1590 }
1591
Test20639_DeprecatesISO3Language()1592 void LocaleTest::Test20639_DeprecatesISO3Language() {
1593 IcuTestErrorCode status(*this, "Test20639_DeprecatesISO3Language");
1594
1595 const struct TestCase {
1596 const char* localeName;
1597 const char* expectedISO3Language;
1598 } cases[] = {
1599 {"nb", "nob"},
1600 {"no", "nor"}, // why not nob?
1601 {"he", "heb"},
1602 {"iw", "heb"},
1603 {"ro", "ron"},
1604 {"mo", "mol"},
1605 };
1606 for (auto& cas : cases) {
1607 Locale loc(cas.localeName);
1608 const char* actual = loc.getISO3Language();
1609 assertEquals(cas.localeName, cas.expectedISO3Language, actual);
1610 }
1611 }
1612
1613 #if !UCONFIG_NO_FORMATTING
1614
1615 /**
1616 * @bug 4105828
1617 * Currency symbol in zh is wrong. We will test this at the NumberFormat
1618 * end to test the whole pipe.
1619 */
1620 void
Test4105828()1621 LocaleTest::Test4105828()
1622 {
1623 Locale LOC [] = { Locale::getChinese(), Locale("zh", "CN", ""),
1624 Locale("zh", "TW", ""), Locale("zh", "HK", "") };
1625 UErrorCode status = U_ZERO_ERROR;
1626 for (int32_t i = 0; i < 4; ++i) {
1627 NumberFormat *fmt = NumberFormat::createPercentInstance(LOC[i], status);
1628 if(U_FAILURE(status)) {
1629 dataerrln("Couldn't create NumberFormat - %s", u_errorName(status));
1630 return;
1631 }
1632 UnicodeString result;
1633 FieldPosition pos(FieldPosition::DONT_CARE);
1634 fmt->format((int32_t)1, result, pos);
1635 UnicodeString temp;
1636 if(result != "100%") {
1637 errln(UnicodeString("Percent for ") + LOC[i].getDisplayName(temp) + " should be 100%, got " + result);
1638 }
1639 delete fmt;
1640 }
1641 }
1642
1643 #endif
1644
1645 // Tests setBogus and isBogus APIs for Locale
1646 // Jitterbug 1735
1647 void
TestSetIsBogus()1648 LocaleTest::TestSetIsBogus() {
1649 Locale l("en_US");
1650 l.setToBogus();
1651 if(l.isBogus() != TRUE) {
1652 errln("After setting bogus, didn't return TRUE");
1653 }
1654 l = "en_US"; // This should reset bogus
1655 if(l.isBogus() != FALSE) {
1656 errln("After resetting bogus, didn't return FALSE");
1657 }
1658 }
1659
1660
1661 void
TestAddLikelySubtags()1662 LocaleTest::TestAddLikelySubtags() {
1663 IcuTestErrorCode status(*this, "TestAddLikelySubtags()");
1664
1665 static const Locale min("sv");
1666 static const Locale max("sv_Latn_SE");
1667
1668 Locale result(min);
1669 result.addLikelySubtags(status);
1670 status.errIfFailureAndReset("\"%s\"", min.getName());
1671 assertEquals("addLikelySubtags", max.getName(), result.getName());
1672 }
1673
1674
1675 void
TestMinimizeSubtags()1676 LocaleTest::TestMinimizeSubtags() {
1677 IcuTestErrorCode status(*this, "TestMinimizeSubtags()");
1678
1679 static const Locale max("zh_Hant_TW");
1680 static const Locale min("zh_TW");
1681
1682 Locale result(max);
1683 result.minimizeSubtags(status);
1684 status.errIfFailureAndReset("\"%s\"", max.getName());
1685 assertEquals("minimizeSubtags", min.getName(), result.getName());
1686 }
1687
1688
1689 void
TestAddLikelyAndMinimizeSubtags()1690 LocaleTest::TestAddLikelyAndMinimizeSubtags() {
1691 IcuTestErrorCode status(*this, "TestAddLikelyAndMinimizeSubtags()");
1692
1693 static const struct {
1694 const char* const from;
1695 const char* const add;
1696 const char* const remove;
1697 } full_data[] = {
1698 {
1699 "und_AQ",
1700 "_Latn_AQ",
1701 "_AQ"
1702 }, {
1703 "und_Zzzz_AQ",
1704 "_Latn_AQ",
1705 "_AQ"
1706 }, {
1707 "und_Latn_AQ",
1708 "_Latn_AQ",
1709 "_AQ"
1710 }, {
1711 "und_Moon_AQ",
1712 "_Moon_AQ",
1713 "_Moon_AQ"
1714 },
1715 };
1716
1717 for (const auto& item : full_data) {
1718 const char* const org = item.from;
1719 const char* const exp = item.add;
1720 Locale res(org);
1721 res.addLikelySubtags(status);
1722 status.errIfFailureAndReset("\"%s\"", org);
1723 assertEquals("addLikelySubtags", exp, res.getName());
1724 }
1725
1726 for (const auto& item : full_data) {
1727 const char* const org = item.from;
1728 const char* const exp = item.remove;
1729 Locale res(org);
1730 res.minimizeSubtags(status);
1731 status.errIfFailureAndReset("\"%s\"", org);
1732 assertEquals("minimizeSubtags", exp, res.getName());
1733 }
1734 }
1735
1736
1737 void
TestKeywordVariants(void)1738 LocaleTest::TestKeywordVariants(void) {
1739 static const struct {
1740 const char *localeID;
1741 const char *expectedLocaleID;
1742 //const char *expectedLocaleIDNoKeywords;
1743 //const char *expectedCanonicalID;
1744 const char *expectedKeywords[10];
1745 int32_t numKeywords;
1746 UErrorCode expectedStatus;
1747 } testCases[] = {
1748 {
1749 "de_DE@ currency = euro; C o ll A t i o n = Phonebook ; C alen dar = buddhist ",
1750 "de_DE@calendar=buddhist;collation=Phonebook;currency=euro",
1751 //"de_DE",
1752 //"de_DE@calendar=buddhist;collation=Phonebook;currency=euro",
1753 {"calendar", "collation", "currency"},
1754 3,
1755 U_ZERO_ERROR
1756 },
1757 {
1758 "de_DE@euro",
1759 "de_DE@euro",
1760 //"de_DE",
1761 //"de_DE@currency=EUR",
1762 {"","","","","","",""},
1763 0,
1764 U_INVALID_FORMAT_ERROR /* must have '=' after '@' */
1765 }
1766 };
1767 UErrorCode status = U_ZERO_ERROR;
1768
1769 int32_t i = 0, j = 0;
1770 const char *result = NULL;
1771 StringEnumeration *keywords;
1772 int32_t keyCount = 0;
1773 const char *keyword = NULL;
1774 const UnicodeString *keywordString;
1775 int32_t keywordLen = 0;
1776
1777 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
1778 status = U_ZERO_ERROR;
1779 Locale l(testCases[i].localeID);
1780 keywords = l.createKeywords(status);
1781
1782 if(status != testCases[i].expectedStatus) {
1783 err("Expected to get status %s. Got %s instead\n",
1784 u_errorName(testCases[i].expectedStatus), u_errorName(status));
1785 }
1786 status = U_ZERO_ERROR;
1787 if(keywords) {
1788 if((keyCount = keywords->count(status)) != testCases[i].numKeywords) {
1789 err("Expected to get %i keywords, got %i\n", testCases[i].numKeywords, keyCount);
1790 }
1791 if(keyCount) {
1792 for(j = 0;;) {
1793 if((j&1)==0) {
1794 if((keyword = keywords->next(&keywordLen, status)) == NULL) {
1795 break;
1796 }
1797 if(strcmp(keyword, testCases[i].expectedKeywords[j]) != 0) {
1798 err("Expected to get keyword value %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
1799 }
1800 } else {
1801 if((keywordString = keywords->snext(status)) == NULL) {
1802 break;
1803 }
1804 if(*keywordString != UnicodeString(testCases[i].expectedKeywords[j], "")) {
1805 err("Expected to get keyword UnicodeString %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
1806 }
1807 }
1808 j++;
1809
1810 if(j == keyCount / 2) {
1811 // replace keywords with a clone of itself
1812 StringEnumeration *k2 = keywords->clone();
1813 if(k2 == NULL || keyCount != k2->count(status)) {
1814 errln("KeywordEnumeration.clone() failed");
1815 } else {
1816 delete keywords;
1817 keywords = k2;
1818 }
1819 }
1820 }
1821 keywords->reset(status); // Make sure that reset works.
1822 for(j = 0;;) {
1823 if((keyword = keywords->next(&keywordLen, status)) == NULL) {
1824 break;
1825 }
1826 if(strcmp(keyword, testCases[i].expectedKeywords[j]) != 0) {
1827 err("Expected to get keyword value %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
1828 }
1829 j++;
1830 }
1831 }
1832 delete keywords;
1833 }
1834 result = l.getName();
1835 if(uprv_strcmp(testCases[i].expectedLocaleID, result) != 0) {
1836 err("Expected to get \"%s\" from \"%s\". Got \"%s\" instead\n",
1837 testCases[i].expectedLocaleID, testCases[i].localeID, result);
1838 }
1839
1840 }
1841
1842 }
1843
1844
1845 void
TestCreateUnicodeKeywords(void)1846 LocaleTest::TestCreateUnicodeKeywords(void) {
1847 IcuTestErrorCode status(*this, "TestCreateUnicodeKeywords()");
1848
1849 static const Locale l("de@calendar=buddhist;collation=phonebook");
1850
1851 LocalPointer<StringEnumeration> keys(l.createUnicodeKeywords(status));
1852 status.errIfFailureAndReset("\"%s\"", l.getName());
1853
1854 const char* key;
1855 int32_t resultLength;
1856
1857 key = keys->next(&resultLength, status);
1858 status.errIfFailureAndReset("key #1");
1859 assertEquals("resultLength", 2, resultLength);
1860 assertTrue("key != nullptr", key != nullptr);
1861 if (key != nullptr) {
1862 assertEquals("calendar", "ca", key);
1863 }
1864
1865 key = keys->next(&resultLength, status);
1866 status.errIfFailureAndReset("key #2");
1867 assertEquals("resultLength", 2, resultLength);
1868 assertTrue("key != nullptr", key != nullptr);
1869 if (key != nullptr) {
1870 assertEquals("collation", "co", key);
1871 }
1872
1873 key = keys->next(&resultLength, status);
1874 status.errIfFailureAndReset("end of keys");
1875 assertEquals("resultLength", 0, resultLength);
1876 assertTrue("key == nullptr", key == nullptr);
1877
1878 const UnicodeString* skey;
1879 keys->reset(status); // KeywordEnumeration::reset() never touches status.
1880
1881 skey = keys->snext(status);
1882 status.errIfFailureAndReset("skey #1");
1883 assertTrue("skey != nullptr", skey != nullptr);
1884 if (skey != nullptr) {
1885 assertEquals("calendar", "ca", *skey);
1886 }
1887
1888 skey = keys->snext(status);
1889 status.errIfFailureAndReset("skey #2");
1890 assertTrue("skey != nullptr", skey != nullptr);
1891 if (skey != nullptr) {
1892 assertEquals("collation", "co", *skey);
1893 }
1894
1895 skey = keys->snext(status);
1896 status.errIfFailureAndReset("end of keys");
1897 assertTrue("skey == nullptr", skey == nullptr);
1898 }
1899
1900
1901 void
TestKeywordVariantParsing(void)1902 LocaleTest::TestKeywordVariantParsing(void) {
1903 static const struct {
1904 const char *localeID;
1905 const char *keyword;
1906 const char *expectedValue;
1907 } testCases[] = {
1908 { "de_DE@ C o ll A t i o n = Phonebook ", "collation", "Phonebook" },
1909 { "de_DE", "collation", ""},
1910 { "de_DE@collation= PHONEBOOK", "collation", "PHONEBOOK" },
1911 { "de_DE@ currency = euro ; CoLLaTion = PHONEBOOk ", "collation", "PHONEBOOk" },
1912 };
1913
1914 UErrorCode status = U_ZERO_ERROR;
1915
1916 int32_t i = 0;
1917 int32_t resultLen = 0;
1918 char buffer[256];
1919
1920 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
1921 *buffer = 0;
1922 Locale l(testCases[i].localeID);
1923 resultLen = l.getKeywordValue(testCases[i].keyword, buffer, 256, status);
1924 (void)resultLen; // Suppress unused variable warning.
1925 if(uprv_strcmp(testCases[i].expectedValue, buffer) != 0) {
1926 err("Expected to extract \"%s\" from \"%s\" for keyword \"%s\". Got \"%s\" instead\n",
1927 testCases[i].expectedValue, testCases[i].localeID, testCases[i].keyword, buffer);
1928 }
1929 }
1930 }
1931
1932 void
TestCreateKeywordSet(void)1933 LocaleTest::TestCreateKeywordSet(void) {
1934 IcuTestErrorCode status(*this, "TestCreateKeywordSet()");
1935
1936 static const Locale l("de@calendar=buddhist;collation=phonebook");
1937
1938 std::set<std::string> result;
1939 l.getKeywords<std::string>(
1940 std::insert_iterator<decltype(result)>(result, result.begin()),
1941 status);
1942 status.errIfFailureAndReset("\"%s\"", l.getName());
1943
1944 assertEquals("set::size()", 2, static_cast<int32_t>(result.size()));
1945 assertTrue("set::find(\"calendar\")",
1946 result.find("calendar") != result.end());
1947 assertTrue("set::find(\"collation\")",
1948 result.find("collation") != result.end());
1949 }
1950
1951 void
TestCreateKeywordSetEmpty(void)1952 LocaleTest::TestCreateKeywordSetEmpty(void) {
1953 IcuTestErrorCode status(*this, "TestCreateKeywordSetEmpty()");
1954
1955 static const Locale l("de");
1956
1957 std::set<std::string> result;
1958 l.getKeywords<std::string>(
1959 std::insert_iterator<decltype(result)>(result, result.begin()),
1960 status);
1961 status.errIfFailureAndReset("\"%s\"", l.getName());
1962
1963 assertEquals("set::size()", 0, static_cast<int32_t>(result.size()));
1964 }
1965
1966 void
TestCreateUnicodeKeywordSet(void)1967 LocaleTest::TestCreateUnicodeKeywordSet(void) {
1968 IcuTestErrorCode status(*this, "TestCreateUnicodeKeywordSet()");
1969
1970 static const Locale l("de@calendar=buddhist;collation=phonebook");
1971
1972 std::set<std::string> result;
1973 l.getUnicodeKeywords<std::string>(
1974 std::insert_iterator<decltype(result)>(result, result.begin()),
1975 status);
1976 status.errIfFailureAndReset("\"%s\"", l.getName());
1977
1978 assertEquals("set::size()", 2, static_cast<int32_t>(result.size()));
1979 assertTrue("set::find(\"ca\")",
1980 result.find("ca") != result.end());
1981 assertTrue("set::find(\"co\")",
1982 result.find("co") != result.end());
1983 }
1984
1985 void
TestCreateUnicodeKeywordSetEmpty(void)1986 LocaleTest::TestCreateUnicodeKeywordSetEmpty(void) {
1987 IcuTestErrorCode status(*this, "TestCreateUnicodeKeywordSetEmpty()");
1988
1989 static const Locale l("de");
1990
1991 std::set<std::string> result;
1992 l.getUnicodeKeywords<std::string>(
1993 std::insert_iterator<decltype(result)>(result, result.begin()),
1994 status);
1995 status.errIfFailureAndReset("\"%s\"", l.getName());
1996
1997 assertEquals("set::size()", 0, static_cast<int32_t>(result.size()));
1998 }
1999
2000 void
TestGetKeywordValueStdString(void)2001 LocaleTest::TestGetKeywordValueStdString(void) {
2002 IcuTestErrorCode status(*this, "TestGetKeywordValueStdString()");
2003
2004 static const char tag[] = "fa-u-nu-latn";
2005 static const char keyword[] = "numbers";
2006 static const char expected[] = "latn";
2007
2008 Locale l = Locale::forLanguageTag(tag, status);
2009 status.errIfFailureAndReset("\"%s\"", tag);
2010
2011 std::string result = l.getKeywordValue<std::string>(keyword, status);
2012 status.errIfFailureAndReset("\"%s\"", keyword);
2013 assertEquals(keyword, expected, result.c_str());
2014 }
2015
2016 void
TestGetUnicodeKeywordValueStdString(void)2017 LocaleTest::TestGetUnicodeKeywordValueStdString(void) {
2018 IcuTestErrorCode status(*this, "TestGetUnicodeKeywordValueStdString()");
2019
2020 static const char keyword[] = "co";
2021 static const char expected[] = "phonebk";
2022
2023 static const Locale l("de@calendar=buddhist;collation=phonebook");
2024
2025 std::string result = l.getUnicodeKeywordValue<std::string>(keyword, status);
2026 status.errIfFailureAndReset("\"%s\"", keyword);
2027 assertEquals(keyword, expected, result.c_str());
2028 }
2029
2030 void
TestSetKeywordValue(void)2031 LocaleTest::TestSetKeywordValue(void) {
2032 static const struct {
2033 const char *keyword;
2034 const char *value;
2035 } testCases[] = {
2036 { "collation", "phonebook" },
2037 { "currency", "euro" },
2038 { "calendar", "buddhist" }
2039 };
2040
2041 UErrorCode status = U_ZERO_ERROR;
2042
2043 int32_t i = 0;
2044 int32_t resultLen = 0;
2045 char buffer[256];
2046
2047 Locale l(Locale::getGerman());
2048
2049 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
2050 l.setKeywordValue(testCases[i].keyword, testCases[i].value, status);
2051 if(U_FAILURE(status)) {
2052 err("FAIL: Locale::setKeywordValue failed - %s\n", u_errorName(status));
2053 }
2054
2055 *buffer = 0;
2056 resultLen = l.getKeywordValue(testCases[i].keyword, buffer, 256, status);
2057 (void)resultLen; // Suppress unused variable warning.
2058 if(uprv_strcmp(testCases[i].value, buffer) != 0) {
2059 err("Expected to extract \"%s\" for keyword \"%s\". Got \"%s\" instead\n",
2060 testCases[i].value, testCases[i].keyword, buffer);
2061 }
2062 }
2063 }
2064
2065 void
TestSetKeywordValueStringPiece(void)2066 LocaleTest::TestSetKeywordValueStringPiece(void) {
2067 IcuTestErrorCode status(*this, "TestSetKeywordValueStringPiece()");
2068 Locale l(Locale::getGerman());
2069
2070 l.setKeywordValue(StringPiece("collation"), StringPiece("phonebook"), status);
2071 l.setKeywordValue(StringPiece("calendarxxx", 8), StringPiece("buddhistxxx", 8), status);
2072
2073 static const char expected[] = "de@calendar=buddhist;collation=phonebook";
2074 assertEquals("", expected, l.getName());
2075 }
2076
2077 void
TestSetUnicodeKeywordValueStringPiece(void)2078 LocaleTest::TestSetUnicodeKeywordValueStringPiece(void) {
2079 IcuTestErrorCode status(*this, "TestSetUnicodeKeywordValueStringPiece()");
2080 Locale l(Locale::getGerman());
2081
2082 l.setUnicodeKeywordValue(StringPiece("co"), StringPiece("phonebk"), status);
2083 status.errIfFailureAndReset();
2084
2085 l.setUnicodeKeywordValue(StringPiece("caxxx", 2), StringPiece("buddhistxxx", 8), status);
2086 status.errIfFailureAndReset();
2087
2088 static const char expected[] = "de@calendar=buddhist;collation=phonebook";
2089 assertEquals("", expected, l.getName());
2090
2091 l.setUnicodeKeywordValue("cu", nullptr, status);
2092 status.errIfFailureAndReset();
2093 assertEquals("", expected, l.getName());
2094
2095 l.setUnicodeKeywordValue("!!", nullptr, status);
2096 assertEquals("status", U_ILLEGAL_ARGUMENT_ERROR, status.reset());
2097 assertEquals("", expected, l.getName());
2098
2099 l.setUnicodeKeywordValue("co", "!!", status);
2100 assertEquals("status", U_ILLEGAL_ARGUMENT_ERROR, status.reset());
2101 assertEquals("", expected, l.getName());
2102
2103 l.setUnicodeKeywordValue("co", nullptr, status);
2104 status.errIfFailureAndReset();
2105
2106 l.setUnicodeKeywordValue("ca", "", status);
2107 status.errIfFailureAndReset();
2108
2109 assertEquals("", Locale::getGerman().getName(), l.getName());
2110 }
2111
2112 void
TestGetBaseName(void)2113 LocaleTest::TestGetBaseName(void) {
2114 static const struct {
2115 const char *localeID;
2116 const char *baseName;
2117 } testCases[] = {
2118 { "de_DE@ C o ll A t i o n = Phonebook ", "de_DE" },
2119 { "de@currency = euro; CoLLaTion = PHONEBOOk", "de" },
2120 { "ja@calendar = buddhist", "ja" },
2121 { "de-u-co-phonebk", "de"}
2122 };
2123
2124 int32_t i = 0;
2125
2126 for(i = 0; i < UPRV_LENGTHOF(testCases); i++) {
2127 Locale loc(testCases[i].localeID);
2128 if(strcmp(testCases[i].baseName, loc.getBaseName())) {
2129 errln("For locale \"%s\" expected baseName \"%s\", but got \"%s\"",
2130 testCases[i].localeID, testCases[i].baseName, loc.getBaseName());
2131 return;
2132 }
2133 }
2134
2135 // Verify that adding a keyword to an existing Locale doesn't change the base name.
2136 UErrorCode status = U_ZERO_ERROR;
2137 Locale loc2("en-US");
2138 if (strcmp("en_US", loc2.getBaseName())) {
2139 errln("%s:%d Expected \"en_US\", got \"%s\"", __FILE__, __LINE__, loc2.getBaseName());
2140 }
2141 loc2.setKeywordValue("key", "value", status);
2142 if (strcmp("en_US@key=value", loc2.getName())) {
2143 errln("%s:%d Expected \"en_US@key=value\", got \"%s\"", __FILE__, __LINE__, loc2.getName());
2144 }
2145 if (strcmp("en_US", loc2.getBaseName())) {
2146 errln("%s:%d Expected \"en_US\", got \"%s\"", __FILE__, __LINE__, loc2.getBaseName());
2147 }
2148 }
2149
2150 /**
2151 * Compare two locale IDs. If they are equal, return 0. If `string'
2152 * starts with `prefix' plus an additional element, that is, string ==
2153 * prefix + '_' + x, then return 1. Otherwise return a value < 0.
2154 */
_loccmp(const char * string,const char * prefix)2155 static UBool _loccmp(const char* string, const char* prefix) {
2156 int32_t slen = (int32_t)strlen(string),
2157 plen = (int32_t)strlen(prefix);
2158 int32_t c = uprv_strncmp(string, prefix, plen);
2159 /* 'root' is "less than" everything */
2160 if (prefix[0] == '\0') {
2161 return string[0] != '\0';
2162 }
2163 if (c) return -1; /* mismatch */
2164 if (slen == plen) return 0;
2165 if (string[plen] == '_') return 1;
2166 return -2; /* false match, e.g. "en_USX" cmp "en_US" */
2167 }
2168
2169 /**
2170 * Check the relationship between requested locales, and report problems.
2171 * The caller specifies the expected relationships between requested
2172 * and valid (expReqValid) and between valid and actual (expValidActual).
2173 * Possible values are:
2174 * "gt" strictly greater than, e.g., en_US > en
2175 * "ge" greater or equal, e.g., en >= en
2176 * "eq" equal, e.g., en == en
2177 */
_checklocs(const char * label,const char * req,const Locale & validLoc,const Locale & actualLoc,const char * expReqValid,const char * expValidActual)2178 void LocaleTest::_checklocs(const char* label,
2179 const char* req,
2180 const Locale& validLoc,
2181 const Locale& actualLoc,
2182 const char* expReqValid,
2183 const char* expValidActual) {
2184 const char* valid = validLoc.getName();
2185 const char* actual = actualLoc.getName();
2186 int32_t reqValid = _loccmp(req, valid);
2187 int32_t validActual = _loccmp(valid, actual);
2188 if (((0 == uprv_strcmp(expReqValid, "gt") && reqValid > 0) ||
2189 (0 == uprv_strcmp(expReqValid, "ge") && reqValid >= 0) ||
2190 (0 == uprv_strcmp(expReqValid, "eq") && reqValid == 0)) &&
2191 ((0 == uprv_strcmp(expValidActual, "gt") && validActual > 0) ||
2192 (0 == uprv_strcmp(expValidActual, "ge") && validActual >= 0) ||
2193 (0 == uprv_strcmp(expValidActual, "eq") && validActual == 0))) {
2194 logln("%s; req=%s, valid=%s, actual=%s",
2195 label, req, valid, actual);
2196 } else {
2197 dataerrln("FAIL: %s; req=%s, valid=%s, actual=%s. Require (R %s V) and (V %s A)",
2198 label, req, valid, actual,
2199 expReqValid, expValidActual);
2200 }
2201 }
2202
TestGetLocale(void)2203 void LocaleTest::TestGetLocale(void) {
2204 #if !UCONFIG_NO_SERVICE
2205 const char *req;
2206 Locale valid, actual, reqLoc;
2207
2208 // Calendar
2209 #if !UCONFIG_NO_FORMATTING
2210 {
2211 UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
2212 req = "en_US_BROOKLYN";
2213 Calendar* cal = Calendar::createInstance(Locale::createFromName(req), ec);
2214 if (U_FAILURE(ec)) {
2215 dataerrln("FAIL: Calendar::createInstance failed - %s", u_errorName(ec));
2216 } else {
2217 valid = cal->getLocale(ULOC_VALID_LOCALE, ec);
2218 actual = cal->getLocale(ULOC_ACTUAL_LOCALE, ec);
2219 if (U_FAILURE(ec)) {
2220 errln("FAIL: Calendar::getLocale() failed");
2221 } else {
2222 _checklocs("Calendar", req, valid, actual);
2223 }
2224 /* Make sure that it fails correctly */
2225 ec = U_FILE_ACCESS_ERROR;
2226 if (cal->getLocale(ULOC_VALID_LOCALE, ec).getName()[0] != 0) {
2227 errln("FAIL: Calendar::getLocale() failed to fail correctly. It should have returned \"\"");
2228 }
2229 ec = U_ZERO_ERROR;
2230 }
2231 delete cal;
2232 }
2233 #endif
2234
2235 // DecimalFormat, DecimalFormatSymbols
2236 #if !UCONFIG_NO_FORMATTING
2237 {
2238 UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
2239 req = "fr_FR_NICE";
2240 NumberFormat* nf = NumberFormat::createInstance(Locale::createFromName(req), ec);
2241 if (U_FAILURE(ec)) {
2242 dataerrln("FAIL: NumberFormat::createInstance failed - %s", u_errorName(ec));
2243 } else {
2244 DecimalFormat* dec = dynamic_cast<DecimalFormat*>(nf);
2245 if (dec == NULL) {
2246 errln("FAIL: NumberFormat::createInstance does not return a DecimalFormat");
2247 return;
2248 }
2249 valid = dec->getLocale(ULOC_VALID_LOCALE, ec);
2250 actual = dec->getLocale(ULOC_ACTUAL_LOCALE, ec);
2251 if (U_FAILURE(ec)) {
2252 errln("FAIL: DecimalFormat::getLocale() failed");
2253 } else {
2254 _checklocs("DecimalFormat", req, valid, actual);
2255 }
2256
2257 const DecimalFormatSymbols* sym = dec->getDecimalFormatSymbols();
2258 if (sym == NULL) {
2259 errln("FAIL: getDecimalFormatSymbols returned NULL");
2260 return;
2261 }
2262 valid = sym->getLocale(ULOC_VALID_LOCALE, ec);
2263 actual = sym->getLocale(ULOC_ACTUAL_LOCALE, ec);
2264 if (U_FAILURE(ec)) {
2265 errln("FAIL: DecimalFormatSymbols::getLocale() failed");
2266 } else {
2267 _checklocs("DecimalFormatSymbols", req, valid, actual);
2268 }
2269 }
2270 delete nf;
2271 }
2272 #endif
2273
2274 // DateFormat, DateFormatSymbols
2275 #if !UCONFIG_NO_FORMATTING
2276 {
2277 UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
2278 req = "de_CH_LUCERNE";
2279 DateFormat* df =
2280 DateFormat::createDateInstance(DateFormat::kDefault,
2281 Locale::createFromName(req));
2282 if (df == 0){
2283 dataerrln("Error calling DateFormat::createDateInstance()");
2284 } else {
2285 SimpleDateFormat* dat = dynamic_cast<SimpleDateFormat*>(df);
2286 if (dat == NULL) {
2287 errln("FAIL: DateFormat::createInstance does not return a SimpleDateFormat");
2288 return;
2289 }
2290 valid = dat->getLocale(ULOC_VALID_LOCALE, ec);
2291 actual = dat->getLocale(ULOC_ACTUAL_LOCALE, ec);
2292 if (U_FAILURE(ec)) {
2293 errln("FAIL: SimpleDateFormat::getLocale() failed");
2294 } else {
2295 _checklocs("SimpleDateFormat", req, valid, actual);
2296 }
2297
2298 const DateFormatSymbols* sym = dat->getDateFormatSymbols();
2299 if (sym == NULL) {
2300 errln("FAIL: getDateFormatSymbols returned NULL");
2301 return;
2302 }
2303 valid = sym->getLocale(ULOC_VALID_LOCALE, ec);
2304 actual = sym->getLocale(ULOC_ACTUAL_LOCALE, ec);
2305 if (U_FAILURE(ec)) {
2306 errln("FAIL: DateFormatSymbols::getLocale() failed");
2307 } else {
2308 _checklocs("DateFormatSymbols", req, valid, actual);
2309 }
2310 }
2311 delete df;
2312 }
2313 #endif
2314
2315 // BreakIterator
2316 #if !UCONFIG_NO_BREAK_ITERATION
2317 {
2318 UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
2319 req = "es_ES_BARCELONA";
2320 reqLoc = Locale::createFromName(req);
2321 BreakIterator* brk = BreakIterator::createWordInstance(reqLoc, ec);
2322 if (U_FAILURE(ec)) {
2323 dataerrln("FAIL: BreakIterator::createWordInstance failed - %s", u_errorName(ec));
2324 } else {
2325 valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
2326 actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
2327 if (U_FAILURE(ec)) {
2328 errln("FAIL: BreakIterator::getLocale() failed");
2329 } else {
2330 _checklocs("BreakIterator", req, valid, actual);
2331 }
2332
2333 // After registering something, the behavior should be different
2334 URegistryKey key = BreakIterator::registerInstance(brk, reqLoc, UBRK_WORD, ec);
2335 brk = 0; // registerInstance adopts
2336 if (U_FAILURE(ec)) {
2337 errln("FAIL: BreakIterator::registerInstance() failed");
2338 } else {
2339 brk = BreakIterator::createWordInstance(reqLoc, ec);
2340 if (U_FAILURE(ec)) {
2341 errln("FAIL: BreakIterator::createWordInstance failed");
2342 } else {
2343 valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
2344 actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
2345 if (U_FAILURE(ec)) {
2346 errln("FAIL: BreakIterator::getLocale() failed");
2347 } else {
2348 // N.B.: now expect valid==actual==req
2349 _checklocs("BreakIterator(registered)",
2350 req, valid, actual, "eq", "eq");
2351 }
2352 }
2353 // No matter what, unregister
2354 BreakIterator::unregister(key, ec);
2355 if (U_FAILURE(ec)) {
2356 errln("FAIL: BreakIterator::unregister() failed");
2357 }
2358 delete brk;
2359 brk = 0;
2360 }
2361
2362 // After unregistering, should behave normally again
2363 brk = BreakIterator::createWordInstance(reqLoc, ec);
2364 if (U_FAILURE(ec)) {
2365 errln("FAIL: BreakIterator::createWordInstance failed");
2366 } else {
2367 valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
2368 actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
2369 if (U_FAILURE(ec)) {
2370 errln("FAIL: BreakIterator::getLocale() failed");
2371 } else {
2372 _checklocs("BreakIterator(unregistered)", req, valid, actual);
2373 }
2374 }
2375 }
2376 delete brk;
2377 }
2378 #endif
2379
2380 // Collator
2381 #if !UCONFIG_NO_COLLATION
2382 {
2383 UErrorCode ec = U_ZERO_ERROR; // give each resource type its own error code
2384
2385 checkRegisteredCollators(NULL); // Don't expect any extras
2386
2387 req = "hi_IN_BHOPAL";
2388 reqLoc = Locale::createFromName(req);
2389 Collator* coll = Collator::createInstance(reqLoc, ec);
2390 if (U_FAILURE(ec)) {
2391 dataerrln("FAIL: Collator::createInstance failed - %s", u_errorName(ec));
2392 } else {
2393 valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
2394 actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
2395 if (U_FAILURE(ec)) {
2396 errln("FAIL: Collator::getLocale() failed");
2397 } else {
2398 _checklocs("Collator", req, valid, actual);
2399 }
2400
2401 // After registering something, the behavior should be different
2402 URegistryKey key = Collator::registerInstance(coll, reqLoc, ec);
2403 coll = 0; // registerInstance adopts
2404 if (U_FAILURE(ec)) {
2405 errln("FAIL: Collator::registerInstance() failed");
2406 } else {
2407 coll = Collator::createInstance(reqLoc, ec);
2408 if (U_FAILURE(ec)) {
2409 errln("FAIL: Collator::createWordInstance failed");
2410 } else {
2411 valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
2412 actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
2413 if (U_FAILURE(ec)) {
2414 errln("FAIL: Collator::getLocale() failed");
2415 } else {
2416 // N.B.: now expect valid==actual==req
2417 _checklocs("Collator(registered)",
2418 req, valid, actual, "eq", "eq");
2419 }
2420 }
2421 checkRegisteredCollators(req); // include hi_IN_BHOPAL
2422
2423 // No matter what, unregister
2424 Collator::unregister(key, ec);
2425 if (U_FAILURE(ec)) {
2426 errln("FAIL: Collator::unregister() failed");
2427 }
2428 delete coll;
2429 coll = 0;
2430 }
2431
2432 // After unregistering, should behave normally again
2433 coll = Collator::createInstance(reqLoc, ec);
2434 if (U_FAILURE(ec)) {
2435 errln("FAIL: Collator::createInstance failed");
2436 } else {
2437 valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
2438 actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
2439 if (U_FAILURE(ec)) {
2440 errln("FAIL: Collator::getLocale() failed");
2441 } else {
2442 _checklocs("Collator(unregistered)", req, valid, actual);
2443 }
2444 }
2445 }
2446 delete coll;
2447
2448 checkRegisteredCollators(NULL); // extra should be gone again
2449 }
2450 #endif
2451 #endif
2452 }
2453
2454 #if !UCONFIG_NO_COLLATION
2455 /**
2456 * Compare Collator::getAvailableLocales(int) [ "old", returning an array ]
2457 * with Collator::getAvailableLocales() [ "new", returning a StringEnumeration ]
2458 * These should be identical (check their API docs) EXCEPT that
2459 * if expectExtra is non-NULL, it will be in the "new" array but not "old".
2460 * Does not return any status but calls errln on error.
2461 * @param expectExtra an extra locale, will be in "new" but not "old". Or NULL.
2462 */
checkRegisteredCollators(const char * expectExtra)2463 void LocaleTest::checkRegisteredCollators(const char *expectExtra) {
2464 UErrorCode status = U_ZERO_ERROR;
2465 int32_t count1=0,count2=0;
2466 Hashtable oldHash(status);
2467 Hashtable newHash(status);
2468 assertSuccess(WHERE, status);
2469
2470 UnicodeString expectStr(expectExtra?expectExtra:"n/a", "");
2471
2472 // the 'old' list (non enumeration)
2473 const Locale* oldList = Collator::getAvailableLocales(count1);
2474 if(oldList == NULL) {
2475 dataerrln("Error: Collator::getAvailableLocales(count) returned NULL");
2476 return;
2477 }
2478
2479 // the 'new' list (enumeration)
2480 LocalPointer<StringEnumeration> newEnum(Collator::getAvailableLocales());
2481 if(newEnum.isNull()) {
2482 errln("Error: collator::getAvailableLocales() returned NULL");
2483 return;
2484 }
2485
2486 // OK. Let's add all of the OLD
2487 // then check for any in the NEW not in OLD
2488 // then check for any in OLD not in NEW.
2489
2490 // 1. add all of OLD
2491 for(int32_t i=0;i<count1;i++) {
2492 const UnicodeString key(oldList[i].getName(), "");
2493 int32_t oldI = oldHash.puti(key, 1, status);
2494 if( oldI == 1 ){
2495 errln("Error: duplicate key %s in Collator::getAvailableLocales(count) list.\n",
2496 oldList[i].getName());
2497 return;
2498 }
2499 if(expectExtra != NULL && !strcmp(expectExtra, oldList[i].getName())) {
2500 errln("Inexplicably, Collator::getAvailableCollators(count) had registered collator %s. This shouldn't happen, so I am going to consider it an error.\n", expectExtra);
2501 }
2502 }
2503
2504 // 2. add all of NEW
2505 const UnicodeString *locStr;
2506 UBool foundExpected = FALSE;
2507 while((locStr = newEnum->snext(status)) && U_SUCCESS(status)) {
2508 count2++;
2509
2510 if(expectExtra != NULL && expectStr == *locStr) {
2511 foundExpected = TRUE;
2512 logln(UnicodeString("Found expected registered collator: ","") + expectStr);
2513 }
2514 (void)foundExpected; // Hush unused variable compiler warning.
2515
2516 if( oldHash.geti(*locStr) == 0 ) {
2517 if(expectExtra != NULL && expectStr==*locStr) {
2518 logln(UnicodeString("As expected, Collator::getAvailableLocales(count) is missing registered collator ") + expectStr);
2519 } else {
2520 errln(UnicodeString("Error: Collator::getAvailableLocales(count) is missing: ","")
2521 + *locStr);
2522 }
2523 }
2524 newHash.puti(*locStr, 1, status);
2525 }
2526
2527 // 3. check all of OLD again
2528 for(int32_t i=0;i<count1;i++) {
2529 const UnicodeString key(oldList[i].getName(), "");
2530 int32_t newI = newHash.geti(key);
2531 if(newI == 0) {
2532 errln(UnicodeString("Error: Collator::getAvailableLocales() is missing: ","")
2533 + key);
2534 }
2535 }
2536
2537 int32_t expectCount2 = count1;
2538 if(expectExtra != NULL) {
2539 expectCount2 ++; // if an extra item registered, bump the expect count
2540 }
2541
2542 assertEquals("Collator::getAvail() count", expectCount2, count2);
2543 }
2544 #endif
2545
2546
2547
TestVariantWithOutCountry(void)2548 void LocaleTest::TestVariantWithOutCountry(void) {
2549 Locale loc("en","","POSIX");
2550 if (0 != strcmp(loc.getVariant(), "POSIX")) {
2551 errln("FAIL: en__POSIX didn't get parsed correctly - name is %s - expected %s got %s", loc.getName(), "POSIX", loc.getVariant());
2552 }
2553 Locale loc2("en","","FOUR");
2554 if (0 != strcmp(loc2.getVariant(), "FOUR")) {
2555 errln("FAIL: en__FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc2.getName(), "FOUR", loc2.getVariant());
2556 }
2557 Locale loc3("en","Latn","","FOUR");
2558 if (0 != strcmp(loc3.getVariant(), "FOUR")) {
2559 errln("FAIL: en_Latn__FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc3.getName(), "FOUR", loc3.getVariant());
2560 }
2561 Locale loc4("","Latn","","FOUR");
2562 if (0 != strcmp(loc4.getVariant(), "FOUR")) {
2563 errln("FAIL: _Latn__FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc4.getName(), "FOUR", loc4.getVariant());
2564 }
2565 Locale loc5("","Latn","US","FOUR");
2566 if (0 != strcmp(loc5.getVariant(), "FOUR")) {
2567 errln("FAIL: _Latn_US_FOUR didn't get parsed correctly - name is %s - expected %s got %s", loc5.getName(), "FOUR", loc5.getVariant());
2568 }
2569 Locale loc6("de-1901");
2570 if (0 != strcmp(loc6.getVariant(), "1901")) {
2571 errln("FAIL: de-1901 didn't get parsed correctly - name is %s - expected %s got %s", loc6.getName(), "1901", loc6.getVariant());
2572 }
2573 }
2574
_canonicalize(int32_t selector,const char * localeID)2575 static Locale _canonicalize(int32_t selector, /* 0==createFromName, 1==createCanonical, 2==Locale ct */
2576 const char* localeID) {
2577 switch (selector) {
2578 case 0:
2579 return Locale::createFromName(localeID);
2580 case 1:
2581 return Locale::createCanonical(localeID);
2582 case 2:
2583 return Locale(localeID);
2584 default:
2585 return Locale("");
2586 }
2587 }
2588
TestCanonicalization(void)2589 void LocaleTest::TestCanonicalization(void)
2590 {
2591 static const struct {
2592 const char *localeID; /* input */
2593 const char *getNameID; /* expected getName() result */
2594 const char *canonicalID; /* expected canonicalize() result */
2595 } testCases[] = {
2596 { "ca_ES-with-extra-stuff-that really doesn't make any sense-unless-you're trying to increase code coverage",
2597 "ca_ES_WITH_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_YOU'RE TRYING TO INCREASE CODE COVERAGE",
2598 "ca_ES_WITH_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_YOU'RE TRYING TO INCREASE CODE COVERAGE"},
2599 { "zh@collation=pinyin", "zh@collation=pinyin", "zh@collation=pinyin" },
2600 { "zh_CN@collation=pinyin", "zh_CN@collation=pinyin", "zh_Hans_CN@collation=pinyin" },
2601 { "zh_CN_CA@collation=pinyin", "zh_CN_CA@collation=pinyin", "zh_Hans_CN_CA@collation=pinyin" },
2602 { "en_US_POSIX", "en_US_POSIX", "en_US_POSIX" },
2603 { "hy_AM_REVISED", "hy_AM_REVISED", "hy_AM_REVISED" },
2604 { "no_NO_NY", "no_NO_NY", "nb_NO_NY" /* not: "nn_NO" [alan ICU3.0] */ },
2605 { "no@ny", "no@ny", "nb__NY" /* not: "nn" [alan ICU3.0] */ }, /* POSIX ID */
2606 { "no-no.utf32@B", "no_NO.utf32@B", "nb_NO_B" /* not: "nb_NO_B" [alan ICU3.0] */ }, /* POSIX ID */
2607 { "qz-qz@Euro", "qz_QZ@Euro", "qz_QZ_EURO" }, /* qz-qz uses private use iso codes */
2608 // NOTE: uloc_getName() works on en-BOONT, but Locale() parser considers it BOGUS
2609 // TODO: unify this behavior
2610 { "en-BOONT", "en__BOONT", "en__BOONT" }, /* registered name */
2611 { "de-1901", "de__1901", "de__1901" }, /* registered name */
2612 { "de-1906", "de__1906", "de__1906" }, /* registered name */
2613
2614 /* posix behavior that used to be performed by getName */
2615 { "mr.utf8", "mr.utf8", "mr" },
2616 { "de-tv.koi8r", "de_TV.koi8r", "de_TV" },
2617 { "x-piglatin_ML.MBE", "x-piglatin_ML.MBE", "x-piglatin_ML" },
2618 { "i-cherokee_US.utf7", "i-cherokee_US.utf7", "i-cherokee_US" },
2619 { "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA" },
2620 { "no-no-ny.utf8@B", "no_NO_NY.utf8@B", "nb_NO_NY_B" /* not: "nn_NO" [alan ICU3.0] */ }, /* @ ignored unless variant is empty */
2621
2622 /* fleshing out canonicalization */
2623 /* trim space and sort keywords, ';' is separator so not present at end in canonical form */
2624 { "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" },
2625 /* already-canonical ids are not changed */
2626 { "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" },
2627 /* norwegian is just too weird, if we handle things in their full generality */
2628 { "no-Hant-GB_NY@currency=$$$", "no_Hant_GB_NY@currency=$$$", "nb_Hant_GB_NY@currency=$$$" /* not: "nn_Hant_GB@currency=$$$" [alan ICU3.0] */ },
2629
2630 /* test cases reflecting internal resource bundle usage */
2631 { "root@kw=foo", "root@kw=foo", "root@kw=foo" },
2632 { "@calendar=gregorian", "@calendar=gregorian", "@calendar=gregorian" },
2633 { "ja_JP@calendar=Japanese", "ja_JP@calendar=Japanese", "ja_JP@calendar=Japanese" },
2634
2635 // Before ICU 64, ICU locale canonicalization had some additional mappings.
2636 // They were removed for ICU-20187 "drop support for long-obsolete locale ID variants".
2637 // The following now use standard canonicalization.
2638 { "", "", "" },
2639 { "C", "c", "c" },
2640 { "POSIX", "posix", "posix" },
2641 { "ca_ES_PREEURO", "ca_ES_PREEURO", "ca_ES_PREEURO" },
2642 { "de_AT_PREEURO", "de_AT_PREEURO", "de_AT_PREEURO" },
2643 { "de_DE_PREEURO", "de_DE_PREEURO", "de_DE_PREEURO" },
2644 { "de_LU_PREEURO", "de_LU_PREEURO", "de_LU_PREEURO" },
2645 { "el_GR_PREEURO", "el_GR_PREEURO", "el_GR_PREEURO" },
2646 { "en_BE_PREEURO", "en_BE_PREEURO", "en_BE_PREEURO" },
2647 { "en_IE_PREEURO", "en_IE_PREEURO", "en_IE_PREEURO" },
2648 { "es_ES_PREEURO", "es_ES_PREEURO", "es_ES_PREEURO" },
2649 { "eu_ES_PREEURO", "eu_ES_PREEURO", "eu_ES_PREEURO" },
2650 { "fi_FI_PREEURO", "fi_FI_PREEURO", "fi_FI_PREEURO" },
2651 { "fr_BE_PREEURO", "fr_BE_PREEURO", "fr_BE_PREEURO" },
2652 { "fr_FR_PREEURO", "fr_FR_PREEURO", "fr_FR_PREEURO" },
2653 { "fr_LU_PREEURO", "fr_LU_PREEURO", "fr_LU_PREEURO" },
2654 { "ga_IE_PREEURO", "ga_IE_PREEURO", "ga_IE_PREEURO" },
2655 { "gl_ES_PREEURO", "gl_ES_PREEURO", "gl_ES_PREEURO" },
2656 { "it_IT_PREEURO", "it_IT_PREEURO", "it_IT_PREEURO" },
2657 { "nl_BE_PREEURO", "nl_BE_PREEURO", "nl_BE_PREEURO" },
2658 { "nl_NL_PREEURO", "nl_NL_PREEURO", "nl_NL_PREEURO" },
2659 { "pt_PT_PREEURO", "pt_PT_PREEURO", "pt_PT_PREEURO" },
2660 { "de__PHONEBOOK", "de__PHONEBOOK", "de__PHONEBOOK" },
2661 { "en_GB_EURO", "en_GB_EURO", "en_GB_EURO" },
2662 { "en_GB@EURO", "en_GB@EURO", "en_GB_EURO" }, /* POSIX ID */
2663 { "es__TRADITIONAL", "es__TRADITIONAL", "es__TRADITIONAL" },
2664 { "hi__DIRECT", "hi__DIRECT", "hi__DIRECT" },
2665 { "ja_JP_TRADITIONAL", "ja_JP_TRADITIONAL", "ja_JP_TRADITIONAL" },
2666 { "th_TH_TRADITIONAL", "th_TH_TRADITIONAL", "th_TH_TRADITIONAL" },
2667 { "zh_TW_STROKE", "zh_TW_STROKE", "zh_Hant_TW_STROKE" },
2668 { "zh__PINYIN", "zh__PINYIN", "zh__PINYIN" },
2669 { "sr-SP-Cyrl", "sr_SP_CYRL", "sr_SP_CYRL" }, /* .NET name */
2670 { "sr-SP-Latn", "sr_SP_LATN", "sr_SP_LATN" }, /* .NET name */
2671 { "sr_YU_CYRILLIC", "sr_YU_CYRILLIC", "sr_RS_CYRILLIC" }, /* Linux name */
2672 { "uz-UZ-Cyrl", "uz_UZ_CYRL", "uz_Latn_UZ_CYRL" }, /* .NET name */
2673 { "uz-UZ-Latn", "uz_UZ_LATN", "uz_Latn_UZ_LATN" }, /* .NET name */
2674 { "zh-CHS", "zh_CHS", "zh_CHS" }, /* .NET name */
2675 { "zh-CHT", "zh_CHT", "zh_CHT" }, /* .NET name This may change back to zh_Hant */
2676 /* PRE_EURO and EURO conversions don't affect other keywords */
2677 { "es_ES_PREEURO@CALendar=Japanese", "es_ES_PREEURO@calendar=Japanese", "es_ES_PREEURO@calendar=Japanese" },
2678 { "es_ES_EURO@SHOUT=zipeedeedoodah", "es_ES_EURO@shout=zipeedeedoodah", "es_ES_EURO@shout=zipeedeedoodah" },
2679 /* currency keyword overrides PRE_EURO and EURO currency */
2680 { "es_ES_PREEURO@currency=EUR", "es_ES_PREEURO@currency=EUR", "es_ES_PREEURO@currency=EUR" },
2681 { "es_ES_EURO@currency=ESP", "es_ES_EURO@currency=ESP", "es_ES_EURO@currency=ESP" },
2682 };
2683
2684 static const char* label[] = { "createFromName", "createCanonical", "Locale" };
2685
2686 int32_t i, j;
2687
2688 for (i=0; i < UPRV_LENGTHOF(testCases); i++) {
2689 for (j=0; j<3; ++j) {
2690 const char* expected = (j==1) ? testCases[i].canonicalID : testCases[i].getNameID;
2691 Locale loc = _canonicalize(j, testCases[i].localeID);
2692 const char* getName = loc.isBogus() ? "BOGUS" : loc.getName();
2693 if(uprv_strcmp(expected, getName) != 0) {
2694 errln("FAIL: %s(%s).getName() => \"%s\", expected \"%s\"",
2695 label[j], testCases[i].localeID, getName, expected);
2696 } else {
2697 logln("Ok: %s(%s) => \"%s\"",
2698 label[j], testCases[i].localeID, getName);
2699 }
2700 }
2701 }
2702 }
2703
TestCanonicalize(void)2704 void LocaleTest::TestCanonicalize(void)
2705 {
2706 static const struct {
2707 const char *localeID; /* input */
2708 const char *canonicalID; /* expected canonicalize() result */
2709 } testCases[] = {
2710 // language _ variant -> language
2711 { "no-BOKMAL", "nb" },
2712 // also test with script, country and extensions
2713 { "no-Cyrl-ID-BOKMAL-u-ca-japanese", "nb-Cyrl-ID-u-ca-japanese" },
2714 { "no-Cyrl-ID-1901-BOKMAL-xsistemo-u-ca-japanese", "nb-Cyrl-ID-1901-xsistemo-u-ca-japanese" },
2715 { "no-Cyrl-ID-1901-BOKMAL-u-ca-japanese", "nb-Cyrl-ID-1901-u-ca-japanese" },
2716 { "no-Cyrl-ID-BOKMAL-xsistemo-u-ca-japanese", "nb-Cyrl-ID-xsistemo-u-ca-japanese" },
2717 { "no-NYNORSK", "nn" },
2718 { "no-Cyrl-ID-NYNORSK-u-ca-japanese", "nn-Cyrl-ID-u-ca-japanese" },
2719 { "aa-SAAHO", "ssy" },
2720 // also test with script, country and extensions
2721 { "aa-Deva-IN-SAAHO-u-ca-japanese", "ssy-Deva-IN-u-ca-japanese" },
2722
2723 // language -> language
2724 { "aam", "aas" },
2725 // also test with script, country, variants and extensions
2726 { "aam-Cyrl-ID-3456-u-ca-japanese", "aas-Cyrl-ID-3456-u-ca-japanese" },
2727
2728 // language -> language _ Script
2729 { "sh", "sr-Latn" },
2730 // also test with script
2731 { "sh-Cyrl", "sr-Cyrl" },
2732 // also test with country, variants and extensions
2733 { "sh-ID-3456-u-ca-roc", "sr-Latn-ID-3456-u-ca-roc" },
2734
2735 // language -> language _ country
2736 { "prs", "fa-AF" },
2737 // also test with country
2738 { "prs-RU", "fa-RU" },
2739 // also test with script, variants and extensions
2740 { "prs-Cyrl-1009-u-ca-roc", "fa-Cyrl-AF-1009-u-ca-roc" },
2741
2742 // language _ country -> language _ script _ country
2743 { "pa-IN", "pa-Guru-IN" },
2744 // also test with script
2745 { "pa-Latn-IN", "pa-Latn-IN" },
2746 // also test with variants and extensions
2747 { "pa-IN-5678-u-ca-hindi", "pa-Guru-IN-5678-u-ca-hindi" },
2748
2749 // language _ script _ country -> language _ country
2750 { "ky-Cyrl-KG", "ky-KG" },
2751 // also test with variants and extensions
2752 { "ky-Cyrl-KG-3456-u-ca-roc", "ky-KG-3456-u-ca-roc" },
2753
2754 // Test replacement of territoryAlias
2755 // 554 has one replacement
2756 { "en-554", "en-NZ" },
2757 { "en-554-u-nu-arab", "en-NZ-u-nu-arab" },
2758 // 172 has multiple replacements
2759 // also test with variants
2760 { "ru-172-1234", "ru-RU-1234" },
2761 // also test with extensions
2762 { "ru-172-1234-u-nu-latn", "ru-RU-1234-u-nu-latn" },
2763 // also test with scripts
2764 { "uz-172", "uz-UZ" },
2765 { "uz-Cyrl-172", "uz-Cyrl-UZ" },
2766 { "uz-Bopo-172", "uz-Bopo-UZ" },
2767 // also test with variants and scripts
2768 { "uz-Cyrl-172-5678-u-nu-latn", "uz-Cyrl-UZ-5678-u-nu-latn" },
2769 // a language not used in this region
2770 { "fr-172", "fr-RU" },
2771 };
2772 int32_t i;
2773 for (i=0; i < UPRV_LENGTHOF(testCases); i++) {
2774 UErrorCode status = U_ZERO_ERROR;
2775 std::string otag = testCases[i].localeID;
2776 Locale loc = Locale::forLanguageTag(otag.c_str(), status);
2777 loc.canonicalize(status);
2778 std::string tag = loc.toLanguageTag<std::string>(status);
2779 if (tag != testCases[i].canonicalID) {
2780 errcheckln(status, "FAIL: %s should be canonicalized to %s but got %s - %s",
2781 otag.c_str(),
2782 testCases[i].canonicalID,
2783 tag.c_str(),
2784 u_errorName(status));
2785 }
2786 }
2787 }
2788
TestCurrencyByDate(void)2789 void LocaleTest::TestCurrencyByDate(void)
2790 {
2791 #if !UCONFIG_NO_FORMATTING
2792 UErrorCode status = U_ZERO_ERROR;
2793 UDate date = uprv_getUTCtime();
2794 UChar TMP[4] = {0, 0, 0, 0};
2795 int32_t index = 0;
2796 int32_t resLen = 0;
2797 UnicodeString tempStr, resultStr;
2798
2799 // Cycle through historical currencies
2800 date = (UDate)-630720000000.0; // pre 1961 - no currency defined
2801 index = ucurr_countCurrencies("eo_AM", date, &status);
2802 if (index != 0)
2803 {
2804 errcheckln(status, "FAIL: didn't return 0 for eo_AM - %s", u_errorName(status));
2805 }
2806 resLen = ucurr_forLocaleAndDate("eo_AM", date, index, TMP, 4, &status);
2807 if (resLen != 0) {
2808 errcheckln(status, "FAIL: eo_AM didn't return NULL - %s", u_errorName(status));
2809 }
2810 status = U_ZERO_ERROR;
2811
2812 date = (UDate)0.0; // 1970 - one currency defined
2813 index = ucurr_countCurrencies("eo_AM", date, &status);
2814 if (index != 1)
2815 {
2816 errcheckln(status, "FAIL: didn't return 1 for eo_AM - %s", u_errorName(status));
2817 }
2818 resLen = ucurr_forLocaleAndDate("eo_AM", date, index, TMP, 4, &status);
2819 tempStr.setTo(TMP);
2820 resultStr.setTo("SUR");
2821 if (resultStr != tempStr) {
2822 errcheckln(status, "FAIL: didn't return SUR for eo_AM - %s", u_errorName(status));
2823 }
2824
2825 date = (UDate)693792000000.0; // 1992 - one currency defined
2826 index = ucurr_countCurrencies("eo_AM", date, &status);
2827 if (index != 1)
2828 {
2829 errcheckln(status, "FAIL: didn't return 1 for eo_AM - %s", u_errorName(status));
2830 }
2831 resLen = ucurr_forLocaleAndDate("eo_AM", date, index, TMP, 4, &status);
2832 tempStr.setTo(TMP);
2833 resultStr.setTo("RUR");
2834 if (resultStr != tempStr) {
2835 errcheckln(status, "FAIL: didn't return RUR for eo_AM - %s", u_errorName(status));
2836 }
2837
2838 date = (UDate)977616000000.0; // post 1993 - one currency defined
2839 index = ucurr_countCurrencies("eo_AM", date, &status);
2840 if (index != 1)
2841 {
2842 errcheckln(status, "FAIL: didn't return 1 for eo_AM - %s", u_errorName(status));
2843 }
2844 resLen = ucurr_forLocaleAndDate("eo_AM", date, index, TMP, 4, &status);
2845 tempStr.setTo(TMP);
2846 resultStr.setTo("AMD");
2847 if (resultStr != tempStr) {
2848 errcheckln(status, "FAIL: didn't return AMD for eo_AM - %s", u_errorName(status));
2849 }
2850
2851 // Locale AD has multiple currencies at once
2852 date = (UDate)977616000000.0; // year 2001
2853 index = ucurr_countCurrencies("eo_AD", date, &status);
2854 if (index != 4)
2855 {
2856 errcheckln(status, "FAIL: didn't return 4 for eo_AD - %s", u_errorName(status));
2857 }
2858 resLen = ucurr_forLocaleAndDate("eo_AD", date, 1, TMP, 4, &status);
2859 tempStr.setTo(TMP);
2860 resultStr.setTo("EUR");
2861 if (resultStr != tempStr) {
2862 errcheckln(status, "FAIL: didn't return EUR for eo_AD - %s", u_errorName(status));
2863 }
2864 resLen = ucurr_forLocaleAndDate("eo_AD", date, 2, TMP, 4, &status);
2865 tempStr.setTo(TMP);
2866 resultStr.setTo("ESP");
2867 if (resultStr != tempStr) {
2868 errcheckln(status, "FAIL: didn't return ESP for eo_AD - %s", u_errorName(status));
2869 }
2870 resLen = ucurr_forLocaleAndDate("eo_AD", date, 3, TMP, 4, &status);
2871 tempStr.setTo(TMP);
2872 resultStr.setTo("FRF");
2873 if (resultStr != tempStr) {
2874 errcheckln(status, "FAIL: didn't return FRF for eo_AD - %s", u_errorName(status));
2875 }
2876 resLen = ucurr_forLocaleAndDate("eo_AD", date, 4, TMP, 4, &status);
2877 tempStr.setTo(TMP);
2878 resultStr.setTo("ADP");
2879 if (resultStr != tempStr) {
2880 errcheckln(status, "FAIL: didn't return ADP for eo_AD - %s", u_errorName(status));
2881 }
2882
2883 date = (UDate)0.0; // year 1970
2884 index = ucurr_countCurrencies("eo_AD", date, &status);
2885 if (index != 3)
2886 {
2887 errcheckln(status, "FAIL: didn't return 3 for eo_AD - %s", u_errorName(status));
2888 }
2889 resLen = ucurr_forLocaleAndDate("eo_AD", date, 1, TMP, 4, &status);
2890 tempStr.setTo(TMP);
2891 resultStr.setTo("ESP");
2892 if (resultStr != tempStr) {
2893 errcheckln(status, "FAIL: didn't return ESP for eo_AD - %s", u_errorName(status));
2894 }
2895 resLen = ucurr_forLocaleAndDate("eo_AD", date, 2, TMP, 4, &status);
2896 tempStr.setTo(TMP);
2897 resultStr.setTo("FRF");
2898 if (resultStr != tempStr) {
2899 errcheckln(status, "FAIL: didn't return FRF for eo_AD - %s", u_errorName(status));
2900 }
2901 resLen = ucurr_forLocaleAndDate("eo_AD", date, 3, TMP, 4, &status);
2902 tempStr.setTo(TMP);
2903 resultStr.setTo("ADP");
2904 if (resultStr != tempStr) {
2905 errcheckln(status, "FAIL: didn't return ADP for eo_AD - %s", u_errorName(status));
2906 }
2907
2908 date = (UDate)-630720000000.0; // year 1950
2909 index = ucurr_countCurrencies("eo_AD", date, &status);
2910 if (index != 2)
2911 {
2912 errcheckln(status, "FAIL: didn't return 2 for eo_AD - %s", u_errorName(status));
2913 }
2914 resLen = ucurr_forLocaleAndDate("eo_AD", date, 1, TMP, 4, &status);
2915 tempStr.setTo(TMP);
2916 resultStr.setTo("ESP");
2917 if (resultStr != tempStr) {
2918 errcheckln(status, "FAIL: didn't return ESP for eo_AD - %s", u_errorName(status));
2919 }
2920 resLen = ucurr_forLocaleAndDate("eo_AD", date, 2, TMP, 4, &status);
2921 tempStr.setTo(TMP);
2922 resultStr.setTo("ADP");
2923 if (resultStr != tempStr) {
2924 errcheckln(status, "FAIL: didn't return ADP for eo_AD - %s", u_errorName(status));
2925 }
2926
2927 date = (UDate)-2207520000000.0; // year 1900
2928 index = ucurr_countCurrencies("eo_AD", date, &status);
2929 if (index != 1)
2930 {
2931 errcheckln(status, "FAIL: didn't return 1 for eo_AD - %s", u_errorName(status));
2932 }
2933 resLen = ucurr_forLocaleAndDate("eo_AD", date, 1, TMP, 4, &status);
2934 tempStr.setTo(TMP);
2935 resultStr.setTo("ESP");
2936 if (resultStr != tempStr) {
2937 errcheckln(status, "FAIL: didn't return ESP for eo_AD - %s", u_errorName(status));
2938 }
2939
2940 // Locale UA has gap between years 1994 - 1996
2941 date = (UDate)788400000000.0;
2942 index = ucurr_countCurrencies("eo_UA", date, &status);
2943 if (index != 0)
2944 {
2945 errcheckln(status, "FAIL: didn't return 0 for eo_UA - %s", u_errorName(status));
2946 }
2947 resLen = ucurr_forLocaleAndDate("eo_UA", date, index, TMP, 4, &status);
2948 if (resLen != 0) {
2949 errcheckln(status, "FAIL: eo_UA didn't return NULL - %s", u_errorName(status));
2950 }
2951 status = U_ZERO_ERROR;
2952
2953 // Test index bounds
2954 resLen = ucurr_forLocaleAndDate("eo_UA", date, 100, TMP, 4, &status);
2955 if (resLen != 0) {
2956 errcheckln(status, "FAIL: eo_UA didn't return NULL - %s", u_errorName(status));
2957 }
2958 status = U_ZERO_ERROR;
2959
2960 resLen = ucurr_forLocaleAndDate("eo_UA", date, 0, TMP, 4, &status);
2961 if (resLen != 0) {
2962 errcheckln(status, "FAIL: eo_UA didn't return NULL - %s", u_errorName(status));
2963 }
2964 status = U_ZERO_ERROR;
2965
2966 // Test for bogus locale
2967 index = ucurr_countCurrencies("eo_QQ", date, &status);
2968 if (index != 0)
2969 {
2970 errcheckln(status, "FAIL: didn't return 0 for eo_QQ - %s", u_errorName(status));
2971 }
2972 status = U_ZERO_ERROR;
2973 resLen = ucurr_forLocaleAndDate("eo_QQ", date, 1, TMP, 4, &status);
2974 if (resLen != 0) {
2975 errcheckln(status, "FAIL: eo_QQ didn't return NULL - %s", u_errorName(status));
2976 }
2977 status = U_ZERO_ERROR;
2978 resLen = ucurr_forLocaleAndDate("eo_QQ", date, 0, TMP, 4, &status);
2979 if (resLen != 0) {
2980 errcheckln(status, "FAIL: eo_QQ didn't return NULL - %s", u_errorName(status));
2981 }
2982 status = U_ZERO_ERROR;
2983
2984 // Cycle through histrocial currencies
2985 date = (UDate)977616000000.0; // 2001 - one currency
2986 index = ucurr_countCurrencies("eo_AO", date, &status);
2987 if (index != 1)
2988 {
2989 errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
2990 }
2991 resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
2992 tempStr.setTo(TMP);
2993 resultStr.setTo("AOA");
2994 if (resultStr != tempStr) {
2995 errcheckln(status, "FAIL: didn't return AOA for eo_AO - %s", u_errorName(status));
2996 }
2997
2998 date = (UDate)819936000000.0; // 1996 - 2 currencies
2999 index = ucurr_countCurrencies("eo_AO", date, &status);
3000 if (index != 2)
3001 {
3002 errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
3003 }
3004 resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
3005 tempStr.setTo(TMP);
3006 resultStr.setTo("AOR");
3007 if (resultStr != tempStr) {
3008 errcheckln(status, "FAIL: didn't return AOR for eo_AO - %s", u_errorName(status));
3009 }
3010 resLen = ucurr_forLocaleAndDate("eo_AO", date, 2, TMP, 4, &status);
3011 tempStr.setTo(TMP);
3012 resultStr.setTo("AON");
3013 if (resultStr != tempStr) {
3014 errcheckln(status, "FAIL: didn't return AON for eo_AO - %s", u_errorName(status));
3015 }
3016
3017 date = (UDate)662256000000.0; // 1991 - 2 currencies
3018 index = ucurr_countCurrencies("eo_AO", date, &status);
3019 if (index != 2)
3020 {
3021 errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
3022 }
3023 resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
3024 tempStr.setTo(TMP);
3025 resultStr.setTo("AON");
3026 if (resultStr != tempStr) {
3027 errcheckln(status, "FAIL: didn't return AON for eo_AO - %s", u_errorName(status));
3028 }
3029 resLen = ucurr_forLocaleAndDate("eo_AO", date, 2, TMP, 4, &status);
3030 tempStr.setTo(TMP);
3031 resultStr.setTo("AOK");
3032 if (resultStr != tempStr) {
3033 errcheckln(status, "FAIL: didn't return AOK for eo_AO - %s", u_errorName(status));
3034 }
3035
3036 date = (UDate)315360000000.0; // 1980 - one currency
3037 index = ucurr_countCurrencies("eo_AO", date, &status);
3038 if (index != 1)
3039 {
3040 errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
3041 }
3042 resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
3043 tempStr.setTo(TMP);
3044 resultStr.setTo("AOK");
3045 if (resultStr != tempStr) {
3046 errcheckln(status, "FAIL: didn't return AOK for eo_AO - %s", u_errorName(status));
3047 }
3048
3049 date = (UDate)0.0; // 1970 - no currencies
3050 index = ucurr_countCurrencies("eo_AO", date, &status);
3051 if (index != 0)
3052 {
3053 errcheckln(status, "FAIL: didn't return 1 for eo_AO - %s", u_errorName(status));
3054 }
3055 resLen = ucurr_forLocaleAndDate("eo_AO", date, 1, TMP, 4, &status);
3056 if (resLen != 0) {
3057 errcheckln(status, "FAIL: eo_AO didn't return NULL - %s", u_errorName(status));
3058 }
3059 status = U_ZERO_ERROR;
3060
3061 // Test with currency keyword override
3062 date = (UDate)977616000000.0; // 2001 - two currencies
3063 index = ucurr_countCurrencies("eo_DE@currency=DEM", date, &status);
3064 if (index != 2)
3065 {
3066 errcheckln(status, "FAIL: didn't return 2 for eo_DE@currency=DEM - %s", u_errorName(status));
3067 }
3068 resLen = ucurr_forLocaleAndDate("eo_DE@currency=DEM", date, 1, TMP, 4, &status);
3069 tempStr.setTo(TMP);
3070 resultStr.setTo("EUR");
3071 if (resultStr != tempStr) {
3072 errcheckln(status, "FAIL: didn't return EUR for eo_DE@currency=DEM - %s", u_errorName(status));
3073 }
3074 resLen = ucurr_forLocaleAndDate("eo_DE@currency=DEM", date, 2, TMP, 4, &status);
3075 tempStr.setTo(TMP);
3076 resultStr.setTo("DEM");
3077 if (resultStr != tempStr) {
3078 errcheckln(status, "FAIL: didn't return DEM for eo_DE@currency=DEM - %s", u_errorName(status));
3079 }
3080
3081 // Test Euro Support
3082 status = U_ZERO_ERROR; // reset
3083 date = uprv_getUTCtime();
3084
3085 UChar USD[4];
3086 ucurr_forLocaleAndDate("en_US", date, 1, USD, 4, &status);
3087
3088 UChar YEN[4];
3089 ucurr_forLocaleAndDate("ja_JP", date, 1, YEN, 4, &status);
3090
3091 ucurr_forLocaleAndDate("en_US", date, 1, TMP, 4, &status);
3092 if (u_strcmp(USD, TMP) != 0) {
3093 errcheckln(status, "Fail: en_US didn't return USD - %s", u_errorName(status));
3094 }
3095 ucurr_forLocaleAndDate("en_US_Q", date, 1, TMP, 4, &status);
3096 if (u_strcmp(USD, TMP) != 0) {
3097 errcheckln(status, "Fail: en_US_Q didn't fallback to en_US - %s", u_errorName(status));
3098 }
3099 status = U_ZERO_ERROR; // reset
3100 #endif
3101 }
3102
TestGetVariantWithKeywords(void)3103 void LocaleTest::TestGetVariantWithKeywords(void)
3104 {
3105 Locale l("en_US_VALLEY@foo=value");
3106 const char *variant = l.getVariant();
3107 logln(variant);
3108 test_assert(strcmp("VALLEY", variant) == 0);
3109
3110 UErrorCode status = U_ZERO_ERROR;
3111 char buffer[50];
3112 int32_t len = l.getKeywordValue("foo", buffer, 50, status);
3113 buffer[len] = '\0';
3114 test_assert(strcmp("value", buffer) == 0);
3115 }
3116
TestIsRightToLeft()3117 void LocaleTest::TestIsRightToLeft() {
3118 assertFalse("root LTR", Locale::getRoot().isRightToLeft());
3119 assertFalse("zh LTR", Locale::getChinese().isRightToLeft());
3120 assertTrue("ar RTL", Locale("ar").isRightToLeft());
3121 assertTrue("und-EG RTL", Locale("und-EG").isRightToLeft(), FALSE, TRUE);
3122 assertFalse("fa-Cyrl LTR", Locale("fa-Cyrl").isRightToLeft());
3123 assertTrue("en-Hebr RTL", Locale("en-Hebr").isRightToLeft());
3124 assertTrue("ckb RTL", Locale("ckb").isRightToLeft(), FALSE, TRUE); // Sorani Kurdish
3125 assertFalse("fil LTR", Locale("fil").isRightToLeft());
3126 assertFalse("he-Zyxw LTR", Locale("he-Zyxw").isRightToLeft());
3127 }
3128
TestBug11421()3129 void LocaleTest::TestBug11421() {
3130 Locale::getDefault().getBaseName();
3131 int32_t numLocales;
3132 const Locale *localeList = Locale::getAvailableLocales(numLocales);
3133 for (int localeIndex = 0; localeIndex < numLocales; localeIndex++) {
3134 const Locale &loc = localeList[localeIndex];
3135 if (strncmp(loc.getName(), loc.getBaseName(), strlen(loc.getBaseName()))) {
3136 errln("%s:%d loc.getName=\"%s\"; loc.getBaseName=\"%s\"",
3137 __FILE__, __LINE__, loc.getName(), loc.getBaseName());
3138 break;
3139 }
3140 }
3141 }
3142
3143 // TestBug13277. The failure manifests as valgrind errors.
3144 // See the trac ticket for details.
3145 //
3146
TestBug13277()3147 void LocaleTest::TestBug13277() {
3148 UErrorCode status = U_ZERO_ERROR;
3149 CharString name("en-us-x-foo", -1, status);
3150 while (name.length() < 152) {
3151 name.append("-x-foo", -1, status);
3152 }
3153
3154 while (name.length() < 160) {
3155 name.append('z', status);
3156 Locale loc(name.data(), nullptr, nullptr, nullptr);
3157 }
3158 }
3159
3160 // TestBug13554 Check for read past end of array in getPosixID().
3161 // The bug shows as an Address Sanitizer failure.
3162
TestBug13554()3163 void LocaleTest::TestBug13554() {
3164 UErrorCode status = U_ZERO_ERROR;
3165 const int BUFFER_SIZE = 100;
3166 char posixID[BUFFER_SIZE];
3167
3168 for (uint32_t hostid = 0; hostid < 0x500; ++hostid) {
3169 status = U_ZERO_ERROR;
3170 uprv_convertToPosix(hostid, posixID, BUFFER_SIZE, &status);
3171 }
3172 }
3173
TestBug20410()3174 void LocaleTest::TestBug20410() {
3175 IcuTestErrorCode status(*this, "TestBug20410()");
3176
3177 static const char tag1[] = "art-lojban-x-0";
3178 static const Locale expected1("jbo@x=0");
3179 Locale result1 = Locale::forLanguageTag(tag1, status);
3180 status.errIfFailureAndReset("\"%s\"", tag1);
3181 assertEquals(tag1, expected1.getName(), result1.getName());
3182
3183 static const char tag2[] = "zh-xiang-u-nu-thai-x-0";
3184 static const Locale expected2("hsn@numbers=thai;x=0");
3185 Locale result2 = Locale::forLanguageTag(tag2, status);
3186 status.errIfFailureAndReset("\"%s\"", tag2);
3187 assertEquals(tag2, expected2.getName(), result2.getName());
3188
3189 static const char locid3[] = "art__lojban@x=0";
3190 Locale result3 = Locale::createCanonical(locid3);
3191 static const Locale expected3("jbo@x=0");
3192 assertEquals(locid3, expected3.getName(), result3.getName());
3193
3194 static const char locid4[] = "art-lojban-x-0";
3195 Locale result4 = Locale::createCanonical(locid4);
3196 static const Locale expected4("jbo@x=0");
3197 assertEquals(locid4, expected4.getName(), result4.getName());
3198 }
3199
TestBug20900()3200 void LocaleTest::TestBug20900() {
3201 static const struct {
3202 const char *localeID; /* input */
3203 const char *canonicalID; /* expected canonicalize() result */
3204 } testCases[] = {
3205 { "art-lojban", "jbo" },
3206 { "zh-guoyu", "zh" },
3207 { "zh-hakka", "hak" },
3208 { "zh-xiang", "hsn" },
3209 { "zh-min-nan", "nan" },
3210 { "zh-gan", "gan" },
3211 { "zh-wuu", "wuu" },
3212 { "zh-yue", "yue" },
3213 };
3214
3215 IcuTestErrorCode status(*this, "TestBug20900");
3216 for (int32_t i=0; i < UPRV_LENGTHOF(testCases); i++) {
3217 Locale loc = Locale::createCanonical(testCases[i].localeID);
3218 std::string result = loc.toLanguageTag<std::string>(status);
3219 const char* tag = loc.isBogus() ? "BOGUS" : result.c_str();
3220 status.errIfFailureAndReset("FAIL: createCanonical(%s).toLanguageTag() expected \"%s\"",
3221 testCases[i].localeID, tag);
3222 assertEquals("createCanonical", testCases[i].canonicalID, tag);
3223 }
3224 }
3225
TestConstructorAcceptsBCP47()3226 void LocaleTest::TestConstructorAcceptsBCP47() {
3227 IcuTestErrorCode status(*this, "TestConstructorAcceptsBCP47");
3228
3229 Locale loc1("ar-EG-u-nu-latn");
3230 Locale loc2("ar-EG@numbers=latn");
3231 Locale loc3("ar-EG");
3232 std::string val;
3233
3234 // Check getKeywordValue "numbers"
3235 val = loc1.getKeywordValue<std::string>("numbers", status);
3236 assertEquals("BCP47 syntax has ICU keyword value", "latn", val.c_str());
3237
3238 val = loc2.getKeywordValue<std::string>("numbers", status);
3239 assertEquals("ICU syntax has ICU keyword value", "latn", val.c_str());
3240
3241 val = loc3.getKeywordValue<std::string>("numbers", status);
3242 assertEquals("Default, ICU keyword", "", val.c_str());
3243
3244 // Check getUnicodeKeywordValue "nu"
3245 val = loc1.getUnicodeKeywordValue<std::string>("nu", status);
3246 assertEquals("BCP47 syntax has short unicode keyword value", "latn", val.c_str());
3247
3248 val = loc2.getUnicodeKeywordValue<std::string>("nu", status);
3249 assertEquals("ICU syntax has short unicode keyword value", "latn", val.c_str());
3250
3251 val = loc3.getUnicodeKeywordValue<std::string>("nu", status);
3252 status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR, "Default, short unicode keyword");
3253
3254 // Check getUnicodeKeywordValue "numbers"
3255 val = loc1.getUnicodeKeywordValue<std::string>("numbers", status);
3256 assertEquals("BCP47 syntax has long unicode keyword value", "latn", val.c_str());
3257
3258 val = loc2.getUnicodeKeywordValue<std::string>("numbers", status);
3259 assertEquals("ICU syntax has long unicode keyword value", "latn", val.c_str());
3260
3261 val = loc3.getUnicodeKeywordValue<std::string>("numbers", status);
3262 status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR, "Default, long unicode keyword");
3263 }
3264
TestForLanguageTag()3265 void LocaleTest::TestForLanguageTag() {
3266 IcuTestErrorCode status(*this, "TestForLanguageTag()");
3267
3268 static const char tag_en[] = "en-US";
3269 static const char tag_oed[] = "en-GB-oed";
3270 static const char tag_af[] = "af-t-ar-i0-handwrit-u-ca-coptic-x-foo";
3271 static const char tag_ill[] = "!";
3272 static const char tag_no_nul[] = { 'e', 'n', '-', 'G', 'B' };
3273 static const char tag_ext[] = "en-GB-1-abc-efg-a-xyz";
3274 static const char tag_var[] = "sl-rozaj-biske-1994";
3275
3276 static const Locale loc_en("en_US");
3277 static const Locale loc_oed("en_GB_OXENDICT");
3278 static const Locale loc_af("af@calendar=coptic;t=ar-i0-handwrit;x=foo");
3279 static const Locale loc_null("");
3280 static const Locale loc_gb("en_GB");
3281 static const Locale loc_ext("en_GB@1=abc-efg;a=xyz");
3282 static const Locale loc_var("sl__1994_BISKE_ROZAJ");
3283
3284 Locale result_en = Locale::forLanguageTag(tag_en, status);
3285 status.errIfFailureAndReset("\"%s\"", tag_en);
3286 assertEquals(tag_en, loc_en.getName(), result_en.getName());
3287
3288 Locale result_oed = Locale::forLanguageTag(tag_oed, status);
3289 status.errIfFailureAndReset("\"%s\"", tag_oed);
3290 assertEquals(tag_oed, loc_oed.getName(), result_oed.getName());
3291
3292 Locale result_af = Locale::forLanguageTag(tag_af, status);
3293 status.errIfFailureAndReset("\"%s\"", tag_af);
3294 assertEquals(tag_af, loc_af.getName(), result_af.getName());
3295
3296 Locale result_var = Locale::forLanguageTag(tag_var, status);
3297 status.errIfFailureAndReset("\"%s\"", tag_var);
3298 assertEquals(tag_var, loc_var.getName(), result_var.getName());
3299
3300 Locale result_ill = Locale::forLanguageTag(tag_ill, status);
3301 assertEquals(tag_ill, U_ILLEGAL_ARGUMENT_ERROR, status.reset());
3302 assertTrue(result_ill.getName(), result_ill.isBogus());
3303
3304 Locale result_null = Locale::forLanguageTag(nullptr, status);
3305 status.errIfFailureAndReset("nullptr");
3306 assertEquals("nullptr", loc_null.getName(), result_null.getName());
3307
3308 StringPiece sp_substr(tag_oed, 5); // "en-GB", no NUL.
3309 Locale result_substr = Locale::forLanguageTag(sp_substr, status);
3310 status.errIfFailureAndReset("\"%.*s\"", sp_substr.size(), sp_substr.data());
3311 assertEquals(CharString(sp_substr, status).data(),
3312 loc_gb.getName(), result_substr.getName());
3313
3314 StringPiece sp_no_nul(tag_no_nul, sizeof tag_no_nul); // "en-GB", no NUL.
3315 Locale result_no_nul = Locale::forLanguageTag(sp_no_nul, status);
3316 status.errIfFailureAndReset("\"%.*s\"", sp_no_nul.size(), sp_no_nul.data());
3317 assertEquals(CharString(sp_no_nul, status).data(),
3318 loc_gb.getName(), result_no_nul.getName());
3319
3320 Locale result_ext = Locale::forLanguageTag(tag_ext, status);
3321 status.errIfFailureAndReset("\"%s\"", tag_ext);
3322 assertEquals(tag_ext, loc_ext.getName(), result_ext.getName());
3323 }
3324
TestToLanguageTag()3325 void LocaleTest::TestToLanguageTag() {
3326 IcuTestErrorCode status(*this, "TestToLanguageTag()");
3327
3328 static const Locale loc_c("en_US_POSIX");
3329 static const Locale loc_en("en_US");
3330 static const Locale loc_af("af@calendar=coptic;t=ar-i0-handwrit;x=foo");
3331 static const Locale loc_ext("en@0=abc;a=xyz");
3332 static const Locale loc_empty("");
3333 static const Locale loc_ill("!");
3334 static const Locale loc_variant("sl__ROZAJ_BISKE_1994");
3335
3336 static const char tag_c[] = "en-US-u-va-posix";
3337 static const char tag_en[] = "en-US";
3338 static const char tag_af[] = "af-t-ar-i0-handwrit-u-ca-coptic-x-foo";
3339 static const char tag_ext[] = "en-0-abc-a-xyz";
3340 static const char tag_und[] = "und";
3341 static const char tag_variant[] = "sl-1994-biske-rozaj";
3342
3343 std::string result;
3344 StringByteSink<std::string> sink(&result);
3345 loc_c.toLanguageTag(sink, status);
3346 status.errIfFailureAndReset("\"%s\"", loc_c.getName());
3347 assertEquals(loc_c.getName(), tag_c, result.c_str());
3348
3349 std::string result_c = loc_c.toLanguageTag<std::string>(status);
3350 status.errIfFailureAndReset("\"%s\"", loc_c.getName());
3351 assertEquals(loc_c.getName(), tag_c, result_c.c_str());
3352
3353 std::string result_en = loc_en.toLanguageTag<std::string>(status);
3354 status.errIfFailureAndReset("\"%s\"", loc_en.getName());
3355 assertEquals(loc_en.getName(), tag_en, result_en.c_str());
3356
3357 std::string result_af = loc_af.toLanguageTag<std::string>(status);
3358 status.errIfFailureAndReset("\"%s\"", loc_af.getName());
3359 assertEquals(loc_af.getName(), tag_af, result_af.c_str());
3360
3361 std::string result_ext = loc_ext.toLanguageTag<std::string>(status);
3362 status.errIfFailureAndReset("\"%s\"", loc_ext.getName());
3363 assertEquals(loc_ext.getName(), tag_ext, result_ext.c_str());
3364
3365 std::string result_empty = loc_empty.toLanguageTag<std::string>(status);
3366 status.errIfFailureAndReset("\"%s\"", loc_empty.getName());
3367 assertEquals(loc_empty.getName(), tag_und, result_empty.c_str());
3368
3369 std::string result_ill = loc_ill.toLanguageTag<std::string>(status);
3370 status.errIfFailureAndReset("\"%s\"", loc_ill.getName());
3371 assertEquals(loc_ill.getName(), tag_und, result_ill.c_str());
3372
3373 std::string result_variant = loc_variant.toLanguageTag<std::string>(status);
3374 status.errIfFailureAndReset("\"%s\"", loc_variant.getName());
3375 assertEquals(loc_variant.getName(), tag_variant, result_variant.c_str());
3376
3377 Locale loc_bogus;
3378 loc_bogus.setToBogus();
3379 std::string result_bogus = loc_bogus.toLanguageTag<std::string>(status);
3380 assertEquals("bogus", U_ILLEGAL_ARGUMENT_ERROR, status.reset());
3381 assertTrue(result_bogus.c_str(), result_bogus.empty());
3382 }
3383
3384 /* ICU-20310 */
TestToLanguageTagOmitTrue()3385 void LocaleTest::TestToLanguageTagOmitTrue() {
3386 IcuTestErrorCode status(*this, "TestToLanguageTagOmitTrue()");
3387 assertEquals("en-u-kn should drop true",
3388 "en-u-kn", Locale("en-u-kn-true").toLanguageTag<std::string>(status).c_str());
3389 status.errIfFailureAndReset();
3390 assertEquals("en-u-kn should drop true",
3391 "en-u-kn", Locale("en-u-kn").toLanguageTag<std::string>(status).c_str());
3392 status.errIfFailureAndReset();
3393
3394 assertEquals("de-u-co should drop true",
3395 "de-u-co", Locale("de-u-co").toLanguageTag<std::string>(status).c_str());
3396 status.errIfFailureAndReset();
3397 assertEquals("de-u-co should drop true",
3398 "de-u-co", Locale("de-u-co-yes").toLanguageTag<std::string>(status).c_str());
3399 status.errIfFailureAndReset();
3400 assertEquals("de@collation=yes should drop true",
3401 "de-u-co", Locale("de@collation=yes").toLanguageTag<std::string>(status).c_str());
3402 status.errIfFailureAndReset();
3403
3404 assertEquals("cmn-Hans-CN-t-ca-u-ca-x-t-u should drop true",
3405 "cmn-Hans-CN-t-ca-u-ca-x-t-u",
3406 Locale("cmn-hans-cn-u-ca-t-ca-x-t-u").toLanguageTag<std::string>(status).c_str());
3407 status.errIfFailureAndReset();
3408 }
3409
TestMoveAssign()3410 void LocaleTest::TestMoveAssign() {
3411 // ULOC_FULLNAME_CAPACITY == 157 (uloc.h)
3412 Locale l1("de@collation=phonebook;x="
3413 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
3414 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
3415 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
3416 "aaaaabbbbbzz");
3417
3418 Locale l2;
3419 {
3420 Locale l3(l1);
3421 assertTrue("l1 == l3", l1 == l3);
3422 l2 = std::move(l3);
3423 assertTrue("l1 == l2", l1 == l2);
3424 assertTrue("l2 != l3", l2.getName() != l3.getName());
3425 }
3426
3427 // This should remain true also after l3 has been destructed.
3428 assertTrue("l1 == l2, again", l1 == l2);
3429
3430 Locale l4("de@collation=phonebook");
3431
3432 Locale l5;
3433 {
3434 Locale l6(l4);
3435 assertTrue("l4 == l6", l4 == l6);
3436 l5 = std::move(l6);
3437 assertTrue("l4 == l5", l4 == l5);
3438 assertTrue("l5 != l6", l5.getName() != l6.getName());
3439 }
3440
3441 // This should remain true also after l6 has been destructed.
3442 assertTrue("l4 == l5, again", l4 == l5);
3443
3444 Locale l7("vo_Cyrl_AQ_EURO");
3445
3446 Locale l8;
3447 {
3448 Locale l9(l7);
3449 assertTrue("l7 == l9", l7 == l9);
3450 l8 = std::move(l9);
3451 assertTrue("l7 == l8", l7 == l8);
3452 assertTrue("l8 != l9", l8.getName() != l9.getName());
3453 }
3454
3455 // This should remain true also after l9 has been destructed.
3456 assertTrue("l7 == l8, again", l7 == l8);
3457
3458 assertEquals("language", l7.getLanguage(), l8.getLanguage());
3459 assertEquals("script", l7.getScript(), l8.getScript());
3460 assertEquals("country", l7.getCountry(), l8.getCountry());
3461 assertEquals("variant", l7.getVariant(), l8.getVariant());
3462 assertEquals("bogus", l7.isBogus(), l8.isBogus());
3463 }
3464
TestMoveCtor()3465 void LocaleTest::TestMoveCtor() {
3466 // ULOC_FULLNAME_CAPACITY == 157 (uloc.h)
3467 Locale l1("de@collation=phonebook;x="
3468 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
3469 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
3470 "aaaaabbbbbcccccdddddeeeeefffffggggghhhhh"
3471 "aaaaabbbbbzz");
3472
3473 Locale l3(l1);
3474 assertTrue("l1 == l3", l1 == l3);
3475 Locale l2(std::move(l3));
3476 assertTrue("l1 == l2", l1 == l2);
3477 assertTrue("l2 != l3", l2.getName() != l3.getName());
3478
3479 Locale l4("de@collation=phonebook");
3480
3481 Locale l6(l4);
3482 assertTrue("l4 == l6", l4 == l6);
3483 Locale l5(std::move(l6));
3484 assertTrue("l4 == l5", l4 == l5);
3485 assertTrue("l5 != l6", l5.getName() != l6.getName());
3486
3487 Locale l7("vo_Cyrl_AQ_EURO");
3488
3489 Locale l9(l7);
3490 assertTrue("l7 == l9", l7 == l9);
3491 Locale l8(std::move(l9));
3492 assertTrue("l7 == l8", l7 == l8);
3493 assertTrue("l8 != l9", l8.getName() != l9.getName());
3494
3495 assertEquals("language", l7.getLanguage(), l8.getLanguage());
3496 assertEquals("script", l7.getScript(), l8.getScript());
3497 assertEquals("country", l7.getCountry(), l8.getCountry());
3498 assertEquals("variant", l7.getVariant(), l8.getVariant());
3499 assertEquals("bogus", l7.isBogus(), l8.isBogus());
3500 }
3501
TestBug20407iVariantPreferredValue()3502 void LocaleTest::TestBug20407iVariantPreferredValue() {
3503 IcuTestErrorCode status(*this, "TestBug20407iVariantPreferredValue()");
3504
3505 Locale l = Locale::forLanguageTag("hy-arevela", status);
3506 status.errIfFailureAndReset("hy-arevela fail");
3507 assertTrue("!l.isBogus()", !l.isBogus());
3508
3509 std::string result = l.toLanguageTag<std::string>(status);
3510 assertEquals(l.getName(), "hy", result.c_str());
3511
3512 l = Locale::forLanguageTag("hy-arevmda", status);
3513 status.errIfFailureAndReset("hy-arevmda");
3514 assertTrue("!l.isBogus()", !l.isBogus());
3515
3516 result = l.toLanguageTag<std::string>(status);
3517 assertEquals(l.getName(), "hyw", result.c_str());
3518 }
3519
TestBug13417VeryLongLanguageTag()3520 void LocaleTest::TestBug13417VeryLongLanguageTag() {
3521 IcuTestErrorCode status(*this, "TestBug13417VeryLongLanguageTag()");
3522
3523 static const char tag[] =
3524 "zh-x"
3525 "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
3526 "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
3527 "-foo-bar-baz-foo-bar-baz-foo-bar-baz-foo-bar-baz"
3528 "-foo-bar-baz-fxx"
3529 ;
3530
3531 Locale l = Locale::forLanguageTag(tag, status);
3532 status.errIfFailureAndReset("\"%s\"", tag);
3533 assertTrue("!l.isBogus()", !l.isBogus());
3534
3535 std::string result = l.toLanguageTag<std::string>(status);
3536 status.errIfFailureAndReset("\"%s\"", l.getName());
3537 assertEquals("equals", tag, result.c_str());
3538 }
3539
TestBug11053UnderlineTimeZone()3540 void LocaleTest::TestBug11053UnderlineTimeZone() {
3541 static const char* const tz_in_ext[] = {
3542 "etadd",
3543 "tzdar",
3544 "eheai",
3545 "sttms",
3546 "arirj",
3547 "arrgl",
3548 "aruaq",
3549 "arluq",
3550 "mxpvr",
3551 "brbvb",
3552 "arbue",
3553 "caycb",
3554 "brcgr",
3555 "cayzs",
3556 "crsjo",
3557 "caydq",
3558 "svsal",
3559 "cafne",
3560 "caglb",
3561 "cagoo",
3562 "tcgdt",
3563 "ustel",
3564 "bolpb",
3565 "uslax",
3566 "sxphi",
3567 "mxmex",
3568 "usnyc",
3569 "usxul",
3570 "usndcnt",
3571 "usndnsl",
3572 "ttpos",
3573 "brpvh",
3574 "prsju",
3575 "clpuq",
3576 "caffs",
3577 "cayek",
3578 "brrbr",
3579 "mxstis",
3580 "dosdq",
3581 "brsao",
3582 "gpsbh",
3583 "casjf",
3584 "knbas",
3585 "lccas",
3586 "vistt",
3587 "vcsvd",
3588 "cayyn",
3589 "cathu",
3590 "hkhkg",
3591 "mykul",
3592 "khpnh",
3593 "cvrai",
3594 "gsgrv",
3595 "shshn",
3596 "aubhq",
3597 "auldh",
3598 "imdgs",
3599 "smsai",
3600 "asppg",
3601 "pgpom",
3602 };
3603 static const char* const tzname_with_underline[] = {
3604 "America/Buenos_Aires",
3605 "America/Coral_Harbour",
3606 "America/Los_Angeles",
3607 "America/Mexico_City",
3608 "America/New_York",
3609 "America/Rio_Branco",
3610 "America/Sao_Paulo",
3611 "America/St_Johns",
3612 "America/St_Thomas",
3613 "Australia/Broken_Hill",
3614 "Australia/Lord_Howe",
3615 "Pacific/Pago_Pago",
3616 };
3617 std::string locale_str;
3618 for (int32_t i = 0; i < UPRV_LENGTHOF(tz_in_ext); i++) {
3619 locale_str = "en-u-tz-";
3620 locale_str += tz_in_ext[i];
3621 Locale l(locale_str.c_str());
3622 assertTrue((locale_str + " !l.isBogus()").c_str(), !l.isBogus());
3623 }
3624 for (int32_t i = 0; i < UPRV_LENGTHOF(tzname_with_underline); i++) {
3625 locale_str = "en@timezone=";
3626 locale_str += tzname_with_underline[i];
3627 Locale l(locale_str.c_str());
3628 assertTrue((locale_str + " !l.isBogus()").c_str(), !l.isBogus());
3629 }
3630 locale_str = "en_US@timezone=America/Coral_Harbour";
3631 Locale l2(locale_str.c_str());
3632 assertTrue((locale_str + " !l2.isBogus()").c_str(), !l2.isBogus());
3633 locale_str = "en_Latn@timezone=America/New_York";
3634 Locale l3(locale_str.c_str());
3635 assertTrue((locale_str + " !l3.isBogus()").c_str(), !l3.isBogus());
3636 locale_str = "en_Latn_US@timezone=Australia/Broken_Hill";
3637 Locale l4(locale_str.c_str());
3638 assertTrue((locale_str + " !l4.isBogus()").c_str(), !l4.isBogus());
3639 locale_str = "en-u-tz-ciabj";
3640 Locale l5(locale_str.c_str());
3641 assertTrue((locale_str + " !l5.isBogus()").c_str(), !l5.isBogus());
3642 locale_str = "en-US-u-tz-asppg";
3643 Locale l6(locale_str.c_str());
3644 assertTrue((locale_str + " !l6.isBogus()").c_str(), !l6.isBogus());
3645 locale_str = "fil-Latn-u-tz-cvrai";
3646 Locale l7(locale_str.c_str());
3647 assertTrue((locale_str + " !l7.isBogus()").c_str(), !l7.isBogus());
3648 locale_str = "fil-Latn-PH-u-tz-gsgrv";
3649 Locale l8(locale_str.c_str());
3650 assertTrue((locale_str + " !l8.isBogus()").c_str(), !l8.isBogus());
3651 }
3652
TestUnd()3653 void LocaleTest::TestUnd() {
3654 IcuTestErrorCode status(*this, "TestUnd()");
3655
3656 static const char empty[] = "";
3657 static const char root[] = "root";
3658 static const char und[] = "und";
3659
3660 Locale empty_ctor(empty);
3661 Locale empty_tag = Locale::forLanguageTag(empty, status);
3662 status.errIfFailureAndReset("\"%s\"", empty);
3663
3664 Locale root_ctor(root);
3665 Locale root_tag = Locale::forLanguageTag(root, status);
3666 Locale root_build = LocaleBuilder().setLanguageTag(root).build(status);
3667 status.errIfFailureAndReset("\"%s\"", root);
3668
3669 Locale und_ctor(und);
3670 Locale und_tag = Locale::forLanguageTag(und, status);
3671 Locale und_build = LocaleBuilder().setLanguageTag(und).build(status);
3672 status.errIfFailureAndReset("\"%s\"", und);
3673
3674 assertEquals("getName()", empty, empty_ctor.getName());
3675 assertEquals("getName()", empty, root_ctor.getName());
3676 assertEquals("getName()", empty, und_ctor.getName());
3677
3678 assertEquals("getName()", empty, empty_tag.getName());
3679 assertEquals("getName()", empty, root_tag.getName());
3680 assertEquals("getName()", empty, und_tag.getName());
3681
3682 assertEquals("getName()", empty, root_build.getName());
3683 assertEquals("getName()", empty, und_build.getName());
3684
3685 assertEquals("toLanguageTag()", und, empty_ctor.toLanguageTag<std::string>(status).c_str());
3686 assertEquals("toLanguageTag()", und, root_ctor.toLanguageTag<std::string>(status).c_str());
3687 assertEquals("toLanguageTag()", und, und_ctor.toLanguageTag<std::string>(status).c_str());
3688 status.errIfFailureAndReset();
3689
3690 assertEquals("toLanguageTag()", und, empty_tag.toLanguageTag<std::string>(status).c_str());
3691 assertEquals("toLanguageTag()", und, root_tag.toLanguageTag<std::string>(status).c_str());
3692 assertEquals("toLanguageTag()", und, und_tag.toLanguageTag<std::string>(status).c_str());
3693 status.errIfFailureAndReset();
3694
3695 assertEquals("toLanguageTag()", und, root_build.toLanguageTag<std::string>(status).c_str());
3696 assertEquals("toLanguageTag()", und, und_build.toLanguageTag<std::string>(status).c_str());
3697 status.errIfFailureAndReset();
3698
3699 assertTrue("empty_ctor == empty_tag", empty_ctor == empty_tag);
3700
3701 assertTrue("root_ctor == root_tag", root_ctor == root_tag);
3702 assertTrue("root_ctor == root_build", root_ctor == root_build);
3703 assertTrue("root_tag == root_build", root_tag == root_build);
3704
3705 assertTrue("und_ctor == und_tag", und_ctor == und_tag);
3706 assertTrue("und_ctor == und_build", und_ctor == und_build);
3707 assertTrue("und_tag == und_build", und_tag == und_build);
3708
3709 assertTrue("empty_ctor == root_ctor", empty_ctor == root_ctor);
3710 assertTrue("empty_ctor == und_ctor", empty_ctor == und_ctor);
3711 assertTrue("root_ctor == und_ctor", root_ctor == und_ctor);
3712
3713 assertTrue("empty_tag == root_tag", empty_tag == root_tag);
3714 assertTrue("empty_tag == und_tag", empty_tag == und_tag);
3715 assertTrue("root_tag == und_tag", root_tag == und_tag);
3716
3717 assertTrue("root_build == und_build", root_build == und_build);
3718
3719 static const Locale& displayLocale = Locale::getEnglish();
3720 static const UnicodeString displayName("Unknown language");
3721 UnicodeString tmp;
3722
3723 assertEquals("getDisplayName()", displayName, empty_ctor.getDisplayName(displayLocale, tmp));
3724 assertEquals("getDisplayName()", displayName, root_ctor.getDisplayName(displayLocale, tmp));
3725 assertEquals("getDisplayName()", displayName, und_ctor.getDisplayName(displayLocale, tmp));
3726
3727 assertEquals("getDisplayName()", displayName, empty_tag.getDisplayName(displayLocale, tmp));
3728 assertEquals("getDisplayName()", displayName, root_tag.getDisplayName(displayLocale, tmp));
3729 assertEquals("getDisplayName()", displayName, und_tag.getDisplayName(displayLocale, tmp));
3730
3731 assertEquals("getDisplayName()", displayName, root_build.getDisplayName(displayLocale, tmp));
3732 assertEquals("getDisplayName()", displayName, und_build.getDisplayName(displayLocale, tmp));
3733 }
3734
TestUndScript()3735 void LocaleTest::TestUndScript() {
3736 IcuTestErrorCode status(*this, "TestUndScript()");
3737
3738 static const char id[] = "_Cyrl";
3739 static const char tag[] = "und-Cyrl";
3740 static const char script[] = "Cyrl";
3741
3742 Locale locale_ctor(id);
3743 Locale locale_legacy(tag);
3744 Locale locale_tag = Locale::forLanguageTag(tag, status);
3745 Locale locale_build = LocaleBuilder().setScript(script).build(status);
3746 status.errIfFailureAndReset("\"%s\"", tag);
3747
3748 assertEquals("getName()", id, locale_ctor.getName());
3749 assertEquals("getName()", id, locale_legacy.getName());
3750 assertEquals("getName()", id, locale_tag.getName());
3751 assertEquals("getName()", id, locale_build.getName());
3752
3753 assertEquals("toLanguageTag()", tag, locale_ctor.toLanguageTag<std::string>(status).c_str());
3754 assertEquals("toLanguageTag()", tag, locale_legacy.toLanguageTag<std::string>(status).c_str());
3755 assertEquals("toLanguageTag()", tag, locale_tag.toLanguageTag<std::string>(status).c_str());
3756 assertEquals("toLanguageTag()", tag, locale_build.toLanguageTag<std::string>(status).c_str());
3757 status.errIfFailureAndReset();
3758
3759 static const Locale& displayLocale = Locale::getEnglish();
3760 static const UnicodeString displayName("Unknown language (Cyrillic)");
3761 UnicodeString tmp;
3762
3763 assertEquals("getDisplayName()", displayName, locale_ctor.getDisplayName(displayLocale, tmp));
3764 assertEquals("getDisplayName()", displayName, locale_legacy.getDisplayName(displayLocale, tmp));
3765 assertEquals("getDisplayName()", displayName, locale_tag.getDisplayName(displayLocale, tmp));
3766 assertEquals("getDisplayName()", displayName, locale_build.getDisplayName(displayLocale, tmp));
3767 }
3768
TestUndRegion()3769 void LocaleTest::TestUndRegion() {
3770 IcuTestErrorCode status(*this, "TestUndRegion()");
3771
3772 static const char id[] = "_AQ";
3773 static const char tag[] = "und-AQ";
3774 static const char region[] = "AQ";
3775
3776 Locale locale_ctor(id);
3777 Locale locale_legacy(tag);
3778 Locale locale_tag = Locale::forLanguageTag(tag, status);
3779 Locale locale_build = LocaleBuilder().setRegion(region).build(status);
3780 status.errIfFailureAndReset("\"%s\"", tag);
3781
3782 assertEquals("getName()", id, locale_ctor.getName());
3783 assertEquals("getName()", id, locale_legacy.getName());
3784 assertEquals("getName()", id, locale_tag.getName());
3785 assertEquals("getName()", id, locale_build.getName());
3786
3787 assertEquals("toLanguageTag()", tag, locale_ctor.toLanguageTag<std::string>(status).c_str());
3788 assertEquals("toLanguageTag()", tag, locale_legacy.toLanguageTag<std::string>(status).c_str());
3789 assertEquals("toLanguageTag()", tag, locale_tag.toLanguageTag<std::string>(status).c_str());
3790 assertEquals("toLanguageTag()", tag, locale_build.toLanguageTag<std::string>(status).c_str());
3791 status.errIfFailureAndReset();
3792
3793 static const Locale& displayLocale = Locale::getEnglish();
3794 static const UnicodeString displayName("Unknown language (Antarctica)");
3795 UnicodeString tmp;
3796
3797 assertEquals("getDisplayName()", displayName, locale_ctor.getDisplayName(displayLocale, tmp));
3798 assertEquals("getDisplayName()", displayName, locale_legacy.getDisplayName(displayLocale, tmp));
3799 assertEquals("getDisplayName()", displayName, locale_tag.getDisplayName(displayLocale, tmp));
3800 assertEquals("getDisplayName()", displayName, locale_build.getDisplayName(displayLocale, tmp));
3801 }
3802
TestUndCAPI()3803 void LocaleTest::TestUndCAPI() {
3804 IcuTestErrorCode status(*this, "TestUndCAPI()");
3805
3806 static const char empty[] = "";
3807 static const char root[] = "root";
3808 static const char und[] = "und";
3809
3810 static const char empty_script[] = "_Cyrl";
3811 static const char empty_region[] = "_AQ";
3812
3813 static const char und_script[] = "und_Cyrl";
3814 static const char und_region[] = "und_AQ";
3815
3816 char tmp[ULOC_FULLNAME_CAPACITY];
3817 int32_t reslen;
3818
3819 // uloc_getName()
3820
3821 uprv_memset(tmp, '!', sizeof tmp);
3822 reslen = uloc_getName(empty, tmp, sizeof tmp, status);
3823 status.errIfFailureAndReset("\"%s\"", empty);
3824 assertTrue("reslen >= 0", reslen >= 0);
3825 assertEquals("uloc_getName()", empty, tmp);
3826
3827 uprv_memset(tmp, '!', sizeof tmp);
3828 reslen = uloc_getName(root, tmp, sizeof tmp, status);
3829 status.errIfFailureAndReset("\"%s\"", root);
3830 assertTrue("reslen >= 0", reslen >= 0);
3831 assertEquals("uloc_getName()", empty, tmp);
3832
3833 uprv_memset(tmp, '!', sizeof tmp);
3834 reslen = uloc_getName(und, tmp, sizeof tmp, status);
3835 status.errIfFailureAndReset("\"%s\"", und);
3836 assertTrue("reslen >= 0", reslen >= 0);
3837 assertEquals("uloc_getName()", empty, tmp);
3838
3839 uprv_memset(tmp, '!', sizeof tmp);
3840 reslen = uloc_getName(empty_script, tmp, sizeof tmp, status);
3841 status.errIfFailureAndReset("\"%s\"", empty_script);
3842 assertTrue("reslen >= 0", reslen >= 0);
3843 assertEquals("uloc_getName()", empty_script, tmp);
3844
3845 uprv_memset(tmp, '!', sizeof tmp);
3846 reslen = uloc_getName(empty_region, tmp, sizeof tmp, status);
3847 status.errIfFailureAndReset("\"%s\"", empty_region);
3848 assertTrue("reslen >= 0", reslen >= 0);
3849 assertEquals("uloc_getName()", empty_region, tmp);
3850
3851 uprv_memset(tmp, '!', sizeof tmp);
3852 reslen = uloc_getName(und_script, tmp, sizeof tmp, status);
3853 status.errIfFailureAndReset("\"%s\"", und_script);
3854 assertTrue("reslen >= 0", reslen >= 0);
3855 assertEquals("uloc_getName()", empty_script, tmp);
3856
3857 uprv_memset(tmp, '!', sizeof tmp);
3858 reslen = uloc_getName(und_region, tmp, sizeof tmp, status);
3859 status.errIfFailureAndReset("\"%s\"", und_region);
3860 assertTrue("reslen >= 0", reslen >= 0);
3861 assertEquals("uloc_getName()", empty_region, tmp);
3862
3863 // uloc_getBaseName()
3864
3865 uprv_memset(tmp, '!', sizeof tmp);
3866 reslen = uloc_getBaseName(empty, tmp, sizeof tmp, status);
3867 status.errIfFailureAndReset("\"%s\"", empty);
3868 assertTrue("reslen >= 0", reslen >= 0);
3869 assertEquals("uloc_getBaseName()", empty, tmp);
3870
3871 uprv_memset(tmp, '!', sizeof tmp);
3872 reslen = uloc_getBaseName(root, tmp, sizeof tmp, status);
3873 status.errIfFailureAndReset("\"%s\"", root);
3874 assertTrue("reslen >= 0", reslen >= 0);
3875 assertEquals("uloc_getBaseName()", empty, tmp);
3876
3877 uprv_memset(tmp, '!', sizeof tmp);
3878 reslen = uloc_getBaseName(und, tmp, sizeof tmp, status);
3879 status.errIfFailureAndReset("\"%s\"", und);
3880 assertTrue("reslen >= 0", reslen >= 0);
3881 assertEquals("uloc_getBaseName()", empty, tmp);
3882
3883 uprv_memset(tmp, '!', sizeof tmp);
3884 reslen = uloc_getBaseName(empty_script, tmp, sizeof tmp, status);
3885 status.errIfFailureAndReset("\"%s\"", empty_script);
3886 assertTrue("reslen >= 0", reslen >= 0);
3887 assertEquals("uloc_getBaseName()", empty_script, tmp);
3888
3889 uprv_memset(tmp, '!', sizeof tmp);
3890 reslen = uloc_getBaseName(empty_region, tmp, sizeof tmp, status);
3891 status.errIfFailureAndReset("\"%s\"", empty_region);
3892 assertTrue("reslen >= 0", reslen >= 0);
3893 assertEquals("uloc_getBaseName()", empty_region, tmp);
3894
3895 uprv_memset(tmp, '!', sizeof tmp);
3896 reslen = uloc_getBaseName(und_script, tmp, sizeof tmp, status);
3897 status.errIfFailureAndReset("\"%s\"", und_script);
3898 assertTrue("reslen >= 0", reslen >= 0);
3899 assertEquals("uloc_getBaseName()", empty_script, tmp);
3900
3901 uprv_memset(tmp, '!', sizeof tmp);
3902 reslen = uloc_getBaseName(und_region, tmp, sizeof tmp, status);
3903 status.errIfFailureAndReset("\"%s\"", und_region);
3904 assertTrue("reslen >= 0", reslen >= 0);
3905 assertEquals("uloc_getBaseName()", empty_region, tmp);
3906
3907 // uloc_getParent()
3908
3909 uprv_memset(tmp, '!', sizeof tmp);
3910 reslen = uloc_getParent(empty, tmp, sizeof tmp, status);
3911 status.errIfFailureAndReset("\"%s\"", empty);
3912 assertTrue("reslen >= 0", reslen >= 0);
3913 assertEquals("uloc_getParent()", empty, tmp);
3914
3915 uprv_memset(tmp, '!', sizeof tmp);
3916 reslen = uloc_getParent(root, tmp, sizeof tmp, status);
3917 status.errIfFailureAndReset("\"%s\"", root);
3918 assertTrue("reslen >= 0", reslen >= 0);
3919 assertEquals("uloc_getParent()", empty, tmp);
3920
3921 uprv_memset(tmp, '!', sizeof tmp);
3922 reslen = uloc_getParent(und, tmp, sizeof tmp, status);
3923 status.errIfFailureAndReset("\"%s\"", und);
3924 assertTrue("reslen >= 0", reslen >= 0);
3925 assertEquals("uloc_getParent()", empty, tmp);
3926
3927 uprv_memset(tmp, '!', sizeof tmp);
3928 reslen = uloc_getParent(empty_script, tmp, sizeof tmp, status);
3929 status.errIfFailureAndReset("\"%s\"", empty_script);
3930 assertTrue("reslen >= 0", reslen >= 0);
3931 assertEquals("uloc_getParent()", empty, tmp);
3932
3933 uprv_memset(tmp, '!', sizeof tmp);
3934 reslen = uloc_getParent(empty_region, tmp, sizeof tmp, status);
3935 status.errIfFailureAndReset("\"%s\"", empty_region);
3936 assertTrue("reslen >= 0", reslen >= 0);
3937 assertEquals("uloc_getParent()", empty, tmp);
3938
3939 uprv_memset(tmp, '!', sizeof tmp);
3940 reslen = uloc_getParent(und_script, tmp, sizeof tmp, status);
3941 status.errIfFailureAndReset("\"%s\"", und_script);
3942 assertTrue("reslen >= 0", reslen >= 0);
3943 assertEquals("uloc_getParent()", empty, tmp);
3944
3945 uprv_memset(tmp, '!', sizeof tmp);
3946 reslen = uloc_getParent(und_region, tmp, sizeof tmp, status);
3947 status.errIfFailureAndReset("\"%s\"", und_region);
3948 assertTrue("reslen >= 0", reslen >= 0);
3949 assertEquals("uloc_getParent()", empty, tmp);
3950
3951 // uloc_getLanguage()
3952
3953 uprv_memset(tmp, '!', sizeof tmp);
3954 reslen = uloc_getLanguage(empty, tmp, sizeof tmp, status);
3955 status.errIfFailureAndReset("\"%s\"", empty);
3956 assertTrue("reslen >= 0", reslen >= 0);
3957 assertEquals("uloc_getLanguage()", empty, tmp);
3958
3959 uprv_memset(tmp, '!', sizeof tmp);
3960 reslen = uloc_getLanguage(root, tmp, sizeof tmp, status);
3961 status.errIfFailureAndReset("\"%s\"", root);
3962 assertTrue("reslen >= 0", reslen >= 0);
3963 assertEquals("uloc_getLanguage()", empty, tmp);
3964
3965 uprv_memset(tmp, '!', sizeof tmp);
3966 reslen = uloc_getLanguage(und, tmp, sizeof tmp, status);
3967 status.errIfFailureAndReset("\"%s\"", und);
3968 assertTrue("reslen >= 0", reslen >= 0);
3969 assertEquals("uloc_getLanguage()", empty, tmp);
3970
3971 uprv_memset(tmp, '!', sizeof tmp);
3972 reslen = uloc_getLanguage(empty_script, tmp, sizeof tmp, status);
3973 status.errIfFailureAndReset("\"%s\"", empty_script);
3974 assertTrue("reslen >= 0", reslen >= 0);
3975 assertEquals("uloc_getLanguage()", empty, tmp);
3976
3977 uprv_memset(tmp, '!', sizeof tmp);
3978 reslen = uloc_getLanguage(empty_region, tmp, sizeof tmp, status);
3979 status.errIfFailureAndReset("\"%s\"", empty_region);
3980 assertTrue("reslen >= 0", reslen >= 0);
3981 assertEquals("uloc_getLanguage()", empty, tmp);
3982
3983 uprv_memset(tmp, '!', sizeof tmp);
3984 reslen = uloc_getLanguage(und_script, tmp, sizeof tmp, status);
3985 status.errIfFailureAndReset("\"%s\"", und_script);
3986 assertTrue("reslen >= 0", reslen >= 0);
3987 assertEquals("uloc_getLanguage()", empty, tmp);
3988
3989 uprv_memset(tmp, '!', sizeof tmp);
3990 reslen = uloc_getLanguage(und_region, tmp, sizeof tmp, status);
3991 status.errIfFailureAndReset("\"%s\"", und_region);
3992 assertTrue("reslen >= 0", reslen >= 0);
3993 assertEquals("uloc_getLanguage()", empty, tmp);
3994 }
3995
3996 #define ARRAY_RANGE(array) (array), ((array) + UPRV_LENGTHOF(array))
3997
TestRangeIterator()3998 void LocaleTest::TestRangeIterator() {
3999 IcuTestErrorCode status(*this, "TestRangeIterator");
4000 Locale locales[] = { "fr", "en_GB", "en" };
4001 Locale::RangeIterator<Locale *> iter(ARRAY_RANGE(locales));
4002
4003 assertTrue("0.hasNext()", iter.hasNext());
4004 const Locale &l0 = iter.next();
4005 assertEquals("0.next()", "fr", l0.getName());
4006 assertTrue("&0.next()", &l0 == &locales[0]);
4007
4008 assertTrue("1.hasNext()", iter.hasNext());
4009 const Locale &l1 = iter.next();
4010 assertEquals("1.next()", "en_GB", l1.getName());
4011 assertTrue("&1.next()", &l1 == &locales[1]);
4012
4013 assertTrue("2.hasNext()", iter.hasNext());
4014 const Locale &l2 = iter.next();
4015 assertEquals("2.next()", "en", l2.getName());
4016 assertTrue("&2.next()", &l2 == &locales[2]);
4017
4018 assertFalse("3.hasNext()", iter.hasNext());
4019 }
4020
TestPointerConvertingIterator()4021 void LocaleTest::TestPointerConvertingIterator() {
4022 IcuTestErrorCode status(*this, "TestPointerConvertingIterator");
4023 Locale locales[] = { "fr", "en_GB", "en" };
4024 Locale *pointers[] = { locales, locales + 1, locales + 2 };
4025 // Lambda with explicit reference return type to prevent copy-constructing a temporary
4026 // which would be destructed right away.
4027 Locale::ConvertingIterator<Locale **, std::function<const Locale &(const Locale *)>> iter(
4028 ARRAY_RANGE(pointers), [](const Locale *p) -> const Locale & { return *p; });
4029
4030 assertTrue("0.hasNext()", iter.hasNext());
4031 const Locale &l0 = iter.next();
4032 assertEquals("0.next()", "fr", l0.getName());
4033 assertTrue("&0.next()", &l0 == pointers[0]);
4034
4035 assertTrue("1.hasNext()", iter.hasNext());
4036 const Locale &l1 = iter.next();
4037 assertEquals("1.next()", "en_GB", l1.getName());
4038 assertTrue("&1.next()", &l1 == pointers[1]);
4039
4040 assertTrue("2.hasNext()", iter.hasNext());
4041 const Locale &l2 = iter.next();
4042 assertEquals("2.next()", "en", l2.getName());
4043 assertTrue("&2.next()", &l2 == pointers[2]);
4044
4045 assertFalse("3.hasNext()", iter.hasNext());
4046 }
4047
4048 namespace {
4049
4050 class LocaleFromTag {
4051 public:
LocaleFromTag()4052 LocaleFromTag() : locale(Locale::getRoot()) {}
operator ()(const char * tag)4053 const Locale &operator()(const char *tag) { return locale = Locale(tag); }
4054
4055 private:
4056 // Store the locale in the converter, rather than return a reference to a temporary,
4057 // or a value which could go out of scope with the caller's reference to it.
4058 Locale locale;
4059 };
4060
4061 } // namespace
4062
TestTagConvertingIterator()4063 void LocaleTest::TestTagConvertingIterator() {
4064 IcuTestErrorCode status(*this, "TestTagConvertingIterator");
4065 const char *tags[] = { "fr", "en_GB", "en" };
4066 LocaleFromTag converter;
4067 Locale::ConvertingIterator<const char **, LocaleFromTag> iter(ARRAY_RANGE(tags), converter);
4068
4069 assertTrue("0.hasNext()", iter.hasNext());
4070 const Locale &l0 = iter.next();
4071 assertEquals("0.next()", "fr", l0.getName());
4072
4073 assertTrue("1.hasNext()", iter.hasNext());
4074 const Locale &l1 = iter.next();
4075 assertEquals("1.next()", "en_GB", l1.getName());
4076
4077 assertTrue("2.hasNext()", iter.hasNext());
4078 const Locale &l2 = iter.next();
4079 assertEquals("2.next()", "en", l2.getName());
4080
4081 assertFalse("3.hasNext()", iter.hasNext());
4082 }
4083
TestCapturingTagConvertingIterator()4084 void LocaleTest::TestCapturingTagConvertingIterator() {
4085 IcuTestErrorCode status(*this, "TestCapturingTagConvertingIterator");
4086 const char *tags[] = { "fr", "en_GB", "en" };
4087 // Store the converted locale in a locale variable,
4088 // rather than return a reference to a temporary,
4089 // or a value which could go out of scope with the caller's reference to it.
4090 Locale locale;
4091 // Lambda with explicit reference return type to prevent copy-constructing a temporary
4092 // which would be destructed right away.
4093 Locale::ConvertingIterator<const char **, std::function<const Locale &(const char *)>> iter(
4094 ARRAY_RANGE(tags), [&](const char *tag) -> const Locale & { return locale = Locale(tag); });
4095
4096 assertTrue("0.hasNext()", iter.hasNext());
4097 const Locale &l0 = iter.next();
4098 assertEquals("0.next()", "fr", l0.getName());
4099
4100 assertTrue("1.hasNext()", iter.hasNext());
4101 const Locale &l1 = iter.next();
4102 assertEquals("1.next()", "en_GB", l1.getName());
4103
4104 assertTrue("2.hasNext()", iter.hasNext());
4105 const Locale &l2 = iter.next();
4106 assertEquals("2.next()", "en", l2.getName());
4107
4108 assertFalse("3.hasNext()", iter.hasNext());
4109 }
4110
TestSetUnicodeKeywordValueInLongLocale()4111 void LocaleTest::TestSetUnicodeKeywordValueInLongLocale() {
4112 IcuTestErrorCode status(*this, "TestSetUnicodeKeywordValueInLongLocale");
4113 const char* value = "efghijkl";
4114 icu::Locale l("de");
4115 char keyword[3];
4116 CharString expected("de-u", status);
4117 keyword[2] = '\0';
4118 for (char i = 'a'; i < 's'; i++) {
4119 keyword[0] = keyword[1] = i;
4120 expected.append("-", status);
4121 expected.append(keyword, status);
4122 expected.append("-", status);
4123 expected.append(value, status);
4124 l.setUnicodeKeywordValue(keyword, value, status);
4125 if (status.errIfFailureAndReset(
4126 "setUnicodeKeywordValue(\"%s\", \"%s\") fail while locale is \"%s\"",
4127 keyword, value, l.getName())) {
4128 return;
4129 }
4130 std::string tag = l.toLanguageTag<std::string>(status);
4131 if (status.errIfFailureAndReset(
4132 "toLanguageTag fail on \"%s\"", l.getName())) {
4133 return;
4134 }
4135 if (tag != expected.data()) {
4136 errln("Expected to get \"%s\" bug got \"%s\"", tag.c_str(),
4137 expected.data());
4138 return;
4139 }
4140 }
4141 }
4142
TestSetUnicodeKeywordValueNullInLongLocale()4143 void LocaleTest::TestSetUnicodeKeywordValueNullInLongLocale() {
4144 IcuTestErrorCode status(*this, "TestSetUnicodeKeywordValueNullInLongLocale");
4145 const char *exts[] = {"cf", "cu", "em", "kk", "kr", "ks", "kv", "lb", "lw",
4146 "ms", "nu", "rg", "sd", "ss", "tz"};
4147 for (int32_t i = 0; i < UPRV_LENGTHOF(exts); i++) {
4148 CharString tag("de-u", status);
4149 for (int32_t j = 0; j <= i; j++) {
4150 tag.append("-", status).append(exts[j], status);
4151 }
4152 if (status.errIfFailureAndReset(
4153 "Cannot create tag \"%s\"", tag.data())) {
4154 continue;
4155 }
4156 Locale l = Locale::forLanguageTag(tag.data(), status);
4157 if (status.errIfFailureAndReset(
4158 "Locale::forLanguageTag(\"%s\") failed", tag.data())) {
4159 continue;
4160 }
4161 for (int32_t j = 0; j <= i; j++) {
4162 l.setUnicodeKeywordValue(exts[j], nullptr, status);
4163 if (status.errIfFailureAndReset(
4164 "Locale(\"%s\").setUnicodeKeywordValue(\"%s\", nullptr) failed",
4165 tag.data(), exts[j])) {
4166 continue;
4167 }
4168 }
4169 if (strcmp("de", l.getName()) != 0) {
4170 errln("setUnicodeKeywordValue should remove all extensions from "
4171 "\"%s\" and only have \"de\", but is \"%s\" instead.",
4172 tag.data(), l.getName());
4173 }
4174 }
4175 }
4176