2 *******************************************************************************
3 * Copyright (C) 2003-2011, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
8 #include "unicode/utypes.h"
10 #if !UCONFIG_NO_COLLATION
13 #include "unicode/coll.h"
14 #include "unicode/strenum.h"
18 #include "ucol_imp.h" // internal api needed to test ucollator equality
19 #include "cstring.h" // internal api used to compare locale strings
21 void CollationServiceTest::runIndexedTest(int32_t index
, UBool exec
, const char* &name
, char* /*par */)
23 if (exec
) logln("TestSuite CollationServiceTest: ");
25 TESTCASE(0, TestRegister
);
26 TESTCASE(1, TestRegisterFactory
);
27 TESTCASE(2, TestSeparateTree
);
28 default: name
= ""; break;
32 void CollationServiceTest::TestRegister()
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");
40 UErrorCode status
= U_ZERO_ERROR
;
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
));
51 { // try override en_US collator
52 URegistryKey key
= Collator::registerInstance(frcol
, US
, status
);
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");
58 // ensure original collator's params not touched
59 Locale loc
= frcol
->getLocale(ULOC_REQUESTED_LOCALE
, status
);
61 errln(UnicodeString("fr collator's requested locale changed to ") + loc
.getName());
63 loc
= frcol
->getLocale(ULOC_VALID_LOCALE
, status
);
65 errln(UnicodeString("fr collator's valid locale changed to ") + loc
.getName());
68 loc
= ncol
->getLocale(ULOC_REQUESTED_LOCALE
, status
);
70 errln(UnicodeString("requested locale for en_US_FOO is not en_US_FOO but ") + loc
.getName());
72 loc
= ncol
->getLocale(ULOC_VALID_LOCALE
, status
);
74 errln(UnicodeString("valid locale for en_US_FOO is not en_US but ") + loc
.getName());
76 loc
= ncol
->getLocale(ULOC_ACTUAL_LOCALE
, status
);
78 errln(UnicodeString("actual locale for en_US_FOO is not en_US but ") + loc
.getName());
80 delete ncol
; ncol
= NULL
;
82 if (!Collator::unregister(key
, status
)) {
83 errln("failed to unregister french collator");
85 // !!! frcol pointer is now invalid !!!
87 ncol
= Collator::createInstance(US
, status
);
88 if (*uscol
!= *ncol
) {
89 errln("collator after unregister does not match original");
91 delete ncol
; ncol
= NULL
;
95 frcol
= Collator::createInstance(FR
, status
);
97 LocalUCollatorPointer
frFR(ucol_open("fr_FR", &status
));
99 { // try create collator for new locale
100 Locale
fu_FU_FOO("fu", "FU", "FOO");
101 Locale
fu_FU("fu", "FU", "");
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");
110 UnicodeString locName
= fu_FU
.getName();
111 StringEnumeration
* localeEnum
= Collator::getAvailableLocales();
113 const UnicodeString
* locStr
, *ls2
;
114 for (locStr
= localeEnum
->snext(status
);
115 !found
&& locStr
!= NULL
;
116 locStr
= localeEnum
->snext(status
)) {
118 if (locName
== *locStr
) {
123 StringEnumeration
*le2
= NULL
;
124 localeEnum
->reset(status
);
126 count
= localeEnum
->count(status
);
127 for(i
= 0; i
< count
; ++i
) {
129 le2
= localeEnum
->clone();
130 if(le2
== NULL
|| count
!= le2
->count(status
)) {
131 errln("ServiceEnumeration.clone() failed");
136 locStr
= localeEnum
->snext(status
);
137 ls2
= le2
->snext(status
);
138 if(*locStr
!= *ls2
) {
139 errln("ServiceEnumeration.clone() failed for item %d", i
);
142 localeEnum
->snext(status
);
150 errln("new locale fu_FU not reported as supported locale");
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");
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");
173 LocalUCollatorPointer
fufu(ucol_open("fu_FU_FOO", &status
));
175 errln("could not open fu_FU_FOO with ucol_open");
177 if (!ucol_equals(fufu
.getAlias(), frFR
.getAlias())) {
178 errln("collator fufu != collator frFR");
182 if (!Collator::unregister(key
, status
)) {
183 errln("failed to unregister french collator");
185 // !!! note frcoll invalid again, but we're no longer using it
187 // other collators should still work ok
188 Locale nloc
= ncol
->getLocale(ULOC_VALID_LOCALE
, status
);
190 errln(UnicodeString("asked for nloc valid locale after close and got") + nloc
.getName());
192 delete ncol
; ncol
= NULL
;
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
);
201 ncol
= Collator::createInstance(fu_FU
, status
);
202 if (*fucol
!= *ncol
) {
203 errln("collator after unregister does not match original fu_FU");
205 delete uscol
; uscol
= NULL
;
206 delete ncol
; ncol
= NULL
;
207 delete fucol
; fucol
= NULL
;
212 // ------------------
214 #if !UCONFIG_NO_SERVICE
215 struct CollatorInfo
{
218 Hashtable
* displayNames
; // locale name -> string
220 CollatorInfo(const Locale
& locale
, Collator
* collatorToAdopt
, Hashtable
* displayNamesToAdopt
);
222 UnicodeString
& getDisplayName(const Locale
& displayLocale
, UnicodeString
& name
) const;
225 CollatorInfo::CollatorInfo(const Locale
& _locale
, Collator
* _collator
, Hashtable
* _displayNames
)
227 , collator(_collator
)
228 , displayNames(_displayNames
)
232 CollatorInfo::~CollatorInfo() {
238 CollatorInfo::getDisplayName(const Locale
& displayLocale
, UnicodeString
& name
) const {
240 UnicodeString
* val
= (UnicodeString
*)displayNames
->get(displayLocale
.getName());
247 return locale
.getDisplayName(displayLocale
, name
);
252 class TestFactory
: public CollatorFactory
{
257 const CollatorInfo
* getInfo(const Locale
& loc
) const {
258 for (CollatorInfo
** p
= info
; *p
; ++p
) {
259 if (loc
== (**p
).locale
) {
267 TestFactory(CollatorInfo
** _info
)
273 for (p
= info
; *p
; ++p
) {}
274 count
= (int32_t)(p
- info
);
278 for (CollatorInfo
** p
= info
; *p
; ++p
) {
285 virtual Collator
* createCollator(const Locale
& loc
) {
286 const CollatorInfo
* ci
= getInfo(loc
);
288 return ci
->collator
->clone();
293 virtual UnicodeString
& getDisplayName(const Locale
& objectLocale
,
294 const Locale
& displayLocale
,
295 UnicodeString
& result
)
297 const CollatorInfo
* ci
= getInfo(objectLocale
);
299 ci
->getDisplayName(displayLocale
, result
);
306 const UnicodeString
* getSupportedIDs(int32_t& _count
, UErrorCode
& status
) {
307 if (U_SUCCESS(status
)) {
309 ids
= new UnicodeString
[count
];
311 status
= U_MEMORY_ALLOCATION_ERROR
;
316 for (int i
= 0; i
< count
; ++i
) {
317 ids
[i
] = info
[i
]->locale
.getName();
327 virtual inline UClassID
getDynamicClassID() const {
328 return (UClassID
)&gClassID
;
331 static UClassID
getStaticClassID() {
332 return (UClassID
)&gClassID
;
336 static char gClassID
;
339 char TestFactory::gClassID
= 0;
342 void CollationServiceTest::TestRegisterFactory(void)
344 #if !UCONFIG_NO_SERVICE
346 Locale
fu_FU("fu", "FU", "");
347 Locale
fu_FU_FOO("fu", "FU", "FOO");
349 UErrorCode status
= U_ZERO_ERROR
;
351 Hashtable
* fuFUNames
= new Hashtable(FALSE
, status
);
353 errln("memory allocation error");
356 fuFUNames
->setValueDeleter(uprv_deleteUObject
);
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
);
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
));
374 CollatorInfo
** info
= new CollatorInfo
*[4];
376 errln("memory allocation error");
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
);
385 TestFactory
* factory
= new TestFactory(info
);
387 errln("memory allocation error");
391 Collator
* uscol
= Collator::createInstance(Locale::getUS(), status
);
392 Collator
* fucol
= Collator::createInstance(fu_FU
, status
);
395 n1
= checkAvailable("before registerFactory");
397 URegistryKey key
= Collator::registerFactory(factory
, status
);
399 n2
= checkAvailable("after registerFactory");
400 assertTrue("count after > count before", n2
> n1
);
402 Collator
* ncol
= Collator::createInstance(Locale::getUS(), status
);
403 if (*frcol
!= *ncol
) {
404 errln("frcoll for en_US failed");
406 delete ncol
; ncol
= NULL
;
408 ncol
= Collator::createInstance(fu_FU_FOO
, status
);
409 if (*jpcol
!= *ncol
) {
410 errln("jpcol for fu_FU_FOO failed");
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());
417 loc
= ncol
->getLocale(ULOC_VALID_LOCALE
, status
);
419 errln(UnicodeString("valid locale for fu_FU_FOO is not fu_FU but ") + loc
.getName());
421 delete ncol
; ncol
= NULL
;
423 UnicodeString locName
= fu_FU
.getName();
424 StringEnumeration
* localeEnum
= Collator::getAvailableLocales();
426 const UnicodeString
* locStr
;
427 for (locStr
= localeEnum
->snext(status
);
428 !found
&& locStr
!= NULL
;
429 locStr
= localeEnum
->snext(status
))
431 if (locName
== *locStr
) {
438 errln("new locale fu_FU not reported as supported locale");
442 Collator::getDisplayName(fu_FU
, name
);
443 if (name
!= "little bunny Foo Foo") {
444 errln(UnicodeString("found ") + name
+ " for fu_FU");
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");
452 if (!Collator::unregister(key
, status
)) {
453 errln("failed to unregister factory");
455 // ja, fr, ge collators no longer valid
457 ncol
= Collator::createInstance(fu_FU
, status
);
458 if (*fucol
!= *ncol
) {
459 errln("collator after unregister does not match original fu_FU");
463 n3
= checkAvailable("after unregister");
464 assertTrue("count after unregister == count before register", n3
== n1
);
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
478 int32_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;
489 const UnicodeString
* s
= iter
.snext(ec
);
490 if (!assertSuccess("snext", ec
) || s
== NULL
)
493 buf
.append(UNICODE_STRING_SIMPLE(", "));
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
);
501 logln((UnicodeString
)"Ok: \"" + exp
+ "\" seen");
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
) + ")");
510 logln(UnicodeString() + msg
+ " = [" + buf
+ "] (??? NO_FORMATTING)");
512 assertTrue("count verified", i
==n
);
514 for (;; ++idxAfterReset
) {
515 const UChar
*s
= iter
.unext(NULL
, ec
);
516 if (!assertSuccess("unext", ec
) || s
== NULL
)
518 if (idxAfterReset
!= 0)
519 buffAfterReset
.append(UNICODE_STRING_SIMPLE(", "));
520 buffAfterReset
.append(s
);
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");
536 * Check the integrity of the results of Collator::getAvailableLocales().
537 * Return the number of items returned.
539 #if !UCONFIG_NO_SERVICE
540 int32_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);
549 static const char* KW
[] = {
552 static const int32_t KW_COUNT
= sizeof(KW
)/sizeof(KW
[0]);
554 static const char* KWVAL
[] = {
558 static const int32_t KWVAL_COUNT
= sizeof(KWVAL
)/sizeof(KWVAL
[0]);
560 void 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
);
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
);
575 Locale equiv
= Collator::getFunctionalEquivalent("collation",
576 Locale::createFromName("de"),
578 assertSuccess("getFunctionalEquivalent", ec
);
579 assertEquals("getFunctionalEquivalent(de)", "de", equiv
.getName());
580 assertTrue("getFunctionalEquivalent(de).isAvailable==TRUE",
581 isAvailable
== TRUE
);
583 equiv
= Collator::getFunctionalEquivalent("collation",
584 Locale::createFromName("de_DE"),
586 assertSuccess("getFunctionalEquivalent", ec
);
587 assertEquals("getFunctionalEquivalent(de_DE)", "de", equiv
.getName());
588 assertTrue("getFunctionalEquivalent(de_DE).isAvailable==TRUE",
589 isAvailable
== TRUE
);