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