1/* 2 ******************************************************************************* 3 * Copyright (C) 2003-2013, 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 "hash.h" 16#include "uassert.h" 17 18#include "ucol_imp.h" // internal api needed to test ucollator equality 19#include "cstring.h" // internal api used to compare locale strings 20 21void 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 32void 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 URegistryKey key = Collator::registerInstance(frcol, US, status); 53 54 Collator* ncol = Collator::createInstance(US_FOO, status); 55 if (*frcol != *ncol) { 56 errln("register of french collator for en_US failed on request for en_US_FOO"); 57 } 58 // ensure original collator's params not touched 59 Locale loc = frcol->getLocale(ULOC_REQUESTED_LOCALE, status); 60 if (loc != FR) { 61 errln(UnicodeString("fr collator's requested locale changed to ") + loc.getName()); 62 } 63 loc = frcol->getLocale(ULOC_VALID_LOCALE, status); 64 if (loc != FR) { 65 errln(UnicodeString("fr collator's valid locale changed to ") + loc.getName()); 66 } 67 68 loc = ncol->getLocale(ULOC_REQUESTED_LOCALE, status); 69 if (loc != US_FOO) { 70 errln(UnicodeString("requested locale for en_US_FOO is not en_US_FOO but ") + loc.getName()); 71 } 72 loc = ncol->getLocale(ULOC_VALID_LOCALE, status); 73 if (loc != US) { 74 errln(UnicodeString("valid locale for en_US_FOO is not en_US but ") + loc.getName()); 75 } 76 loc = ncol->getLocale(ULOC_ACTUAL_LOCALE, status); 77 if (loc != US) { 78 errln(UnicodeString("actual locale for en_US_FOO is not en_US but ") + loc.getName()); 79 } 80 delete ncol; ncol = NULL; 81 82 if (!Collator::unregister(key, status)) { 83 errln("failed to unregister french collator"); 84 } 85 // !!! frcol pointer is now invalid !!! 86 87 ncol = Collator::createInstance(US, status); 88 if (*uscol != *ncol) { 89 errln("collator after unregister does not match original"); 90 } 91 delete ncol; ncol = NULL; 92 } 93 94 // recreate frcol 95 frcol = Collator::createInstance(FR, status); 96 97 LocalUCollatorPointer frFR(ucol_open("fr_FR", &status)); 98 99 { // try create collator for new locale 100 Locale fu_FU_FOO("fu", "FU", "FOO"); 101 Locale fu_FU("fu", "FU", ""); 102 103 Collator* fucol = Collator::createInstance(fu_FU, status); 104 URegistryKey key = Collator::registerInstance(frcol, fu_FU, status); 105 Collator* ncol = Collator::createInstance(fu_FU_FOO, status); 106 if (*frcol != *ncol) { 107 errln("register of fr collator for fu_FU failed"); 108 } 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 (!ucol_equals(fufu.getAlias(), frFR.getAlias())) { 178 errln("collator fufu != collator frFR"); 179 } 180 } 181 182 if (!Collator::unregister(key, status)) { 183 errln("failed to unregister french collator"); 184 } 185 // !!! note frcoll invalid again, but we're no longer using it 186 187 // other collators should still work ok 188 Locale nloc = ncol->getLocale(ULOC_VALID_LOCALE, status); 189 if (nloc != fu_FU) { 190 errln(UnicodeString("asked for nloc valid locale after close and got") + nloc.getName()); 191 } 192 delete ncol; ncol = NULL; 193 194 if (fufu.isValid()) { 195 const char* nlocstr = ucol_getLocaleByType(fufu.getAlias(), ULOC_VALID_LOCALE, &status); 196 if (uprv_strcmp(nlocstr, "fu_FU") != 0) { 197 errln(UnicodeString("asked for uloc valid locale after close and got ") + nlocstr); 198 } 199 } 200 201 ncol = Collator::createInstance(fu_FU, status); 202 if (*fucol != *ncol) { 203 errln("collator after unregister does not match original fu_FU"); 204 } 205 delete uscol; uscol = NULL; 206 delete ncol; ncol = NULL; 207 delete fucol; fucol = NULL; 208 } 209#endif 210} 211 212// ------------------ 213 214#if !UCONFIG_NO_SERVICE 215struct CollatorInfo { 216 Locale locale; 217 Collator* collator; 218 Hashtable* displayNames; // locale name -> string 219 220 CollatorInfo(const Locale& locale, Collator* collatorToAdopt, Hashtable* displayNamesToAdopt); 221 ~CollatorInfo(); 222 UnicodeString& getDisplayName(const Locale& displayLocale, UnicodeString& name) const; 223}; 224 225CollatorInfo::CollatorInfo(const Locale& _locale, Collator* _collator, Hashtable* _displayNames) 226 : locale(_locale) 227 , collator(_collator) 228 , displayNames(_displayNames) 229{ 230} 231 232CollatorInfo::~CollatorInfo() { 233 delete collator; 234 delete displayNames; 235} 236 237UnicodeString& 238CollatorInfo::getDisplayName(const Locale& displayLocale, UnicodeString& name) const { 239 if (displayNames) { 240 UnicodeString* val = (UnicodeString*)displayNames->get(displayLocale.getName()); 241 if (val) { 242 name = *val; 243 return name; 244 } 245 } 246 247 return locale.getDisplayName(displayLocale, name); 248} 249 250// --------------- 251 252class TestFactory : public CollatorFactory { 253 CollatorInfo** info; 254 int32_t count; 255 UnicodeString* ids; 256 257 const CollatorInfo* getInfo(const Locale& loc) const { 258 for (CollatorInfo** p = info; *p; ++p) { 259 if (loc == (**p).locale) { 260 return *p; 261 } 262 } 263 return NULL; 264 } 265 266public: 267 TestFactory(CollatorInfo** _info) 268 : info(_info) 269 , count(0) 270 , ids(NULL) 271 { 272 CollatorInfo** p; 273 for (p = info; *p; ++p) {} 274 count = (int32_t)(p - info); 275 } 276 277 ~TestFactory() { 278 for (CollatorInfo** p = info; *p; ++p) { 279 delete *p; 280 } 281 delete[] info; 282 delete[] ids; 283 } 284 285 virtual Collator* createCollator(const Locale& loc) { 286 const CollatorInfo* ci = getInfo(loc); 287 if (ci) { 288 return ci->collator->clone(); 289 } 290 return NULL; 291 } 292 293 virtual UnicodeString& getDisplayName(const Locale& objectLocale, 294 const Locale& displayLocale, 295 UnicodeString& result) 296 { 297 const CollatorInfo* ci = getInfo(objectLocale); 298 if (ci) { 299 ci->getDisplayName(displayLocale, result); 300 } else { 301 result.setToBogus(); 302 } 303 return result; 304 } 305 306 const UnicodeString* getSupportedIDs(int32_t& _count, UErrorCode& status) { 307 if (U_SUCCESS(status)) { 308 if (!ids) { 309 ids = new UnicodeString[count]; 310 if (!ids) { 311 status = U_MEMORY_ALLOCATION_ERROR; 312 _count = 0; 313 return NULL; 314 } 315 316 for (int i = 0; i < count; ++i) { 317 ids[i] = info[i]->locale.getName(); 318 } 319 } 320 321 _count = count; 322 return ids; 323 } 324 return NULL; 325 } 326 327 virtual inline UClassID getDynamicClassID() const { 328 return (UClassID)&gClassID; 329 } 330 331 static UClassID getStaticClassID() { 332 return (UClassID)&gClassID; 333 } 334 335private: 336 static char gClassID; 337}; 338 339char TestFactory::gClassID = 0; 340#endif 341 342void CollationServiceTest::TestRegisterFactory(void) 343{ 344#if !UCONFIG_NO_SERVICE 345 int32_t n1, n2, n3; 346 Locale fu_FU("fu", "FU", ""); 347 Locale fu_FU_FOO("fu", "FU", "FOO"); 348 349 UErrorCode status = U_ZERO_ERROR; 350 351 Hashtable* fuFUNames = new Hashtable(FALSE, status); 352 if (!fuFUNames) { 353 errln("memory allocation error"); 354 return; 355 } 356 fuFUNames->setValueDeleter(uprv_deleteUObject); 357 358 fuFUNames->put(fu_FU.getName(), new UnicodeString("ze leetle bunny Fu-Fu"), status); 359 fuFUNames->put(fu_FU_FOO.getName(), new UnicodeString("zee leetel bunny Foo-Foo"), status); 360 fuFUNames->put(Locale::getDefault().getName(), new UnicodeString("little bunny Foo Foo"), status); 361 362 Collator* frcol = Collator::createInstance(Locale::getFrance(), status); 363 Collator* gecol = Collator::createInstance(Locale::getGermany(), status); 364 Collator* jpcol = Collator::createInstance(Locale::getJapan(), status); 365 if(U_FAILURE(status)) { 366 errcheckln(status, "Failed to create collators with %s", u_errorName(status)); 367 delete frcol; 368 delete gecol; 369 delete jpcol; 370 delete fuFUNames; 371 return; 372 } 373 374 CollatorInfo** info = new CollatorInfo*[4]; 375 if (!info) { 376 errln("memory allocation error"); 377 return; 378 } 379 380 info[0] = new CollatorInfo(Locale::getUS(), frcol, NULL); 381 info[1] = new CollatorInfo(Locale::getFrance(), gecol, NULL); 382 info[2] = new CollatorInfo(fu_FU, jpcol, fuFUNames); 383 info[3] = NULL; 384 385 TestFactory* factory = new TestFactory(info); 386 if (!factory) { 387 errln("memory allocation error"); 388 return; 389 } 390 391 Collator* uscol = Collator::createInstance(Locale::getUS(), status); 392 Collator* fucol = Collator::createInstance(fu_FU, status); 393 394 { 395 n1 = checkAvailable("before registerFactory"); 396 397 URegistryKey key = Collator::registerFactory(factory, status); 398 399 n2 = checkAvailable("after registerFactory"); 400 assertTrue("count after > count before", n2 > n1); 401 402 Collator* ncol = Collator::createInstance(Locale::getUS(), status); 403 if (*frcol != *ncol) { 404 errln("frcoll for en_US failed"); 405 } 406 delete ncol; ncol = NULL; 407 408 ncol = Collator::createInstance(fu_FU_FOO, status); 409 if (*jpcol != *ncol) { 410 errln("jpcol for fu_FU_FOO failed"); 411 } 412 413 Locale loc = ncol->getLocale(ULOC_REQUESTED_LOCALE, status); 414 if (loc != fu_FU_FOO) { 415 errln(UnicodeString("requested locale for fu_FU_FOO is not fu_FU_FOO but ") + loc.getName()); 416 } 417 loc = ncol->getLocale(ULOC_VALID_LOCALE, status); 418 if (loc != fu_FU) { 419 errln(UnicodeString("valid locale for fu_FU_FOO is not fu_FU but ") + loc.getName()); 420 } 421 delete ncol; ncol = NULL; 422 423 UnicodeString locName = fu_FU.getName(); 424 StringEnumeration* localeEnum = Collator::getAvailableLocales(); 425 UBool found = FALSE; 426 const UnicodeString* locStr; 427 for (locStr = localeEnum->snext(status); 428 !found && locStr != NULL; 429 locStr = localeEnum->snext(status)) 430 { 431 if (locName == *locStr) { 432 found = TRUE; 433 } 434 } 435 delete localeEnum; 436 437 if (!found) { 438 errln("new locale fu_FU not reported as supported locale"); 439 } 440 441 UnicodeString name; 442 Collator::getDisplayName(fu_FU, name); 443 if (name != "little bunny Foo Foo") { 444 errln(UnicodeString("found ") + name + " for fu_FU"); 445 } 446 447 Collator::getDisplayName(fu_FU, fu_FU_FOO, name); 448 if (name != "zee leetel bunny Foo-Foo") { 449 errln(UnicodeString("found ") + name + " for fu_FU in fu_FU_FOO"); 450 } 451 452 if (!Collator::unregister(key, status)) { 453 errln("failed to unregister factory"); 454 } 455 // ja, fr, ge collators no longer valid 456 457 ncol = Collator::createInstance(fu_FU, status); 458 if (*fucol != *ncol) { 459 errln("collator after unregister does not match original fu_FU"); 460 } 461 delete ncol; 462 463 n3 = checkAvailable("after unregister"); 464 assertTrue("count after unregister == count before register", n3 == n1); 465 } 466 467 delete fucol; 468 delete uscol; 469#endif 470} 471 472/** 473 * Iterate through the given iterator, checking to see that all the strings 474 * in the expected array are present. 475 * @param expected array of strings we expect to see, or NULL 476 * @param expectedCount number of elements of expected, or 0 477 */ 478int32_t CollationServiceTest::checkStringEnumeration(const char* msg, 479 StringEnumeration& iter, 480 const char** expected, 481 int32_t expectedCount) { 482 UErrorCode ec = U_ZERO_ERROR; 483 U_ASSERT(expectedCount >= 0 && expectedCount < 31); // [sic] 31 not 32 484 int32_t i = 0, idxAfterReset = 0, n = iter.count(ec); 485 assertSuccess("count", ec); 486 UnicodeString buf, buffAfterReset; 487 int32_t seenMask = 0; 488 for (;; ++i) { 489 const UnicodeString* s = iter.snext(ec); 490 if (!assertSuccess("snext", ec) || s == NULL) 491 break; 492 if (i != 0) 493 buf.append(UNICODE_STRING_SIMPLE(", ")); 494 buf.append(*s); 495 // check expected list 496 for (int32_t j=0, bit=1; j<expectedCount; ++j, bit<<=1) { 497 if ((seenMask&bit)==0) { 498 UnicodeString exp(expected[j], (char*)NULL); 499 if (*s == exp) { 500 seenMask |= bit; 501 logln((UnicodeString)"Ok: \"" + exp + "\" seen"); 502 } 503 } 504 } 505 } 506 // can't get pesky operator+(const US&, foo) to cooperate; use toString 507#if !UCONFIG_NO_FORMATTING 508 logln(UnicodeString() + msg + " = [" + buf + "] (" + toString(i) + ")"); 509#else 510 logln(UnicodeString() + msg + " = [" + buf + "] (??? NO_FORMATTING)"); 511#endif 512 assertTrue("count verified", i==n); 513 iter.reset(ec); 514 for (;; ++idxAfterReset) { 515 const UChar *s = iter.unext(NULL, ec); 516 if (!assertSuccess("unext", ec) || s == NULL) 517 break; 518 if (idxAfterReset != 0) 519 buffAfterReset.append(UNICODE_STRING_SIMPLE(", ")); 520 buffAfterReset.append(s); 521 } 522 assertTrue("idxAfterReset verified", idxAfterReset==n); 523 assertTrue("buffAfterReset verified", buffAfterReset==buf); 524 // did we see all expected strings? 525 if (((1<<expectedCount)-1) != seenMask) { 526 for (int32_t j=0, bit=1; j<expectedCount; ++j, bit<<=1) { 527 if ((seenMask&bit)==0) { 528 errln((UnicodeString)"FAIL: \"" + expected[j] + "\" not seen"); 529 } 530 } 531 } 532 return n; 533} 534 535/** 536 * Check the integrity of the results of Collator::getAvailableLocales(). 537 * Return the number of items returned. 538 */ 539#if !UCONFIG_NO_SERVICE 540int32_t CollationServiceTest::checkAvailable(const char* msg) { 541 StringEnumeration *iter = Collator::getAvailableLocales(); 542 if (!assertTrue("getAvailableLocales != NULL", iter!=NULL)) return -1; 543 int32_t n = checkStringEnumeration(msg, *iter, NULL, 0); 544 delete iter; 545 return n; 546} 547#endif 548 549static const char* KW[] = { 550 "collation" 551}; 552static const int32_t KW_COUNT = sizeof(KW)/sizeof(KW[0]); 553 554static const char* KWVAL[] = { 555 "phonebook", 556 "stroke" 557}; 558static const int32_t KWVAL_COUNT = sizeof(KWVAL)/sizeof(KWVAL[0]); 559 560void CollationServiceTest::TestSeparateTree() { 561 UErrorCode ec = U_ZERO_ERROR; 562 StringEnumeration *iter = Collator::getKeywords(ec); 563 if (!assertTrue("getKeywords != NULL", iter!=NULL)) return; 564 if (!assertSuccess("getKeywords", ec)) return; 565 checkStringEnumeration("getKeywords", *iter, KW, KW_COUNT); 566 delete iter; 567 568 iter = Collator::getKeywordValues(KW[0], ec); 569 if (!assertTrue("getKeywordValues != NULL", iter!=NULL, FALSE, TRUE)) return; 570 if (!assertSuccess("getKeywordValues", ec)) return; 571 checkStringEnumeration("getKeywordValues", *iter, KWVAL, KWVAL_COUNT); 572 delete iter; 573 574 UBool isAvailable; 575 Locale equiv = Collator::getFunctionalEquivalent("collation", 576 Locale::createFromName("de"), 577 isAvailable, ec); 578 assertSuccess("getFunctionalEquivalent", ec); 579 assertEquals("getFunctionalEquivalent(de)", "root", equiv.getName()); 580 assertTrue("getFunctionalEquivalent(de).isAvailable==TRUE", 581 isAvailable == TRUE); 582 583 equiv = Collator::getFunctionalEquivalent("collation", 584 Locale::createFromName("de_DE"), 585 isAvailable, ec); 586 assertSuccess("getFunctionalEquivalent", ec); 587 assertEquals("getFunctionalEquivalent(de_DE)", "root", equiv.getName()); 588 assertTrue("getFunctionalEquivalent(de_DE).isAvailable==TRUE", 589 isAvailable == TRUE); 590 591 equiv = Collator::getFunctionalEquivalent("collation", 592 Locale::createFromName("sv"), 593 isAvailable, ec); 594 assertSuccess("getFunctionalEquivalent", ec); 595 assertEquals("getFunctionalEquivalent(sv)", "sv", equiv.getName()); 596 assertTrue("getFunctionalEquivalent(sv).isAvailable==TRUE", 597 isAvailable == TRUE); 598 599 equiv = Collator::getFunctionalEquivalent("collation", 600 Locale::createFromName("sv_SE"), 601 isAvailable, ec); 602 assertSuccess("getFunctionalEquivalent", ec); 603 assertEquals("getFunctionalEquivalent(sv_SE)", "sv", equiv.getName()); 604 assertTrue("getFunctionalEquivalent(sv_SE).isAvailable==TRUE", 605 isAvailable == TRUE); 606} 607 608#endif 609