2 *******************************************************************************
3 * Copyright (C) 2003-2014, 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 "cstring.h" // internal api used to compare locale strings
20 void CollationServiceTest::runIndexedTest(int32_t index
, UBool exec
, const char* &name
, char* /*par */)
22 if (exec
) logln("TestSuite CollationServiceTest: ");
24 TESTCASE(0, TestRegister
);
25 TESTCASE(1, TestRegisterFactory
);
26 TESTCASE(2, TestSeparateTree
);
27 default: name
= ""; break;
31 void CollationServiceTest::TestRegister()
33 #if !UCONFIG_NO_SERVICE
34 // register a singleton
35 const Locale
& FR
= Locale::getFrance();
36 const Locale
& US
= Locale::getUS();
37 const Locale
US_FOO("en", "US", "FOO");
39 UErrorCode status
= U_ZERO_ERROR
;
41 Collator
* frcol
= Collator::createInstance(FR
, status
);
42 Collator
* uscol
= Collator::createInstance(US
, status
);
43 if(U_FAILURE(status
)) {
44 errcheckln(status
, "Failed to create collators with %s", u_errorName(status
));
50 { // try override en_US collator
51 Collator
*clone
= frcol
->clone();
52 URegistryKey key
= Collator::registerInstance(frcol
, US
, status
);
53 // frcol has been adopted. We must not use it any more, nor rely on its attributes.
56 Collator
* ncol
= Collator::createInstance(US_FOO
, status
);
57 if (*clone
!= *ncol
) {
58 errln("register of french collator for en_US failed on request for en_US_FOO");
62 // The requested locale may be the same as the valid locale,
63 // or may not be supported at all. See ticket #10477.
64 Locale loc
= ncol
->getLocale(ULOC_REQUESTED_LOCALE
, status
);
65 if (U_SUCCESS(status
) && loc
!= US_FOO
&& loc
!= US
) {
66 errln(UnicodeString("requested locale for en_US_FOO is not en_US_FOO nor en_US but ") + loc
.getName());
68 status
= U_ZERO_ERROR
;
69 loc
= ncol
->getLocale(ULOC_VALID_LOCALE
, status
);
71 errln(UnicodeString("valid locale for en_US_FOO is not en_US but ") + loc
.getName());
73 loc
= ncol
->getLocale(ULOC_ACTUAL_LOCALE
, status
);
75 errln(UnicodeString("actual locale for en_US_FOO is not en_US but ") + loc
.getName());
77 delete ncol
; ncol
= NULL
;
79 if (!Collator::unregister(key
, status
)) {
80 errln("failed to unregister french collator");
83 ncol
= Collator::createInstance(US
, status
);
84 if (*uscol
!= *ncol
) {
85 errln("collator after unregister does not match original");
87 delete ncol
; ncol
= NULL
;
91 frcol
= Collator::createInstance(FR
, status
);
93 LocalUCollatorPointer
frFR(ucol_open("fr_FR", &status
));
95 { // try create collator for new locale
96 Locale
fu_FU_FOO("fu", "FU", "FOO");
97 Locale
fu_FU("fu", "FU", "");
99 Collator
* fucol
= Collator::createInstance(fu_FU
, status
);
100 Collator
*clone
= frcol
->clone();
101 URegistryKey key
= Collator::registerInstance(frcol
, fu_FU
, status
);
102 frcol
= NULL
; // frcol has been adopted.
103 Collator
* ncol
= Collator::createInstance(fu_FU_FOO
, status
);
104 if (*clone
!= *ncol
) {
105 errln("register of fr collator for fu_FU failed");
109 UnicodeString locName
= fu_FU
.getName();
110 StringEnumeration
* localeEnum
= Collator::getAvailableLocales();
112 const UnicodeString
* locStr
, *ls2
;
113 for (locStr
= localeEnum
->snext(status
);
114 !found
&& locStr
!= NULL
;
115 locStr
= localeEnum
->snext(status
)) {
117 if (locName
== *locStr
) {
122 StringEnumeration
*le2
= NULL
;
123 localeEnum
->reset(status
);
125 count
= localeEnum
->count(status
);
126 for(i
= 0; i
< count
; ++i
) {
128 le2
= localeEnum
->clone();
129 if(le2
== NULL
|| count
!= le2
->count(status
)) {
130 errln("ServiceEnumeration.clone() failed");
135 locStr
= localeEnum
->snext(status
);
136 ls2
= le2
->snext(status
);
137 if(*locStr
!= *ls2
) {
138 errln("ServiceEnumeration.clone() failed for item %d", i
);
141 localeEnum
->snext(status
);
149 errln("new locale fu_FU not reported as supported locale");
152 UnicodeString displayName
;
153 Collator::getDisplayName(fu_FU
, displayName
);
154 /* The locale display pattern for the locale ja, ko, and zh are different. */
155 const UChar zh_fuFU_Array
[] = { 0x0066, 0x0075, 0xff08, 0x0046, 0x0055, 0xff09, 0 };
156 const UnicodeString
zh_fuFU(zh_fuFU_Array
);
157 const Locale
& defaultLocale
= Locale::getDefault();
158 if (displayName
!= "fu (FU)" &&
159 ((defaultLocale
== Locale::getKorean() && defaultLocale
== Locale::getJapanese()) && displayName
== "fu(FU)") &&
160 ((defaultLocale
== Locale::getChinese()) && displayName
!= zh_fuFU
)) {
161 errln(UnicodeString("found ") + displayName
+ " for fu_FU");
164 Collator::getDisplayName(fu_FU
, fu_FU
, displayName
);
165 if (displayName
!= "fu (FU)" &&
166 ((defaultLocale
== Locale::getKorean() && defaultLocale
== Locale::getJapanese()) && displayName
== "fu(FU)") &&
167 ((defaultLocale
== Locale::getChinese()) && displayName
!= zh_fuFU
)) {
168 errln(UnicodeString("found ") + displayName
+ " for fu_FU");
172 LocalUCollatorPointer
fufu(ucol_open("fu_FU_FOO", &status
));
174 errln("could not open fu_FU_FOO with ucol_open");
176 if (*Collator::fromUCollator(fufu
.getAlias()) !=
177 *Collator::fromUCollator(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
)
230 collator
->setLocales(locale
, locale
, locale
);
233 CollatorInfo::~CollatorInfo() {
239 CollatorInfo::getDisplayName(const Locale
& displayLocale
, UnicodeString
& name
) const {
241 UnicodeString
* val
= (UnicodeString
*)displayNames
->get(displayLocale
.getName());
248 return locale
.getDisplayName(displayLocale
, name
);
253 class TestFactory
: public CollatorFactory
{
258 const CollatorInfo
* getInfo(const Locale
& loc
) const {
259 for (CollatorInfo
** p
= info
; *p
; ++p
) {
260 if (loc
== (**p
).locale
) {
268 TestFactory(CollatorInfo
** _info
)
274 for (p
= info
; *p
; ++p
) {}
275 count
= (int32_t)(p
- info
);
279 for (CollatorInfo
** p
= info
; *p
; ++p
) {
286 virtual Collator
* createCollator(const Locale
& loc
) {
287 const CollatorInfo
* ci
= getInfo(loc
);
289 return ci
->collator
->clone();
294 virtual UnicodeString
& getDisplayName(const Locale
& objectLocale
,
295 const Locale
& displayLocale
,
296 UnicodeString
& result
)
298 const CollatorInfo
* ci
= getInfo(objectLocale
);
300 ci
->getDisplayName(displayLocale
, result
);
307 const UnicodeString
* getSupportedIDs(int32_t& _count
, UErrorCode
& status
) {
308 if (U_SUCCESS(status
)) {
310 ids
= new UnicodeString
[count
];
312 status
= U_MEMORY_ALLOCATION_ERROR
;
317 for (int i
= 0; i
< count
; ++i
) {
318 ids
[i
] = info
[i
]->locale
.getName();
328 virtual inline UClassID
getDynamicClassID() const {
329 return (UClassID
)&gClassID
;
332 static UClassID
getStaticClassID() {
333 return (UClassID
)&gClassID
;
337 static char gClassID
;
340 char TestFactory::gClassID
= 0;
343 void CollationServiceTest::TestRegisterFactory(void)
345 #if !UCONFIG_NO_SERVICE
347 Locale
fu_FU("fu", "FU", "");
348 Locale
fu_FU_FOO("fu", "FU", "FOO");
350 UErrorCode status
= U_ZERO_ERROR
;
352 Hashtable
* fuFUNames
= new Hashtable(FALSE
, status
);
354 errln("memory allocation error");
357 fuFUNames
->setValueDeleter(uprv_deleteUObject
);
359 fuFUNames
->put(fu_FU
.getName(), new UnicodeString("ze leetle bunny Fu-Fu"), status
);
360 fuFUNames
->put(fu_FU_FOO
.getName(), new UnicodeString("zee leetel bunny Foo-Foo"), status
);
361 fuFUNames
->put(Locale::getDefault().getName(), new UnicodeString("little bunny Foo Foo"), status
);
363 Collator
* frcol
= Collator::createInstance(Locale::getFrance(), status
);
364 Collator
* gecol
= Collator::createInstance(Locale::getGermany(), status
);
365 Collator
* jpcol
= Collator::createInstance(Locale::getJapan(), status
);
366 if(U_FAILURE(status
)) {
367 errcheckln(status
, "Failed to create collators with %s", u_errorName(status
));
375 CollatorInfo
** info
= new CollatorInfo
*[4];
377 errln("memory allocation error");
381 info
[0] = new CollatorInfo(Locale::getUS(), frcol
, NULL
);
382 info
[1] = new CollatorInfo(Locale::getFrance(), gecol
, NULL
);
383 info
[2] = new CollatorInfo(fu_FU
, jpcol
, fuFUNames
);
386 TestFactory
* factory
= new TestFactory(info
);
388 errln("memory allocation error");
392 Collator
* uscol
= Collator::createInstance(Locale::getUS(), status
);
393 Collator
* fucol
= Collator::createInstance(fu_FU
, status
);
396 n1
= checkAvailable("before registerFactory");
398 URegistryKey key
= Collator::registerFactory(factory
, status
);
400 n2
= checkAvailable("after registerFactory");
401 assertTrue("count after > count before", n2
> n1
);
403 Collator
* ncol
= Collator::createInstance(Locale::getUS(), status
);
404 if (*frcol
!= *ncol
) {
405 errln("frcoll for en_US failed");
407 delete ncol
; ncol
= NULL
;
409 ncol
= Collator::createInstance(fu_FU_FOO
, status
);
410 if (*jpcol
!= *ncol
) {
411 errln("jpcol for fu_FU_FOO failed");
414 // The requested locale may be the same as the valid locale,
415 // or may not be supported at all. See ticket #10477.
416 Locale loc
= ncol
->getLocale(ULOC_REQUESTED_LOCALE
, status
);
417 if (U_SUCCESS(status
) && loc
!= fu_FU_FOO
&& loc
!= fu_FU
) {
418 errln(UnicodeString("requested locale for fu_FU_FOO is not fu_FU_FOO nor fu_FU but ") + loc
.getName());
420 status
= U_ZERO_ERROR
;
421 loc
= ncol
->getLocale(ULOC_VALID_LOCALE
, status
);
423 errln(UnicodeString("valid locale for fu_FU_FOO is not fu_FU but ") + loc
.getName());
425 delete ncol
; ncol
= NULL
;
427 UnicodeString locName
= fu_FU
.getName();
428 StringEnumeration
* localeEnum
= Collator::getAvailableLocales();
430 const UnicodeString
* locStr
;
431 for (locStr
= localeEnum
->snext(status
);
432 !found
&& locStr
!= NULL
;
433 locStr
= localeEnum
->snext(status
))
435 if (locName
== *locStr
) {
442 errln("new locale fu_FU not reported as supported locale");
446 Collator::getDisplayName(fu_FU
, name
);
447 if (name
!= "little bunny Foo Foo") {
448 errln(UnicodeString("found ") + name
+ " for fu_FU");
451 Collator::getDisplayName(fu_FU
, fu_FU_FOO
, name
);
452 if (name
!= "zee leetel bunny Foo-Foo") {
453 errln(UnicodeString("found ") + name
+ " for fu_FU in fu_FU_FOO");
456 if (!Collator::unregister(key
, status
)) {
457 errln("failed to unregister factory");
459 // ja, fr, ge collators no longer valid
461 ncol
= Collator::createInstance(fu_FU
, status
);
462 if (*fucol
!= *ncol
) {
463 errln("collator after unregister does not match original fu_FU");
467 n3
= checkAvailable("after unregister");
468 assertTrue("count after unregister == count before register", n3
== n1
);
477 * Iterate through the given iterator, checking to see that all the strings
478 * in the expected array are present.
479 * @param expected array of strings we expect to see, or NULL
480 * @param expectedCount number of elements of expected, or 0
482 int32_t CollationServiceTest::checkStringEnumeration(const char* msg
,
483 StringEnumeration
& iter
,
484 const char** expected
,
485 int32_t expectedCount
) {
486 UErrorCode ec
= U_ZERO_ERROR
;
487 U_ASSERT(expectedCount
>= 0 && expectedCount
< 31); // [sic] 31 not 32
488 int32_t i
= 0, idxAfterReset
= 0, n
= iter
.count(ec
);
489 assertSuccess("count", ec
);
490 UnicodeString buf
, buffAfterReset
;
491 int32_t seenMask
= 0;
493 const UnicodeString
* s
= iter
.snext(ec
);
494 if (!assertSuccess("snext", ec
) || s
== NULL
)
497 buf
.append(UNICODE_STRING_SIMPLE(", "));
499 // check expected list
500 for (int32_t j
=0, bit
=1; j
<expectedCount
; ++j
, bit
<<=1) {
501 if ((seenMask
&bit
)==0) {
502 UnicodeString
exp(expected
[j
], (char*)NULL
);
505 logln((UnicodeString
)"Ok: \"" + exp
+ "\" seen");
510 // can't get pesky operator+(const US&, foo) to cooperate; use toString
511 #if !UCONFIG_NO_FORMATTING
512 logln(UnicodeString() + msg
+ " = [" + buf
+ "] (" + toString(i
) + ")");
514 logln(UnicodeString() + msg
+ " = [" + buf
+ "] (??? NO_FORMATTING)");
516 assertTrue("count verified", i
==n
);
518 for (;; ++idxAfterReset
) {
519 const UChar
*s
= iter
.unext(NULL
, ec
);
520 if (!assertSuccess("unext", ec
) || s
== NULL
)
522 if (idxAfterReset
!= 0)
523 buffAfterReset
.append(UNICODE_STRING_SIMPLE(", "));
524 buffAfterReset
.append(s
);
526 assertTrue("idxAfterReset verified", idxAfterReset
==n
);
527 assertTrue("buffAfterReset verified", buffAfterReset
==buf
);
528 // did we see all expected strings?
529 if (((1<<expectedCount
)-1) != seenMask
) {
530 for (int32_t j
=0, bit
=1; j
<expectedCount
; ++j
, bit
<<=1) {
531 if ((seenMask
&bit
)==0) {
532 errln((UnicodeString
)"FAIL: \"" + expected
[j
] + "\" not seen");
540 * Check the integrity of the results of Collator::getAvailableLocales().
541 * Return the number of items returned.
543 #if !UCONFIG_NO_SERVICE
544 int32_t CollationServiceTest::checkAvailable(const char* msg
) {
545 StringEnumeration
*iter
= Collator::getAvailableLocales();
546 if (!assertTrue("getAvailableLocales != NULL", iter
!=NULL
)) return -1;
547 int32_t n
= checkStringEnumeration(msg
, *iter
, NULL
, 0);
553 static const char* KW
[] = {
556 static const int32_t KW_COUNT
= sizeof(KW
)/sizeof(KW
[0]);
558 static const char* KWVAL
[] = {
562 static const int32_t KWVAL_COUNT
= sizeof(KWVAL
)/sizeof(KWVAL
[0]);
564 void CollationServiceTest::TestSeparateTree() {
565 UErrorCode ec
= U_ZERO_ERROR
;
566 StringEnumeration
*iter
= Collator::getKeywords(ec
);
567 if (!assertTrue("getKeywords != NULL", iter
!=NULL
)) return;
568 if (!assertSuccess("getKeywords", ec
)) return;
569 checkStringEnumeration("getKeywords", *iter
, KW
, KW_COUNT
);
572 iter
= Collator::getKeywordValues(KW
[0], ec
);
573 if (!assertTrue("getKeywordValues != NULL", iter
!=NULL
, FALSE
, TRUE
)) return;
574 if (!assertSuccess("getKeywordValues", ec
)) return;
575 checkStringEnumeration("getKeywordValues", *iter
, KWVAL
, KWVAL_COUNT
);
579 Locale equiv
= Collator::getFunctionalEquivalent("collation",
580 Locale::createFromName("de"),
582 assertSuccess("getFunctionalEquivalent", ec
);
583 assertEquals("getFunctionalEquivalent(de)", "root", equiv
.getName());
584 assertTrue("getFunctionalEquivalent(de).isAvailable==TRUE",
585 isAvailable
== TRUE
);
587 equiv
= Collator::getFunctionalEquivalent("collation",
588 Locale::createFromName("de_DE"),
590 assertSuccess("getFunctionalEquivalent", ec
);
591 assertEquals("getFunctionalEquivalent(de_DE)", "root", equiv
.getName());
592 assertTrue("getFunctionalEquivalent(de_DE).isAvailable==FALSE",
593 isAvailable
== FALSE
);
595 equiv
= Collator::getFunctionalEquivalent("collation",
596 Locale::createFromName("sv"),
598 assertSuccess("getFunctionalEquivalent", ec
);
599 assertEquals("getFunctionalEquivalent(sv)", "sv", equiv
.getName());
600 assertTrue("getFunctionalEquivalent(sv).isAvailable==TRUE",
601 isAvailable
== TRUE
);
603 equiv
= Collator::getFunctionalEquivalent("collation",
604 Locale::createFromName("sv_SE"),
606 assertSuccess("getFunctionalEquivalent", ec
);
607 assertEquals("getFunctionalEquivalent(sv_SE)", "sv", equiv
.getName());
608 assertTrue("getFunctionalEquivalent(sv_SE).isAvailable==FALSE",
609 isAvailable
== FALSE
);