2 *******************************************************************************
3 * Copyright (C) 2003-2016, 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"
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 Collator
*clone
= frcol
->clone();
53 URegistryKey key
= Collator::registerInstance(frcol
, US
, status
);
54 // frcol has been adopted. We must not use it any more, nor rely on its attributes.
57 Collator
* ncol
= Collator::createInstance(US_FOO
, status
);
58 if (*clone
!= *ncol
) {
59 errln("register of french collator for en_US failed on request for en_US_FOO");
63 // The requested locale may be the same as the valid locale,
64 // or may not be supported at all. See ticket #10477.
65 Locale loc
= ncol
->getLocale(ULOC_REQUESTED_LOCALE
, status
);
66 if (U_SUCCESS(status
) && loc
!= US_FOO
&& loc
!= US
) {
67 errln(UnicodeString("requested locale for en_US_FOO is not en_US_FOO nor en_US but ") + loc
.getName());
69 status
= U_ZERO_ERROR
;
70 loc
= ncol
->getLocale(ULOC_VALID_LOCALE
, status
);
72 errln(UnicodeString("valid locale for en_US_FOO is not en_US but ") + loc
.getName());
74 loc
= ncol
->getLocale(ULOC_ACTUAL_LOCALE
, status
);
76 errln(UnicodeString("actual locale for en_US_FOO is not en_US but ") + loc
.getName());
78 delete ncol
; ncol
= NULL
;
80 if (!Collator::unregister(key
, status
)) {
81 errln("failed to unregister french collator");
84 ncol
= Collator::createInstance(US
, status
);
85 if (*uscol
!= *ncol
) {
86 errln("collator after unregister does not match original");
88 delete ncol
; ncol
= NULL
;
92 frcol
= Collator::createInstance(FR
, status
);
94 LocalUCollatorPointer
frFR(ucol_open("fr_FR", &status
));
96 { // try create collator for new locale
97 Locale
fu_FU_FOO("fu", "FU", "FOO");
98 Locale
fu_FU("fu", "FU", "");
100 Collator
* fucol
= Collator::createInstance(fu_FU
, status
);
101 Collator
*clone
= frcol
->clone();
102 URegistryKey key
= Collator::registerInstance(frcol
, fu_FU
, status
);
103 frcol
= NULL
; // frcol has been adopted.
104 Collator
* ncol
= Collator::createInstance(fu_FU_FOO
, status
);
105 if (*clone
!= *ncol
) {
106 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 (*Collator::fromUCollator(fufu
.getAlias()) !=
178 *Collator::fromUCollator(frFR
.getAlias())) {
179 errln("collator fufu != collator frFR");
183 if (!Collator::unregister(key
, status
)) {
184 errln("failed to unregister french collator");
186 // !!! note frcoll invalid again, but we're no longer using it
188 // other collators should still work ok
189 Locale nloc
= ncol
->getLocale(ULOC_VALID_LOCALE
, status
);
191 errln(UnicodeString("asked for nloc valid locale after close and got") + nloc
.getName());
193 delete ncol
; ncol
= NULL
;
195 if (fufu
.isValid()) {
196 const char* nlocstr
= ucol_getLocaleByType(fufu
.getAlias(), ULOC_VALID_LOCALE
, &status
);
197 if (uprv_strcmp(nlocstr
, "fu_FU") != 0) {
198 errln(UnicodeString("asked for uloc valid locale after close and got ") + nlocstr
);
202 ncol
= Collator::createInstance(fu_FU
, status
);
203 if (*fucol
!= *ncol
) {
204 errln("collator after unregister does not match original fu_FU");
206 delete uscol
; uscol
= NULL
;
207 delete ncol
; ncol
= NULL
;
208 delete fucol
; fucol
= NULL
;
213 // ------------------
215 #if !UCONFIG_NO_SERVICE
216 struct CollatorInfo
{
219 Hashtable
* displayNames
; // locale name -> string
221 CollatorInfo(const Locale
& locale
, Collator
* collatorToAdopt
, Hashtable
* displayNamesToAdopt
);
223 UnicodeString
& getDisplayName(const Locale
& displayLocale
, UnicodeString
& name
) const;
226 CollatorInfo::CollatorInfo(const Locale
& _locale
, Collator
* _collator
, Hashtable
* _displayNames
)
228 , collator(_collator
)
229 , displayNames(_displayNames
)
231 collator
->setLocales(locale
, locale
, locale
);
234 CollatorInfo::~CollatorInfo() {
240 CollatorInfo::getDisplayName(const Locale
& displayLocale
, UnicodeString
& name
) const {
242 UnicodeString
* val
= (UnicodeString
*)displayNames
->get(displayLocale
.getName());
249 return locale
.getDisplayName(displayLocale
, name
);
254 class TestFactory
: public CollatorFactory
{
259 const CollatorInfo
* getInfo(const Locale
& loc
) const {
260 for (CollatorInfo
** p
= info
; *p
; ++p
) {
261 if (loc
== (**p
).locale
) {
269 TestFactory(CollatorInfo
** _info
)
275 for (p
= info
; *p
; ++p
) {}
276 count
= (int32_t)(p
- info
);
280 for (CollatorInfo
** p
= info
; *p
; ++p
) {
287 virtual Collator
* createCollator(const Locale
& loc
) {
288 const CollatorInfo
* ci
= getInfo(loc
);
290 return ci
->collator
->clone();
295 virtual UnicodeString
& getDisplayName(const Locale
& objectLocale
,
296 const Locale
& displayLocale
,
297 UnicodeString
& result
)
299 const CollatorInfo
* ci
= getInfo(objectLocale
);
301 ci
->getDisplayName(displayLocale
, result
);
308 const UnicodeString
* getSupportedIDs(int32_t& _count
, UErrorCode
& status
) {
309 if (U_SUCCESS(status
)) {
311 ids
= new UnicodeString
[count
];
313 status
= U_MEMORY_ALLOCATION_ERROR
;
318 for (int i
= 0; i
< count
; ++i
) {
319 ids
[i
] = info
[i
]->locale
.getName();
329 virtual inline UClassID
getDynamicClassID() const {
330 return (UClassID
)&gClassID
;
333 static UClassID
getStaticClassID() {
334 return (UClassID
)&gClassID
;
338 static char gClassID
;
341 char TestFactory::gClassID
= 0;
344 void CollationServiceTest::TestRegisterFactory(void)
346 #if !UCONFIG_NO_SERVICE
348 Locale
fu_FU("fu", "FU", "");
349 Locale
fu_FU_FOO("fu", "FU", "FOO");
351 UErrorCode status
= U_ZERO_ERROR
;
353 Hashtable
* fuFUNames
= new Hashtable(FALSE
, status
);
355 errln("memory allocation error");
358 fuFUNames
->setValueDeleter(uprv_deleteUObject
);
360 fuFUNames
->put(fu_FU
.getName(), new UnicodeString("ze leetle bunny Fu-Fu"), status
);
361 fuFUNames
->put(fu_FU_FOO
.getName(), new UnicodeString("zee leetel bunny Foo-Foo"), status
);
362 fuFUNames
->put(Locale::getDefault().getName(), new UnicodeString("little bunny Foo Foo"), status
);
364 Collator
* frcol
= Collator::createInstance(Locale::getFrance(), status
);
365 Collator
* gecol
= Collator::createInstance(Locale::getGermany(), status
);
366 Collator
* jpcol
= Collator::createInstance(Locale::getJapan(), status
);
367 if(U_FAILURE(status
)) {
368 errcheckln(status
, "Failed to create collators with %s", u_errorName(status
));
376 CollatorInfo
** info
= new CollatorInfo
*[4];
378 errln("memory allocation error");
382 info
[0] = new CollatorInfo(Locale::getUS(), frcol
, NULL
);
383 info
[1] = new CollatorInfo(Locale::getFrance(), gecol
, NULL
);
384 info
[2] = new CollatorInfo(fu_FU
, jpcol
, fuFUNames
);
387 TestFactory
* factory
= new TestFactory(info
);
389 errln("memory allocation error");
393 Collator
* uscol
= Collator::createInstance(Locale::getUS(), status
);
394 Collator
* fucol
= Collator::createInstance(fu_FU
, status
);
397 n1
= checkAvailable("before registerFactory");
399 URegistryKey key
= Collator::registerFactory(factory
, status
);
401 n2
= checkAvailable("after registerFactory");
402 assertTrue("count after > count before", n2
> n1
);
404 Collator
* ncol
= Collator::createInstance(Locale::getUS(), status
);
405 if (*frcol
!= *ncol
) {
406 errln("frcoll for en_US failed");
408 delete ncol
; ncol
= NULL
;
410 ncol
= Collator::createInstance(fu_FU_FOO
, status
);
411 if (*jpcol
!= *ncol
) {
412 errln("jpcol for fu_FU_FOO failed");
415 // The requested locale may be the same as the valid locale,
416 // or may not be supported at all. See ticket #10477.
417 Locale loc
= ncol
->getLocale(ULOC_REQUESTED_LOCALE
, status
);
418 if (U_SUCCESS(status
) && loc
!= fu_FU_FOO
&& loc
!= fu_FU
) {
419 errln(UnicodeString("requested locale for fu_FU_FOO is not fu_FU_FOO nor fu_FU but ") + loc
.getName());
421 status
= U_ZERO_ERROR
;
422 loc
= ncol
->getLocale(ULOC_VALID_LOCALE
, status
);
424 errln(UnicodeString("valid locale for fu_FU_FOO is not fu_FU but ") + loc
.getName());
426 delete ncol
; ncol
= NULL
;
428 UnicodeString locName
= fu_FU
.getName();
429 StringEnumeration
* localeEnum
= Collator::getAvailableLocales();
431 const UnicodeString
* locStr
;
432 for (locStr
= localeEnum
->snext(status
);
433 !found
&& locStr
!= NULL
;
434 locStr
= localeEnum
->snext(status
))
436 if (locName
== *locStr
) {
443 errln("new locale fu_FU not reported as supported locale");
447 Collator::getDisplayName(fu_FU
, name
);
448 if (name
!= "little bunny Foo Foo") {
449 errln(UnicodeString("found ") + name
+ " for fu_FU");
452 Collator::getDisplayName(fu_FU
, fu_FU_FOO
, name
);
453 if (name
!= "zee leetel bunny Foo-Foo") {
454 errln(UnicodeString("found ") + name
+ " for fu_FU in fu_FU_FOO");
457 if (!Collator::unregister(key
, status
)) {
458 errln("failed to unregister factory");
460 // ja, fr, ge collators no longer valid
462 ncol
= Collator::createInstance(fu_FU
, status
);
463 if (*fucol
!= *ncol
) {
464 errln("collator after unregister does not match original fu_FU");
468 n3
= checkAvailable("after unregister");
469 assertTrue("count after unregister == count before register", n3
== n1
);
478 * Iterate through the given iterator, checking to see that all the strings
479 * in the expected array are present.
480 * @param expected array of strings we expect to see, or NULL
481 * @param expectedCount number of elements of expected, or 0
483 int32_t CollationServiceTest::checkStringEnumeration(const char* msg
,
484 StringEnumeration
& iter
,
485 const char** expected
,
486 int32_t expectedCount
) {
487 UErrorCode ec
= U_ZERO_ERROR
;
488 U_ASSERT(expectedCount
>= 0 && expectedCount
< 31); // [sic] 31 not 32
489 int32_t i
= 0, idxAfterReset
= 0, n
= iter
.count(ec
);
490 assertSuccess("count", ec
);
491 UnicodeString buf
, buffAfterReset
;
492 int32_t seenMask
= 0;
494 const UnicodeString
* s
= iter
.snext(ec
);
495 if (!assertSuccess("snext", ec
) || s
== NULL
)
498 buf
.append(UNICODE_STRING_SIMPLE(", "));
500 // check expected list
501 for (int32_t j
=0, bit
=1; j
<expectedCount
; ++j
, bit
<<=1) {
502 if ((seenMask
&bit
)==0) {
503 UnicodeString
exp(expected
[j
], (char*)NULL
);
506 logln((UnicodeString
)"Ok: \"" + exp
+ "\" seen");
511 // can't get pesky operator+(const US&, foo) to cooperate; use toString
512 #if !UCONFIG_NO_FORMATTING
513 logln(UnicodeString() + msg
+ " = [" + buf
+ "] (" + toString(i
) + ")");
515 logln(UnicodeString() + msg
+ " = [" + buf
+ "] (??? NO_FORMATTING)");
517 assertTrue("count verified", i
==n
);
519 for (;; ++idxAfterReset
) {
520 const UChar
*s
= iter
.unext(NULL
, ec
);
521 if (!assertSuccess("unext", ec
) || s
== NULL
)
523 if (idxAfterReset
!= 0)
524 buffAfterReset
.append(UNICODE_STRING_SIMPLE(", "));
525 buffAfterReset
.append(s
);
527 assertTrue("idxAfterReset verified", idxAfterReset
==n
);
528 assertTrue("buffAfterReset verified", buffAfterReset
==buf
);
529 // did we see all expected strings?
530 if (((1<<expectedCount
)-1) != seenMask
) {
531 for (int32_t j
=0, bit
=1; j
<expectedCount
; ++j
, bit
<<=1) {
532 if ((seenMask
&bit
)==0) {
533 errln((UnicodeString
)"FAIL: \"" + expected
[j
] + "\" not seen");
541 * Check the integrity of the results of Collator::getAvailableLocales().
542 * Return the number of items returned.
544 #if !UCONFIG_NO_SERVICE
545 int32_t CollationServiceTest::checkAvailable(const char* msg
) {
546 StringEnumeration
*iter
= Collator::getAvailableLocales();
547 if (!assertTrue("getAvailableLocales != NULL", iter
!=NULL
)) return -1;
548 int32_t n
= checkStringEnumeration(msg
, *iter
, NULL
, 0);
554 static const char* KW
[] = {
557 static const int32_t KW_COUNT
= UPRV_LENGTHOF(KW
);
559 static const char* KWVAL
[] = {
563 static const int32_t KWVAL_COUNT
= UPRV_LENGTHOF(KWVAL
);
565 void CollationServiceTest::TestSeparateTree() {
566 UErrorCode ec
= U_ZERO_ERROR
;
567 StringEnumeration
*iter
= Collator::getKeywords(ec
);
568 if (!assertTrue("getKeywords != NULL", iter
!=NULL
)) return;
569 if (!assertSuccess("getKeywords", ec
)) return;
570 checkStringEnumeration("getKeywords", *iter
, KW
, KW_COUNT
);
573 iter
= Collator::getKeywordValues(KW
[0], ec
);
574 if (!assertTrue("getKeywordValues != NULL", iter
!=NULL
, FALSE
, TRUE
)) return;
575 if (!assertSuccess("getKeywordValues", ec
)) return;
576 checkStringEnumeration("getKeywordValues", *iter
, KWVAL
, KWVAL_COUNT
);
580 Locale equiv
= Collator::getFunctionalEquivalent("collation",
581 Locale::createFromName("de"),
583 assertSuccess("getFunctionalEquivalent", ec
);
584 assertEquals("getFunctionalEquivalent(de)", "root", equiv
.getName());
585 assertTrue("getFunctionalEquivalent(de).isAvailable==TRUE",
586 isAvailable
== TRUE
);
588 equiv
= Collator::getFunctionalEquivalent("collation",
589 Locale::createFromName("de_DE"),
591 assertSuccess("getFunctionalEquivalent", ec
);
592 assertEquals("getFunctionalEquivalent(de_DE)", "root", equiv
.getName());
593 assertTrue("getFunctionalEquivalent(de_DE).isAvailable==FALSE",
594 isAvailable
== FALSE
);
596 equiv
= Collator::getFunctionalEquivalent("collation",
597 Locale::createFromName("sv"),
599 assertSuccess("getFunctionalEquivalent", ec
);
600 assertEquals("getFunctionalEquivalent(sv)", "sv", equiv
.getName());
601 assertTrue("getFunctionalEquivalent(sv).isAvailable==TRUE",
602 isAvailable
== TRUE
);
604 equiv
= Collator::getFunctionalEquivalent("collation",
605 Locale::createFromName("sv_SE"),
607 assertSuccess("getFunctionalEquivalent", ec
);
608 assertEquals("getFunctionalEquivalent(sv_SE)", "sv", equiv
.getName());
609 assertTrue("getFunctionalEquivalent(sv_SE).isAvailable==FALSE",
610 isAvailable
== FALSE
);