2 *******************************************************************************
3 * Copyright (C) 2003-2006, 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 errln("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 UCollator
* 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 if (displayName
!= "fu (FU)") {
156 errln(UnicodeString("found ") + displayName
+ " for fu_FU");
159 Collator::getDisplayName(fu_FU
, fu_FU
, displayName
);
160 if (displayName
!= "fu (FU)") {
161 errln(UnicodeString("found ") + displayName
+ " for fu_FU");
165 UCollator
* fufu
= ucol_open("fu_FU_FOO", &status
);
167 errln("could not open fu_FU_FOO with ucol_open");
169 if (!ucol_equals(fufu
, frFR
)) {
170 errln("collator fufu != collator frFR");
174 if (!Collator::unregister(key
, status
)) {
175 errln("failed to unregister french collator");
177 // !!! note frcoll invalid again, but we're no longer using it
179 // other collators should still work ok
180 Locale nloc
= ncol
->getLocale(ULOC_VALID_LOCALE
, status
);
182 errln(UnicodeString("asked for nloc valid locale after close and got") + nloc
.getName());
184 delete ncol
; ncol
= NULL
;
187 const char* nlocstr
= ucol_getLocale(fufu
, 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
);
195 ncol
= Collator::createInstance(fu_FU
, status
);
196 if (*fucol
!= *ncol
) {
197 errln("collator after unregister does not match original fu_FU");
199 delete uscol
; uscol
= NULL
;
200 delete ncol
; ncol
= NULL
;
201 delete fucol
; fucol
= NULL
;
206 // ------------------
208 #if !UCONFIG_NO_SERVICE
209 struct CollatorInfo
{
212 Hashtable
* displayNames
; // locale name -> string
214 CollatorInfo(const Locale
& locale
, Collator
* collatorToAdopt
, Hashtable
* displayNamesToAdopt
);
216 UnicodeString
& getDisplayName(const Locale
& displayLocale
, UnicodeString
& name
) const;
219 CollatorInfo::CollatorInfo(const Locale
& _locale
, Collator
* _collator
, Hashtable
* _displayNames
)
221 , collator(_collator
)
222 , displayNames(_displayNames
)
226 CollatorInfo::~CollatorInfo() {
232 CollatorInfo::getDisplayName(const Locale
& displayLocale
, UnicodeString
& name
) const {
234 UnicodeString
* val
= (UnicodeString
*)displayNames
->get(displayLocale
.getName());
241 return locale
.getDisplayName(displayLocale
, name
);
246 class TestFactory
: public CollatorFactory
{
251 const CollatorInfo
* getInfo(const Locale
& loc
) const {
252 for (CollatorInfo
** p
= info
; *p
; ++p
) {
253 if (loc
== (**p
).locale
) {
261 TestFactory(CollatorInfo
** _info
)
267 for (p
= info
; *p
; ++p
) {}
268 count
= (int32_t)(p
- info
);
272 for (CollatorInfo
** p
= info
; *p
; ++p
) {
279 virtual Collator
* createCollator(const Locale
& loc
) {
280 const CollatorInfo
* ci
= getInfo(loc
);
282 return ci
->collator
->clone();
287 virtual UnicodeString
& getDisplayName(const Locale
& objectLocale
,
288 const Locale
& displayLocale
,
289 UnicodeString
& result
)
291 const CollatorInfo
* ci
= getInfo(objectLocale
);
293 ci
->getDisplayName(displayLocale
, result
);
300 const UnicodeString
* getSupportedIDs(int32_t& _count
, UErrorCode
& status
) {
301 if (U_SUCCESS(status
)) {
303 ids
= new UnicodeString
[count
];
305 status
= U_MEMORY_ALLOCATION_ERROR
;
310 for (int i
= 0; i
< count
; ++i
) {
311 ids
[i
] = info
[i
]->locale
.getName();
321 virtual inline UClassID
getDynamicClassID() const {
322 return (UClassID
)&gClassID
;
325 static UClassID
getStaticClassID() {
326 return (UClassID
)&gClassID
;
330 static char gClassID
;
333 char TestFactory::gClassID
= 0;
336 void CollationServiceTest::TestRegisterFactory(void)
338 #if !UCONFIG_NO_SERVICE
340 Locale
fu_FU("fu", "FU", "");
341 Locale
fu_FU_FOO("fu", "FU", "FOO");
343 UErrorCode status
= U_ZERO_ERROR
;
345 Hashtable
* fuFUNames
= new Hashtable(FALSE
, status
);
347 errln("memory allocation error");
350 fuFUNames
->setValueDeleter(uhash_deleteUnicodeString
);
352 fuFUNames
->put(fu_FU
.getName(), new UnicodeString("ze leetle bunny Fu-Fu"), status
);
353 fuFUNames
->put(fu_FU_FOO
.getName(), new UnicodeString("zee leetel bunny Foo-Foo"), status
);
354 fuFUNames
->put(Locale::getDefault().getName(), new UnicodeString("little bunny Foo Foo"), status
);
356 Collator
* frcol
= Collator::createInstance(Locale::getFrance(), status
);
357 Collator
* gecol
= Collator::createInstance(Locale::getGermany(), status
);
358 Collator
* jpcol
= Collator::createInstance(Locale::getJapan(), status
);
359 if(U_FAILURE(status
)) {
360 errln("Failed to create collators with %s", u_errorName(status
));
368 CollatorInfo
** info
= new CollatorInfo
*[4];
370 errln("memory allocation error");
374 info
[0] = new CollatorInfo(Locale::getUS(), frcol
, NULL
);
375 info
[1] = new CollatorInfo(Locale::getFrance(), gecol
, NULL
);
376 info
[2] = new CollatorInfo(fu_FU
, jpcol
, fuFUNames
);
379 TestFactory
* factory
= new TestFactory(info
);
381 errln("memory allocation error");
385 Collator
* uscol
= Collator::createInstance(Locale::getUS(), status
);
386 Collator
* fucol
= Collator::createInstance(fu_FU
, status
);
389 n1
= checkAvailable("before registerFactory");
391 URegistryKey key
= Collator::registerFactory(factory
, status
);
393 n2
= checkAvailable("after registerFactory");
394 assertTrue("count after > count before", n2
> n1
);
396 Collator
* ncol
= Collator::createInstance(Locale::getUS(), status
);
397 if (*frcol
!= *ncol
) {
398 errln("frcoll for en_US failed");
400 delete ncol
; ncol
= NULL
;
402 ncol
= Collator::createInstance(fu_FU_FOO
, status
);
403 if (*jpcol
!= *ncol
) {
404 errln("jpcol for fu_FU_FOO failed");
407 Locale loc
= ncol
->getLocale(ULOC_REQUESTED_LOCALE
, status
);
408 if (loc
!= fu_FU_FOO
) {
409 errln(UnicodeString("requested locale for fu_FU_FOO is not fu_FU_FOO but ") + loc
.getName());
411 loc
= ncol
->getLocale(ULOC_VALID_LOCALE
, status
);
413 errln(UnicodeString("valid locale for fu_FU_FOO is not fu_FU but ") + loc
.getName());
415 delete ncol
; ncol
= NULL
;
417 UnicodeString locName
= fu_FU
.getName();
418 StringEnumeration
* localeEnum
= Collator::getAvailableLocales();
420 const UnicodeString
* locStr
;
421 for (locStr
= localeEnum
->snext(status
);
422 !found
&& locStr
!= NULL
;
423 locStr
= localeEnum
->snext(status
))
425 if (locName
== *locStr
) {
432 errln("new locale fu_FU not reported as supported locale");
436 Collator::getDisplayName(fu_FU
, name
);
437 if (name
!= "little bunny Foo Foo") {
438 errln(UnicodeString("found ") + name
+ " for fu_FU");
441 Collator::getDisplayName(fu_FU
, fu_FU_FOO
, name
);
442 if (name
!= "zee leetel bunny Foo-Foo") {
443 errln(UnicodeString("found ") + name
+ " for fu_FU in fu_FU_FOO");
446 if (!Collator::unregister(key
, status
)) {
447 errln("failed to unregister factory");
449 // ja, fr, ge collators no longer valid
451 ncol
= Collator::createInstance(fu_FU
, status
);
452 if (*fucol
!= *ncol
) {
453 errln("collator after unregister does not match original fu_FU");
457 n3
= checkAvailable("after unregister");
458 assertTrue("count after unregister == count before register", n3
== n1
);
467 * Iterate through the given iterator, checking to see that all the strings
468 * in the expected array are present.
469 * @param expected array of strings we expect to see, or NULL
470 * @param expectedCount number of elements of expected, or 0
472 int32_t CollationServiceTest::checkStringEnumeration(const char* msg
,
473 StringEnumeration
& iter
,
474 const char** expected
,
475 int32_t expectedCount
) {
476 UErrorCode ec
= U_ZERO_ERROR
;
477 U_ASSERT(expectedCount
>= 0 && expectedCount
< 31); // [sic] 31 not 32
478 int32_t i
= 0, idxAfterReset
= 0, n
= iter
.count(ec
);
479 assertSuccess("count", ec
);
480 UnicodeString buf
, buffAfterReset
;
481 int32_t seenMask
= 0;
483 const UnicodeString
* s
= iter
.snext(ec
);
484 if (!assertSuccess("snext", ec
) || s
== NULL
)
487 buf
.append(UNICODE_STRING_SIMPLE(", "));
489 // check expected list
490 for (int32_t j
=0, bit
=1; j
<expectedCount
; ++j
, bit
<<=1) {
491 if ((seenMask
&bit
)==0) {
492 UnicodeString
exp(expected
[j
], (char*)NULL
);
495 logln((UnicodeString
)"Ok: \"" + exp
+ "\" seen");
500 // can't get pesky operator+(const US&, foo) to cooperate; use toString
501 #if !UCONFIG_NO_FORMATTING
502 logln(UnicodeString() + msg
+ " = [" + buf
+ "] (" + toString(i
) + ")");
504 logln(UnicodeString() + msg
+ " = [" + buf
+ "] (??? NO_FORMATTING)");
506 assertTrue("count verified", i
==n
);
508 for (;; ++idxAfterReset
) {
509 const UChar
*s
= iter
.unext(NULL
, ec
);
510 if (!assertSuccess("unext", ec
) || s
== NULL
)
512 if (idxAfterReset
!= 0)
513 buffAfterReset
.append(UNICODE_STRING_SIMPLE(", "));
514 buffAfterReset
.append(s
);
516 assertTrue("idxAfterReset verified", idxAfterReset
==n
);
517 assertTrue("buffAfterReset verified", buffAfterReset
==buf
);
518 // did we see all expected strings?
519 if (((1<<expectedCount
)-1) != seenMask
) {
520 for (int32_t j
=0, bit
=1; j
<expectedCount
; ++j
, bit
<<=1) {
521 if ((seenMask
&bit
)==0) {
522 errln((UnicodeString
)"FAIL: \"" + expected
[j
] + "\" not seen");
530 * Check the integrity of the results of Collator::getAvailableLocales().
531 * Return the number of items returned.
533 #if !UCONFIG_NO_SERVICE
534 int32_t CollationServiceTest::checkAvailable(const char* msg
) {
535 StringEnumeration
*iter
= Collator::getAvailableLocales();
536 if (!assertTrue("getAvailableLocales != NULL", iter
!=NULL
)) return -1;
537 int32_t n
= checkStringEnumeration(msg
, *iter
, NULL
, 0);
543 static const char* KW
[] = {
546 static const int32_t KW_COUNT
= sizeof(KW
)/sizeof(KW
[0]);
548 static const char* KWVAL
[] = {
552 static const int32_t KWVAL_COUNT
= sizeof(KWVAL
)/sizeof(KWVAL
[0]);
554 void CollationServiceTest::TestSeparateTree() {
555 UErrorCode ec
= U_ZERO_ERROR
;
556 StringEnumeration
*iter
= Collator::getKeywords(ec
);
557 if (!assertTrue("getKeywords != NULL", iter
!=NULL
)) return;
558 if (!assertSuccess("getKeywords", ec
)) return;
559 checkStringEnumeration("getKeywords", *iter
, KW
, KW_COUNT
);
562 iter
= Collator::getKeywordValues(KW
[0], ec
);
563 if (!assertTrue("getKeywordValues != NULL", iter
!=NULL
)) return;
564 if (!assertSuccess("getKeywordValues", ec
)) return;
565 checkStringEnumeration("getKeywordValues", *iter
, KWVAL
, KWVAL_COUNT
);
569 Locale equiv
= Collator::getFunctionalEquivalent("collation",
570 Locale::createFromName("fr"),
572 assertSuccess("getFunctionalEquivalent", ec
);
573 assertEquals("getFunctionalEquivalent(fr)", "fr", equiv
.getName());
574 assertTrue("getFunctionalEquivalent(fr).isAvailable==TRUE",
575 isAvailable
== TRUE
);
577 equiv
= Collator::getFunctionalEquivalent("collation",
578 Locale::createFromName("fr_FR"),
580 assertSuccess("getFunctionalEquivalent", ec
);
581 assertEquals("getFunctionalEquivalent(fr_FR)", "fr", equiv
.getName());
582 assertTrue("getFunctionalEquivalent(fr_FR).isAvailable==TRUE",
583 isAvailable
== TRUE
);