]> git.saurik.com Git - apple/icu.git/blob - icuSources/test/intltest/svccoll.cpp
ICU-57149.0.1.tar.gz
[apple/icu.git] / icuSources / test / intltest / svccoll.cpp
1 /*
2 *******************************************************************************
3 * Copyright (C) 2003-2016, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 *******************************************************************************
6 */
7
8 #include "unicode/utypes.h"
9
10 #if !UCONFIG_NO_COLLATION
11
12 #include "svccoll.h"
13 #include "unicode/coll.h"
14 #include "unicode/strenum.h"
15 #include "cmemory.h"
16 #include "hash.h"
17 #include "uassert.h"
18
19 #include "cstring.h" // internal api used to compare locale strings
20
21 void CollationServiceTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par */)
22 {
23 if (exec) logln("TestSuite CollationServiceTest: ");
24 switch (index) {
25 TESTCASE(0, TestRegister);
26 TESTCASE(1, TestRegisterFactory);
27 TESTCASE(2, TestSeparateTree);
28 default: name = ""; break;
29 }
30 }
31
32 void CollationServiceTest::TestRegister()
33 {
34 #if !UCONFIG_NO_SERVICE
35 // register a singleton
36 const Locale& FR = Locale::getFrance();
37 const Locale& US = Locale::getUS();
38 const Locale US_FOO("en", "US", "FOO");
39
40 UErrorCode status = U_ZERO_ERROR;
41
42 Collator* frcol = Collator::createInstance(FR, status);
43 Collator* uscol = Collator::createInstance(US, status);
44 if(U_FAILURE(status)) {
45 errcheckln(status, "Failed to create collators with %s", u_errorName(status));
46 delete frcol;
47 delete uscol;
48 return;
49 }
50
51 { // try override en_US collator
52 Collator *clone = frcol->clone();
53 URegistryKey key = Collator::registerInstance(frcol, US, status);
54 // frcol has been adopted. We must not use it any more, nor rely on its attributes.
55 frcol = NULL;
56
57 Collator* ncol = Collator::createInstance(US_FOO, status);
58 if (*clone != *ncol) {
59 errln("register of french collator for en_US failed on request for en_US_FOO");
60 }
61 delete clone;
62
63 // The requested locale may be the same as the valid locale,
64 // or may not be supported at all. See ticket #10477.
65 Locale loc = ncol->getLocale(ULOC_REQUESTED_LOCALE, status);
66 if (U_SUCCESS(status) && loc != US_FOO && loc != US) {
67 errln(UnicodeString("requested locale for en_US_FOO is not en_US_FOO nor en_US but ") + loc.getName());
68 }
69 status = U_ZERO_ERROR;
70 loc = ncol->getLocale(ULOC_VALID_LOCALE, status);
71 if (loc != US) {
72 errln(UnicodeString("valid locale for en_US_FOO is not en_US but ") + loc.getName());
73 }
74 loc = ncol->getLocale(ULOC_ACTUAL_LOCALE, status);
75 if (loc != US) {
76 errln(UnicodeString("actual locale for en_US_FOO is not en_US but ") + loc.getName());
77 }
78 delete ncol; ncol = NULL;
79
80 if (!Collator::unregister(key, status)) {
81 errln("failed to unregister french collator");
82 }
83
84 ncol = Collator::createInstance(US, status);
85 if (*uscol != *ncol) {
86 errln("collator after unregister does not match original");
87 }
88 delete ncol; ncol = NULL;
89 }
90
91 // recreate frcol
92 frcol = Collator::createInstance(FR, status);
93
94 LocalUCollatorPointer frFR(ucol_open("fr_FR", &status));
95
96 { // try create collator for new locale
97 Locale fu_FU_FOO("fu", "FU", "FOO");
98 Locale fu_FU("fu", "FU", "");
99
100 Collator* fucol = Collator::createInstance(fu_FU, status);
101 Collator *clone = frcol->clone();
102 URegistryKey key = Collator::registerInstance(frcol, fu_FU, status);
103 frcol = NULL; // frcol has been adopted.
104 Collator* ncol = Collator::createInstance(fu_FU_FOO, status);
105 if (*clone != *ncol) {
106 errln("register of fr collator for fu_FU failed");
107 }
108 delete clone;
109
110 UnicodeString locName = fu_FU.getName();
111 StringEnumeration* localeEnum = Collator::getAvailableLocales();
112 UBool found = FALSE;
113 const UnicodeString* locStr, *ls2;
114 for (locStr = localeEnum->snext(status);
115 !found && locStr != NULL;
116 locStr = localeEnum->snext(status)) {
117 //
118 if (locName == *locStr) {
119 found = TRUE;
120 }
121 }
122
123 StringEnumeration *le2 = NULL;
124 localeEnum->reset(status);
125 int32_t i, count;
126 count = localeEnum->count(status);
127 for(i = 0; i < count; ++i) {
128 if(i == count / 2) {
129 le2 = localeEnum->clone();
130 if(le2 == NULL || count != le2->count(status)) {
131 errln("ServiceEnumeration.clone() failed");
132 break;
133 }
134 }
135 if(i >= count / 2) {
136 locStr = localeEnum->snext(status);
137 ls2 = le2->snext(status);
138 if(*locStr != *ls2) {
139 errln("ServiceEnumeration.clone() failed for item %d", i);
140 }
141 } else {
142 localeEnum->snext(status);
143 }
144 }
145
146 delete localeEnum;
147 delete le2;
148
149 if (!found) {
150 errln("new locale fu_FU not reported as supported locale");
151 }
152
153 UnicodeString displayName;
154 Collator::getDisplayName(fu_FU, displayName);
155 /* The locale display pattern for the locale ja, ko, and zh are different. */
156 const UChar zh_fuFU_Array[] = { 0x0066, 0x0075, 0xff08, 0x0046, 0x0055, 0xff09, 0 };
157 const UnicodeString zh_fuFU(zh_fuFU_Array);
158 const Locale& defaultLocale = Locale::getDefault();
159 if (displayName != "fu (FU)" &&
160 ((defaultLocale == Locale::getKorean() && defaultLocale == Locale::getJapanese()) && displayName == "fu(FU)") &&
161 ((defaultLocale == Locale::getChinese()) && displayName != zh_fuFU)) {
162 errln(UnicodeString("found ") + displayName + " for fu_FU");
163 }
164
165 Collator::getDisplayName(fu_FU, fu_FU, displayName);
166 if (displayName != "fu (FU)" &&
167 ((defaultLocale == Locale::getKorean() && defaultLocale == Locale::getJapanese()) && displayName == "fu(FU)") &&
168 ((defaultLocale == Locale::getChinese()) && displayName != zh_fuFU)) {
169 errln(UnicodeString("found ") + displayName + " for fu_FU");
170 }
171
172 // test ucol_open
173 LocalUCollatorPointer fufu(ucol_open("fu_FU_FOO", &status));
174 if (fufu.isNull()) {
175 errln("could not open fu_FU_FOO with ucol_open");
176 } else {
177 if (*Collator::fromUCollator(fufu.getAlias()) !=
178 *Collator::fromUCollator(frFR.getAlias())) {
179 errln("collator fufu != collator frFR");
180 }
181 }
182
183 if (!Collator::unregister(key, status)) {
184 errln("failed to unregister french collator");
185 }
186 // !!! note frcoll invalid again, but we're no longer using it
187
188 // other collators should still work ok
189 Locale nloc = ncol->getLocale(ULOC_VALID_LOCALE, status);
190 if (nloc != fu_FU) {
191 errln(UnicodeString("asked for nloc valid locale after close and got") + nloc.getName());
192 }
193 delete ncol; ncol = NULL;
194
195 if (fufu.isValid()) {
196 const char* nlocstr = ucol_getLocaleByType(fufu.getAlias(), ULOC_VALID_LOCALE, &status);
197 if (uprv_strcmp(nlocstr, "fu_FU") != 0) {
198 errln(UnicodeString("asked for uloc valid locale after close and got ") + nlocstr);
199 }
200 }
201
202 ncol = Collator::createInstance(fu_FU, status);
203 if (*fucol != *ncol) {
204 errln("collator after unregister does not match original fu_FU");
205 }
206 delete uscol; uscol = NULL;
207 delete ncol; ncol = NULL;
208 delete fucol; fucol = NULL;
209 }
210 #endif
211 }
212
213 // ------------------
214
215 #if !UCONFIG_NO_SERVICE
216 struct CollatorInfo {
217 Locale locale;
218 Collator* collator;
219 Hashtable* displayNames; // locale name -> string
220
221 CollatorInfo(const Locale& locale, Collator* collatorToAdopt, Hashtable* displayNamesToAdopt);
222 ~CollatorInfo();
223 UnicodeString& getDisplayName(const Locale& displayLocale, UnicodeString& name) const;
224 };
225
226 CollatorInfo::CollatorInfo(const Locale& _locale, Collator* _collator, Hashtable* _displayNames)
227 : locale(_locale)
228 , collator(_collator)
229 , displayNames(_displayNames)
230 {
231 collator->setLocales(locale, locale, locale);
232 }
233
234 CollatorInfo::~CollatorInfo() {
235 delete collator;
236 delete displayNames;
237 }
238
239 UnicodeString&
240 CollatorInfo::getDisplayName(const Locale& displayLocale, UnicodeString& name) const {
241 if (displayNames) {
242 UnicodeString* val = (UnicodeString*)displayNames->get(displayLocale.getName());
243 if (val) {
244 name = *val;
245 return name;
246 }
247 }
248
249 return locale.getDisplayName(displayLocale, name);
250 }
251
252 // ---------------
253
254 class TestFactory : public CollatorFactory {
255 CollatorInfo** info;
256 int32_t count;
257 UnicodeString* ids;
258
259 const CollatorInfo* getInfo(const Locale& loc) const {
260 for (CollatorInfo** p = info; *p; ++p) {
261 if (loc == (**p).locale) {
262 return *p;
263 }
264 }
265 return NULL;
266 }
267
268 public:
269 TestFactory(CollatorInfo** _info)
270 : info(_info)
271 , count(0)
272 , ids(NULL)
273 {
274 CollatorInfo** p;
275 for (p = info; *p; ++p) {}
276 count = (int32_t)(p - info);
277 }
278
279 ~TestFactory() {
280 for (CollatorInfo** p = info; *p; ++p) {
281 delete *p;
282 }
283 delete[] info;
284 delete[] ids;
285 }
286
287 virtual Collator* createCollator(const Locale& loc) {
288 const CollatorInfo* ci = getInfo(loc);
289 if (ci) {
290 return ci->collator->clone();
291 }
292 return NULL;
293 }
294
295 virtual UnicodeString& getDisplayName(const Locale& objectLocale,
296 const Locale& displayLocale,
297 UnicodeString& result)
298 {
299 const CollatorInfo* ci = getInfo(objectLocale);
300 if (ci) {
301 ci->getDisplayName(displayLocale, result);
302 } else {
303 result.setToBogus();
304 }
305 return result;
306 }
307
308 const UnicodeString* getSupportedIDs(int32_t& _count, UErrorCode& status) {
309 if (U_SUCCESS(status)) {
310 if (!ids) {
311 ids = new UnicodeString[count];
312 if (!ids) {
313 status = U_MEMORY_ALLOCATION_ERROR;
314 _count = 0;
315 return NULL;
316 }
317
318 for (int i = 0; i < count; ++i) {
319 ids[i] = info[i]->locale.getName();
320 }
321 }
322
323 _count = count;
324 return ids;
325 }
326 return NULL;
327 }
328
329 virtual inline UClassID getDynamicClassID() const {
330 return (UClassID)&gClassID;
331 }
332
333 static UClassID getStaticClassID() {
334 return (UClassID)&gClassID;
335 }
336
337 private:
338 static char gClassID;
339 };
340
341 char TestFactory::gClassID = 0;
342 #endif
343
344 void CollationServiceTest::TestRegisterFactory(void)
345 {
346 #if !UCONFIG_NO_SERVICE
347 int32_t n1, n2, n3;
348 Locale fu_FU("fu", "FU", "");
349 Locale fu_FU_FOO("fu", "FU", "FOO");
350
351 UErrorCode status = U_ZERO_ERROR;
352
353 Hashtable* fuFUNames = new Hashtable(FALSE, status);
354 if (!fuFUNames) {
355 errln("memory allocation error");
356 return;
357 }
358 fuFUNames->setValueDeleter(uprv_deleteUObject);
359
360 fuFUNames->put(fu_FU.getName(), new UnicodeString("ze leetle bunny Fu-Fu"), status);
361 fuFUNames->put(fu_FU_FOO.getName(), new UnicodeString("zee leetel bunny Foo-Foo"), status);
362 fuFUNames->put(Locale::getDefault().getName(), new UnicodeString("little bunny Foo Foo"), status);
363
364 Collator* frcol = Collator::createInstance(Locale::getFrance(), status);
365 Collator* gecol = Collator::createInstance(Locale::getGermany(), status);
366 Collator* jpcol = Collator::createInstance(Locale::getJapan(), status);
367 if(U_FAILURE(status)) {
368 errcheckln(status, "Failed to create collators with %s", u_errorName(status));
369 delete frcol;
370 delete gecol;
371 delete jpcol;
372 delete fuFUNames;
373 return;
374 }
375
376 CollatorInfo** info = new CollatorInfo*[4];
377 if (!info) {
378 errln("memory allocation error");
379 return;
380 }
381
382 info[0] = new CollatorInfo(Locale::getUS(), frcol, NULL);
383 info[1] = new CollatorInfo(Locale::getFrance(), gecol, NULL);
384 info[2] = new CollatorInfo(fu_FU, jpcol, fuFUNames);
385 info[3] = NULL;
386
387 TestFactory* factory = new TestFactory(info);
388 if (!factory) {
389 errln("memory allocation error");
390 return;
391 }
392
393 Collator* uscol = Collator::createInstance(Locale::getUS(), status);
394 Collator* fucol = Collator::createInstance(fu_FU, status);
395
396 {
397 n1 = checkAvailable("before registerFactory");
398
399 URegistryKey key = Collator::registerFactory(factory, status);
400
401 n2 = checkAvailable("after registerFactory");
402 assertTrue("count after > count before", n2 > n1);
403
404 Collator* ncol = Collator::createInstance(Locale::getUS(), status);
405 if (*frcol != *ncol) {
406 errln("frcoll for en_US failed");
407 }
408 delete ncol; ncol = NULL;
409
410 ncol = Collator::createInstance(fu_FU_FOO, status);
411 if (*jpcol != *ncol) {
412 errln("jpcol for fu_FU_FOO failed");
413 }
414
415 // The requested locale may be the same as the valid locale,
416 // or may not be supported at all. See ticket #10477.
417 Locale loc = ncol->getLocale(ULOC_REQUESTED_LOCALE, status);
418 if (U_SUCCESS(status) && loc != fu_FU_FOO && loc != fu_FU) {
419 errln(UnicodeString("requested locale for fu_FU_FOO is not fu_FU_FOO nor fu_FU but ") + loc.getName());
420 }
421 status = U_ZERO_ERROR;
422 loc = ncol->getLocale(ULOC_VALID_LOCALE, status);
423 if (loc != fu_FU) {
424 errln(UnicodeString("valid locale for fu_FU_FOO is not fu_FU but ") + loc.getName());
425 }
426 delete ncol; ncol = NULL;
427
428 UnicodeString locName = fu_FU.getName();
429 StringEnumeration* localeEnum = Collator::getAvailableLocales();
430 UBool found = FALSE;
431 const UnicodeString* locStr;
432 for (locStr = localeEnum->snext(status);
433 !found && locStr != NULL;
434 locStr = localeEnum->snext(status))
435 {
436 if (locName == *locStr) {
437 found = TRUE;
438 }
439 }
440 delete localeEnum;
441
442 if (!found) {
443 errln("new locale fu_FU not reported as supported locale");
444 }
445
446 UnicodeString name;
447 Collator::getDisplayName(fu_FU, name);
448 if (name != "little bunny Foo Foo") {
449 errln(UnicodeString("found ") + name + " for fu_FU");
450 }
451
452 Collator::getDisplayName(fu_FU, fu_FU_FOO, name);
453 if (name != "zee leetel bunny Foo-Foo") {
454 errln(UnicodeString("found ") + name + " for fu_FU in fu_FU_FOO");
455 }
456
457 if (!Collator::unregister(key, status)) {
458 errln("failed to unregister factory");
459 }
460 // ja, fr, ge collators no longer valid
461
462 ncol = Collator::createInstance(fu_FU, status);
463 if (*fucol != *ncol) {
464 errln("collator after unregister does not match original fu_FU");
465 }
466 delete ncol;
467
468 n3 = checkAvailable("after unregister");
469 assertTrue("count after unregister == count before register", n3 == n1);
470 }
471
472 delete fucol;
473 delete uscol;
474 #endif
475 }
476
477 /**
478 * Iterate through the given iterator, checking to see that all the strings
479 * in the expected array are present.
480 * @param expected array of strings we expect to see, or NULL
481 * @param expectedCount number of elements of expected, or 0
482 */
483 int32_t CollationServiceTest::checkStringEnumeration(const char* msg,
484 StringEnumeration& iter,
485 const char** expected,
486 int32_t expectedCount) {
487 UErrorCode ec = U_ZERO_ERROR;
488 U_ASSERT(expectedCount >= 0 && expectedCount < 31); // [sic] 31 not 32
489 int32_t i = 0, idxAfterReset = 0, n = iter.count(ec);
490 assertSuccess("count", ec);
491 UnicodeString buf, buffAfterReset;
492 int32_t seenMask = 0;
493 for (;; ++i) {
494 const UnicodeString* s = iter.snext(ec);
495 if (!assertSuccess("snext", ec) || s == NULL)
496 break;
497 if (i != 0)
498 buf.append(UNICODE_STRING_SIMPLE(", "));
499 buf.append(*s);
500 // check expected list
501 for (int32_t j=0, bit=1; j<expectedCount; ++j, bit<<=1) {
502 if ((seenMask&bit)==0) {
503 UnicodeString exp(expected[j], (char*)NULL);
504 if (*s == exp) {
505 seenMask |= bit;
506 logln((UnicodeString)"Ok: \"" + exp + "\" seen");
507 }
508 }
509 }
510 }
511 // can't get pesky operator+(const US&, foo) to cooperate; use toString
512 #if !UCONFIG_NO_FORMATTING
513 logln(UnicodeString() + msg + " = [" + buf + "] (" + toString(i) + ")");
514 #else
515 logln(UnicodeString() + msg + " = [" + buf + "] (??? NO_FORMATTING)");
516 #endif
517 assertTrue("count verified", i==n);
518 iter.reset(ec);
519 for (;; ++idxAfterReset) {
520 const UChar *s = iter.unext(NULL, ec);
521 if (!assertSuccess("unext", ec) || s == NULL)
522 break;
523 if (idxAfterReset != 0)
524 buffAfterReset.append(UNICODE_STRING_SIMPLE(", "));
525 buffAfterReset.append(s);
526 }
527 assertTrue("idxAfterReset verified", idxAfterReset==n);
528 assertTrue("buffAfterReset verified", buffAfterReset==buf);
529 // did we see all expected strings?
530 if (((1<<expectedCount)-1) != seenMask) {
531 for (int32_t j=0, bit=1; j<expectedCount; ++j, bit<<=1) {
532 if ((seenMask&bit)==0) {
533 errln((UnicodeString)"FAIL: \"" + expected[j] + "\" not seen");
534 }
535 }
536 }
537 return n;
538 }
539
540 /**
541 * Check the integrity of the results of Collator::getAvailableLocales().
542 * Return the number of items returned.
543 */
544 #if !UCONFIG_NO_SERVICE
545 int32_t CollationServiceTest::checkAvailable(const char* msg) {
546 StringEnumeration *iter = Collator::getAvailableLocales();
547 if (!assertTrue("getAvailableLocales != NULL", iter!=NULL)) return -1;
548 int32_t n = checkStringEnumeration(msg, *iter, NULL, 0);
549 delete iter;
550 return n;
551 }
552 #endif
553
554 static const char* KW[] = {
555 "collation"
556 };
557 static const int32_t KW_COUNT = UPRV_LENGTHOF(KW);
558
559 static const char* KWVAL[] = {
560 "phonebook",
561 "stroke"
562 };
563 static const int32_t KWVAL_COUNT = UPRV_LENGTHOF(KWVAL);
564
565 void CollationServiceTest::TestSeparateTree() {
566 UErrorCode ec = U_ZERO_ERROR;
567 StringEnumeration *iter = Collator::getKeywords(ec);
568 if (!assertTrue("getKeywords != NULL", iter!=NULL)) return;
569 if (!assertSuccess("getKeywords", ec)) return;
570 checkStringEnumeration("getKeywords", *iter, KW, KW_COUNT);
571 delete iter;
572
573 iter = Collator::getKeywordValues(KW[0], ec);
574 if (!assertTrue("getKeywordValues != NULL", iter!=NULL, FALSE, TRUE)) return;
575 if (!assertSuccess("getKeywordValues", ec)) return;
576 checkStringEnumeration("getKeywordValues", *iter, KWVAL, KWVAL_COUNT);
577 delete iter;
578
579 UBool isAvailable;
580 Locale equiv = Collator::getFunctionalEquivalent("collation",
581 Locale::createFromName("de"),
582 isAvailable, ec);
583 assertSuccess("getFunctionalEquivalent", ec);
584 assertEquals("getFunctionalEquivalent(de)", "root", equiv.getName());
585 assertTrue("getFunctionalEquivalent(de).isAvailable==TRUE",
586 isAvailable == TRUE);
587
588 equiv = Collator::getFunctionalEquivalent("collation",
589 Locale::createFromName("de_DE"),
590 isAvailable, ec);
591 assertSuccess("getFunctionalEquivalent", ec);
592 assertEquals("getFunctionalEquivalent(de_DE)", "root", equiv.getName());
593 assertTrue("getFunctionalEquivalent(de_DE).isAvailable==FALSE",
594 isAvailable == FALSE);
595
596 equiv = Collator::getFunctionalEquivalent("collation",
597 Locale::createFromName("sv"),
598 isAvailable, ec);
599 assertSuccess("getFunctionalEquivalent", ec);
600 assertEquals("getFunctionalEquivalent(sv)", "sv", equiv.getName());
601 assertTrue("getFunctionalEquivalent(sv).isAvailable==TRUE",
602 isAvailable == TRUE);
603
604 equiv = Collator::getFunctionalEquivalent("collation",
605 Locale::createFromName("sv_SE"),
606 isAvailable, ec);
607 assertSuccess("getFunctionalEquivalent", ec);
608 assertEquals("getFunctionalEquivalent(sv_SE)", "sv", equiv.getName());
609 assertTrue("getFunctionalEquivalent(sv_SE).isAvailable==FALSE",
610 isAvailable == FALSE);
611 }
612
613 #endif