1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
5 * Copyright (C) 2001-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 *******************************************************************************
10 #include "utypeinfo.h" // for 'typeid' to work
12 #include "unicode/utypes.h"
14 #if !UCONFIG_NO_SERVICE
22 class MyListener
: public EventListener
{
25 class WrongListener
: public EventListener
{
28 class ICUNSubclass
: public ICUNotifier
{
30 UBool
acceptsListener(const EventListener
& /*l*/) const {
32 // return l instanceof MyListener;
35 virtual void notifyListener(EventListener
& /*l*/) const {
39 // This factory does nothing
40 class LKFSubclass0
: public LocaleKeyFactory
{
43 : LocaleKeyFactory(VISIBLE
, "LKFSubclass0")
48 class LKFSubclass
: public LocaleKeyFactory
{
52 LKFSubclass(UBool visible
)
53 : LocaleKeyFactory(visible
? VISIBLE
: INVISIBLE
, "LKFSubclass")
55 UErrorCode status
= U_ZERO_ERROR
;
56 table
.put("en_US", this, status
);
60 virtual const Hashtable
* getSupportedIDs(UErrorCode
&/*status*/) const {
65 class Integer
: public UObject
{
69 Integer(int32_t val
) : _val(val
) {
72 Integer(const Integer
& rhs
) : UObject(rhs
), _val(rhs
._val
) {
79 * UObject boilerplate.
81 static UClassID
getStaticClassID() {
82 return (UClassID
)&fgClassID
;
85 virtual UClassID
getDynamicClassID() const {
86 return getStaticClassID();
89 virtual UBool
operator==(const UObject
& other
) const
91 return typeid(*this) == typeid(other
) &&
92 _val
== ((Integer
&)other
)._val
;
96 virtual UnicodeString
& debug(UnicodeString
& result
) const {
98 result
.append(" val: ");
103 virtual UnicodeString
& debugClass(UnicodeString
& result
) const {
104 return result
.append("Integer");
108 static const char fgClassID
;
111 const char Integer::fgClassID
= '\0';
114 class TestIntegerService
: public ICUService
{
116 ICUServiceKey
* createKey(const UnicodeString
* id
, UErrorCode
& status
) const {
117 return LocaleKey::createWithCanonicalFallback(id
, NULL
, status
); // no fallback locale
120 virtual ICUServiceFactory
* createSimpleFactory(UObject
* obj
, const UnicodeString
& id
, UBool visible
, UErrorCode
& status
)
123 if (U_SUCCESS(status
) && obj
&& (i
= dynamic_cast<Integer
*>(obj
)) != NULL
) {
124 return new SimpleFactory(i
, id
, visible
);
129 virtual UObject
* cloneInstance(UObject
* instance
) const {
130 return instance
? new Integer(*(Integer
*)instance
) : NULL
;
135 ICUServiceTest::ICUServiceTest() {
138 ICUServiceTest::~ICUServiceTest() {
142 ICUServiceTest::runIndexedTest(int32_t index
, UBool exec
, const char* &name
,
146 TESTCASE(0,testAPI_One
);
147 TESTCASE(1,testAPI_Two
);
149 TESTCASE(3,testNotification
);
150 TESTCASE(4,testLocale
);
151 TESTCASE(5,testWrapFactory
);
152 TESTCASE(6,testCoverage
);
153 default: name
= ""; break;
157 UnicodeString
append(UnicodeString
& result
, const UObject
* obj
)
161 result
.append("NULL");
163 const UnicodeString
* s
;
166 if ((s
= dynamic_cast<const UnicodeString
*>(obj
)) != NULL
) {
168 } else if ((loc
= dynamic_cast<const Locale
*>(obj
)) != NULL
) {
169 result
.append(loc
->getName());
170 } else if ((i
= dynamic_cast<const Integer
*>(obj
)) != NULL
) {
171 sprintf(buffer
, "%d", (int)i
->_val
);
172 result
.append(buffer
);
174 sprintf(buffer
, "%p", (const void*)obj
);
175 result
.append(buffer
);
182 ICUServiceTest::lrmsg(UnicodeString
& result
, const UnicodeString
& message
, const UObject
* lhs
, const UObject
* rhs
) const
184 result
.append(message
);
185 result
.append(" lhs: ");
187 result
.append(", rhs: ");
193 ICUServiceTest::confirmBoolean(const UnicodeString
& message
, UBool val
)
204 ICUServiceTest::confirmEqual(const UnicodeString
& message
, const UObject
* lhs
, const UObject
* rhs
)
206 UBool equ
= (lhs
== NULL
)
208 : (rhs
!= NULL
&& lhs
->operator==(*rhs
));
211 lrmsg(temp
, message
, lhs
, rhs
);
221 ICUServiceTest::confirmEqual(const UnicodeString
& message
, const Integer
* lhs
, const Integer
* rhs
)
223 UBool equ
= (lhs
== NULL
)
225 : (rhs
!= NULL
&& lhs
->operator==(*rhs
));
228 lrmsg(temp
, message
, lhs
, rhs
);
238 ICUServiceTest::confirmEqual(const UnicodeString
& message
, const UnicodeString
* lhs
, const UnicodeString
* rhs
)
240 UBool equ
= (lhs
== NULL
)
242 : (rhs
!= NULL
&& lhs
->operator==(*rhs
));
245 lrmsg(temp
, message
, lhs
, rhs
);
255 ICUServiceTest::confirmEqual(const UnicodeString
& message
, const Locale
* lhs
, const Locale
* rhs
)
257 UBool equ
= (lhs
== NULL
)
259 : (rhs
!= NULL
&& lhs
->operator==(*rhs
));
262 lrmsg(temp
, message
, lhs
, rhs
);
274 ICUServiceTest::confirmStringsEqual(const UnicodeString
& message
, const UnicodeString
& lhs
, const UnicodeString
& rhs
)
276 UBool equ
= lhs
== rhs
;
278 UnicodeString temp
= message
;
279 temp
.append(" lhs: ");
281 temp
.append(" rhs: ");
293 ICUServiceTest::confirmIdentical(const UnicodeString
& message
, const UObject
* lhs
, const UObject
*rhs
)
296 lrmsg(temp
, message
, lhs
, rhs
);
305 ICUServiceTest::confirmIdentical(const UnicodeString
& message
, int32_t lhs
, int32_t rhs
)
308 logln(message
+ " lhs: " + lhs
+ " rhs: " + rhs
);
310 errln(message
+ " lhs: " + lhs
+ " rhs: " + rhs
);
315 ICUServiceTest::msgstr(const UnicodeString
& message
, UObject
* obj
, UBool err
)
318 UnicodeString
* str
= (UnicodeString
*)obj
;
319 logln(message
+ *str
);
322 errln("Error " + message
+ "string is NULL");
327 ICUServiceTest::testAPI_One()
329 // create a service using locale keys,
330 TestIntegerService service
;
332 // register an object with one locale,
333 // search for an object with a more specific locale
334 // should return the original object
335 UErrorCode status
= U_ZERO_ERROR
;
336 Integer
* singleton0
= new Integer(0);
337 service
.registerInstance(singleton0
, "en_US", status
);
339 UErrorCode status
= U_ZERO_ERROR
;
340 Integer
* result
= (Integer
*)service
.get("en_US_FOO", status
);
341 confirmEqual("1) en_US_FOO -> en_US", result
, singleton0
);
345 // register a new object with the more specific locale
346 // search for an object with that locale
347 // should return the new object
348 Integer
* singleton1
= new Integer(1);
349 service
.registerInstance(singleton1
, "en_US_FOO", status
);
351 UErrorCode status
= U_ZERO_ERROR
;
352 Integer
* result
= (Integer
*)service
.get("en_US_FOO", status
);
353 confirmEqual("2) en_US_FOO -> en_US_FOO", result
, singleton1
);
357 // search for an object that falls back to the first registered locale
359 UErrorCode status
= U_ZERO_ERROR
;
360 Integer
* result
= (Integer
*)service
.get("en_US_BAR", status
);
361 confirmEqual("3) en_US_BAR -> en_US", result
, singleton0
);
365 // get a list of the factories, should be two
367 confirmIdentical("4) factory size", service
.countFactories(), 2);
370 // register a new object with yet another locale
371 Integer
* singleton2
= new Integer(2);
372 service
.registerInstance(singleton2
, "en", status
);
374 confirmIdentical("5) factory size", service
.countFactories(), 3);
377 // search for an object with the new locale
378 // stack of factories is now en, en_US_FOO, en_US
379 // search for en_US should still find en_US object
381 UErrorCode status
= U_ZERO_ERROR
;
382 Integer
* result
= (Integer
*)service
.get("en_US_BAR", status
);
383 confirmEqual("6) en_US_BAR -> en_US", result
, singleton0
);
387 // register a new object with an old id, should hide earlier factory using this id, but leave it there
388 Integer
* singleton3
= new Integer(3);
389 URegistryKey s3key
= service
.registerInstance(singleton3
, "en_US", status
);
391 confirmIdentical("9) factory size", service
.countFactories(), 4);
394 // should get data from that new factory
396 UErrorCode status
= U_ZERO_ERROR
;
397 Integer
* result
= (Integer
*)service
.get("en_US_BAR", status
);
398 confirmEqual("10) en_US_BAR -> (3)", result
, singleton3
);
402 // remove new factory
403 // should have fewer factories again
406 UErrorCode status
= U_ZERO_ERROR
;
407 service
.unregister(s3key
, status
);
408 confirmIdentical("11) factory size", service
.countFactories(), 3);
411 // should get original data again after remove factory
413 UErrorCode status
= U_ZERO_ERROR
;
414 Integer
* result
= (Integer
*)service
.get("en_US_BAR", status
);
415 confirmEqual("12) en_US_BAR -> (3)", result
, singleton0
);
419 // shouldn't find unregistered ids
421 UErrorCode status
= U_ZERO_ERROR
;
422 Integer
* result
= (Integer
*)service
.get("foo", status
);
423 confirmIdentical("13) foo -> null", result
, NULL
);
427 // should find non-canonical strings
429 UnicodeString resultID
;
430 UErrorCode status
= U_ZERO_ERROR
;
431 Integer
* result
= (Integer
*)service
.get("EN_us_fOo", &resultID
, status
);
432 confirmEqual("14a) find-non-canonical", result
, singleton1
);
433 confirmStringsEqual("14b) find non-canonical", resultID
, "en_US_FOO");
437 // should be able to register non-canonical strings and get them canonicalized
438 Integer
* singleton4
= new Integer(4);
439 service
.registerInstance(singleton4
, "eN_ca_dUde", status
);
441 UnicodeString resultID
;
442 UErrorCode status
= U_ZERO_ERROR
;
443 Integer
* result
= (Integer
*)service
.get("En_Ca_DuDe", &resultID
, status
);
444 confirmEqual("15a) find-non-canonical", result
, singleton4
);
445 confirmStringsEqual("15b) register non-canonical", resultID
, "en_CA_DUDE");
449 // should be able to register invisible factories, these will not
450 // be visible by default, but if you know the secret password you
451 // can still access these services...
452 Integer
* singleton5
= new Integer(5);
453 service
.registerInstance(singleton5
, "en_US_BAR", FALSE
, status
);
455 UErrorCode status
= U_ZERO_ERROR
;
456 Integer
* result
= (Integer
*)service
.get("en_US_BAR", status
);
457 confirmEqual("17) get invisible", result
, singleton5
);
461 // should not be able to locate invisible services
463 UErrorCode status
= U_ZERO_ERROR
;
464 UVector
ids(uprv_deleteUObject
, uhash_compareUnicodeString
, status
);
465 service
.getVisibleIDs(ids
, status
);
466 UnicodeString target
= "en_US_BAR";
467 confirmBoolean("18) find invisible", !ids
.contains(&target
));
470 // clear factory and caches
472 confirmBoolean("19) is default", service
.isDefault());
476 ******************************************************************
478 class TestStringSimpleKeyService
: public ICUService
{
481 virtual ICUServiceFactory
* createSimpleFactory(UObject
* obj
, const UnicodeString
& id
, UBool visible
, UErrorCode
& status
)
483 // We could put this type check into ICUService itself, but we'd still
484 // have to implement cloneInstance. Otherwise we could just tell the service
485 // what the object type is when we create it, and the default implementation
486 // could handle everything for us. Phooey.
487 if (obj
&& dynamic_cast<UnicodeString
*>(obj
) != NULL
) {
488 return ICUService::createSimpleFactory(obj
, id
, visible
, status
);
493 virtual UObject
* cloneInstance(UObject
* instance
) const {
494 return instance
? new UnicodeString(*(UnicodeString
*)instance
) : NULL
;
498 class TestStringService
: public ICUService
{
500 ICUServiceKey
* createKey(const UnicodeString
* id
, UErrorCode
& status
) const {
501 return LocaleKey::createWithCanonicalFallback(id
, NULL
, status
); // no fallback locale
504 virtual ICUServiceFactory
* createSimpleFactory(UObject
* obj
, const UnicodeString
& id
, UBool visible
, UErrorCode
& /* status */)
507 if (obj
&& (s
= dynamic_cast<UnicodeString
*>(obj
)) != NULL
) {
508 return new SimpleFactory(s
, id
, visible
);
513 virtual UObject
* cloneInstance(UObject
* instance
) const {
514 return instance
? new UnicodeString(*(UnicodeString
*)instance
) : NULL
;
518 // this creates a string for any id, but doesn't report anything
519 class AnonymousStringFactory
: public ICUServiceFactory
522 virtual UObject
* create(const ICUServiceKey
& key
, const ICUService
* /* service */, UErrorCode
& /* status */) const {
523 return new UnicodeString(key
.getID());
526 virtual void updateVisibleIDs(Hashtable
& /*result*/, UErrorCode
& /*status*/) const {
530 virtual UnicodeString
& getDisplayName(const UnicodeString
& /*id*/, const Locale
& /*locale*/, UnicodeString
& result
) const {
535 static UClassID
getStaticClassID() {
536 return (UClassID
)&fgClassID
;
539 virtual UClassID
getDynamicClassID() const {
540 return getStaticClassID();
544 static const char fgClassID
;
547 const char AnonymousStringFactory::fgClassID
= '\0';
549 class TestMultipleKeyStringFactory
: public ICUServiceFactory
{
552 UnicodeString _factoryID
;
555 TestMultipleKeyStringFactory(const UnicodeString ids
[], int32_t count
, const UnicodeString
& factoryID
)
556 : _status(U_ZERO_ERROR
)
557 , _ids(uprv_deleteUObject
, uhash_compareUnicodeString
, count
, _status
)
558 , _factoryID(factoryID
+ ": ")
560 for (int i
= 0; i
< count
; ++i
) {
561 _ids
.addElement(new UnicodeString(ids
[i
]), _status
);
565 ~TestMultipleKeyStringFactory() {
568 UObject
* create(const ICUServiceKey
& key
, const ICUService
* /* service */, UErrorCode
& status
) const {
569 if (U_FAILURE(status
)) {
574 if (U_SUCCESS(_status
)) {
575 if (_ids
.contains(&temp
)) {
576 return new UnicodeString(_factoryID
+ temp
);
584 void updateVisibleIDs(Hashtable
& result
, UErrorCode
& status
) const {
585 if (U_SUCCESS(_status
)) {
586 for (int32_t i
= 0; i
< _ids
.size(); ++i
) {
587 result
.put(*(UnicodeString
*)_ids
[i
], (void*)this, status
);
592 UnicodeString
& getDisplayName(const UnicodeString
& id
, const Locale
& locale
, UnicodeString
& result
) const {
593 if (U_SUCCESS(_status
) && _ids
.contains((void*)&id
)) {
595 UErrorCode status
= U_ZERO_ERROR
;
596 int32_t len
= id
.extract(buffer
, sizeof(buffer
), NULL
, status
);
597 if (U_SUCCESS(status
)) {
598 if (len
== sizeof(buffer
)) {
602 Locale loc
= Locale::createFromName(buffer
);
603 loc
.getDisplayName(locale
, result
);
607 result
.setToBogus(); // shouldn't happen
611 static UClassID
getStaticClassID() {
612 return (UClassID
)&fgClassID
;
615 virtual UClassID
getDynamicClassID() const {
616 return getStaticClassID();
620 static const char fgClassID
;
623 const char TestMultipleKeyStringFactory::fgClassID
= '\0';
626 ICUServiceTest::testAPI_Two()
628 UErrorCode status
= U_ZERO_ERROR
;
629 TestStringService service
;
630 service
.registerFactory(new AnonymousStringFactory(), status
);
632 // anonymous factory will still handle the id
634 UErrorCode status
= U_ZERO_ERROR
;
635 const UnicodeString en_US
= "en_US";
636 UnicodeString
* result
= (UnicodeString
*)service
.get(en_US
, status
);
637 confirmEqual("21) locale", result
, &en_US
);
641 // still normalizes id
643 UErrorCode status
= U_ZERO_ERROR
;
644 const UnicodeString en_US_BAR
= "en_US_BAR";
645 UnicodeString resultID
;
646 UnicodeString
* result
= (UnicodeString
*)service
.get("EN_us_bar", &resultID
, status
);
647 confirmEqual("22) locale", &resultID
, &en_US_BAR
);
651 // we can override for particular ids
652 UnicodeString
* singleton0
= new UnicodeString("Zero");
653 service
.registerInstance(singleton0
, "en_US_BAR", status
);
655 UErrorCode status
= U_ZERO_ERROR
;
656 UnicodeString
* result
= (UnicodeString
*)service
.get("en_US_BAR", status
);
657 confirmEqual("23) override super", result
, singleton0
);
661 // empty service should not recognize anything
664 UErrorCode status
= U_ZERO_ERROR
;
665 UnicodeString
* result
= (UnicodeString
*)service
.get("en_US", status
);
666 confirmIdentical("24) empty", result
, NULL
);
669 // create a custom multiple key factory
671 UnicodeString xids
[] = {
677 int32_t count
= UPRV_LENGTHOF(xids
);
679 ICUServiceFactory
* f
= new TestMultipleKeyStringFactory(xids
, count
, "Later");
680 service
.registerFactory(f
, status
);
683 // iterate over the visual ids returned by the multiple factory
685 UErrorCode status
= U_ZERO_ERROR
;
686 UVector
ids(uprv_deleteUObject
, uhash_compareUnicodeString
, 0, status
);
687 service
.getVisibleIDs(ids
, status
);
688 for (int i
= 0; i
< ids
.size(); ++i
) {
689 const UnicodeString
* id
= (const UnicodeString
*)ids
[i
];
690 UnicodeString
* result
= (UnicodeString
*)service
.get(*id
, status
);
692 logln(" " + *id
+ " --> " + *result
);
695 errln("could not find " + *id
);
699 confirmIdentical("25) visible ids", ids
.size(), 4);
702 // iterate over the display names
704 UErrorCode status
= U_ZERO_ERROR
;
705 UVector
names(status
);
706 service
.getDisplayNames(names
, status
);
707 for (int i
= 0; i
< names
.size(); ++i
) {
708 const StringPair
* pair
= (const StringPair
*)names
[i
];
709 logln(" " + pair
->displayName
+ " --> " + pair
->id
);
711 confirmIdentical("26) display names", names
.size(), 4);
714 // no valid display name
717 service
.getDisplayName("en_US_VALLEY_GEEK", name
);
718 confirmBoolean("27) get display name", name
.isBogus());
723 service
.getDisplayName("en_US_SURFER_DUDE", name
, Locale::getEnglish());
724 confirmStringsEqual("28) get display name", name
, "English (United States, SURFER_DUDE)");
727 // register another multiple factory
729 UnicodeString xids
[] = {
733 "en_US_SILICON_GEEK",
735 int32_t count
= UPRV_LENGTHOF(xids
);
737 ICUServiceFactory
* f
= new TestMultipleKeyStringFactory(xids
, count
, "Rad dude");
738 service
.registerFactory(f
, status
);
741 // this time, we have seven display names
742 // Rad dude's surfer gal 'replaces' Later's surfer gal
744 UErrorCode status
= U_ZERO_ERROR
;
745 UVector
names(status
);
746 service
.getDisplayNames(names
, Locale("es"), status
);
747 for (int i
= 0; i
< names
.size(); ++i
) {
748 const StringPair
* pair
= (const StringPair
*)names
[i
];
749 logln(" " + pair
->displayName
+ " --> " + pair
->id
);
751 confirmIdentical("29) display names", names
.size(), 7);
754 // we should get the display name corresponding to the actual id
755 // returned by the id we used.
757 UErrorCode status
= U_ZERO_ERROR
;
758 UnicodeString actualID
;
759 UnicodeString id
= "en_us_surfer_gal";
760 UnicodeString
* gal
= (UnicodeString
*)service
.get(id
, &actualID
, status
);
762 UnicodeString displayName
;
763 logln("actual id: " + actualID
);
764 service
.getDisplayName(actualID
, displayName
, Locale::getEnglish());
765 logln("found actual: " + *gal
+ " with display name: " + displayName
);
766 confirmBoolean("30) found display name for actual", !displayName
.isBogus());
768 service
.getDisplayName(id
, displayName
, Locale::getEnglish());
769 logln("found actual: " + *gal
+ " with display name: " + displayName
);
770 confirmBoolean("31) found display name for query", displayName
.isBogus());
774 errln("30) service could not find entry for " + id
);
778 // this should be handled by the 'dude' factory, since it overrides en_US_SURFER.
780 UErrorCode status
= U_ZERO_ERROR
;
781 UnicodeString actualID
;
782 UnicodeString id
= "en_US_SURFER_BOZO";
783 UnicodeString
* bozo
= (UnicodeString
*)service
.get(id
, &actualID
, status
);
785 UnicodeString displayName
;
786 service
.getDisplayName(actualID
, displayName
, Locale::getEnglish());
787 logln("found actual: " + *bozo
+ " with display name: " + displayName
);
788 confirmBoolean("32) found display name for actual", !displayName
.isBogus());
790 service
.getDisplayName(id
, displayName
, Locale::getEnglish());
791 logln("found actual: " + *bozo
+ " with display name: " + displayName
);
792 confirmBoolean("33) found display name for query", displayName
.isBogus());
796 errln("32) service could not find entry for " + id
);
800 // certainly not default...
802 confirmBoolean("34) is default ", !service
.isDefault());
806 UErrorCode status
= U_ZERO_ERROR
;
807 UVector
ids(uprv_deleteUObject
, uhash_compareUnicodeString
, 0, status
);
808 service
.getVisibleIDs(ids
, status
);
809 for (int i
= 0; i
< ids
.size(); ++i
) {
810 const UnicodeString
* id
= (const UnicodeString
*)ids
[i
];
811 msgstr(*id
+ "? ", service
.get(*id
, status
));
814 logstr("valleygirl? ", service
.get("en_US_VALLEY_GIRL", status
));
815 logstr("valleyboy? ", service
.get("en_US_VALLEY_BOY", status
));
816 logstr("valleydude? ", service
.get("en_US_VALLEY_DUDE", status
));
817 logstr("surfergirl? ", service
.get("en_US_SURFER_GIRL", status
));
822 class CalifornioLanguageFactory
: public ICUResourceBundleFactory
825 static const char* californio
; // = "en_US_CA";
826 static const char* valley
; // = californio ## "_VALLEY";
827 static const char* surfer
; // = californio ## "_SURFER";
828 static const char* geek
; // = californio ## "_GEEK";
829 static Hashtable
* supportedIDs
; // = NULL;
831 static void cleanup(void) {
836 const Hashtable
* getSupportedIDs(UErrorCode
& status
) const
838 if (supportedIDs
== NULL
) {
839 Hashtable
* table
= new Hashtable();
840 table
->put(UnicodeString(californio
), (void*)table
, status
);
841 table
->put(UnicodeString(valley
), (void*)table
, status
);
842 table
->put(UnicodeString(surfer
), (void*)table
, status
);
843 table
->put(UnicodeString(geek
), (void*)table
, status
);
845 // not necessarily atomic, but this is a test...
846 supportedIDs
= table
;
851 UnicodeString
& getDisplayName(const UnicodeString
& id
, const Locale
& locale
, UnicodeString
& result
) const
853 UnicodeString prefix
= "";
854 UnicodeString suffix
= "";
855 UnicodeString ls
= locale
.getName();
856 if (LocaleUtility::isFallbackOf(californio
, ls
)) {
857 if (!ls
.caseCompare(valley
, 0)) {
858 prefix
= "Like, you know, it's so totally ";
859 } else if (!ls
.caseCompare(surfer
, 0)) {
860 prefix
= "Dude, it's ";
861 } else if (!ls
.caseCompare(geek
, 0)) {
862 prefix
= "I'd estimate it is approximately ";
864 prefix
= "Huh? Maybe ";
867 if (LocaleUtility::isFallbackOf(californio
, id
)) {
868 if (!id
.caseCompare(valley
, 0)) {
869 suffix
= "like the Valley, you know? Let's go to the mall!";
870 } else if (!id
.caseCompare(surfer
, 0)) {
871 suffix
= "time to hit those gnarly waves, Dude!!!";
872 } else if (!id
.caseCompare(geek
, 0)) {
873 suffix
= "all systems go. T-Minus 9, 8, 7...";
875 suffix
= "No Habla Englais";
878 suffix
= ICUResourceBundleFactory::getDisplayName(id
, locale
, result
);
881 result
= prefix
+ suffix
;
886 const char* CalifornioLanguageFactory::californio
= "en_US_CA";
887 const char* CalifornioLanguageFactory::valley
= "en_US_CA_VALLEY";
888 const char* CalifornioLanguageFactory::surfer
= "en_US_CA_SURFER";
889 const char* CalifornioLanguageFactory::geek
= "en_US_CA_GEEK";
890 Hashtable
* CalifornioLanguageFactory::supportedIDs
= NULL
;
893 ICUServiceTest::testRBF()
895 // resource bundle factory.
896 UErrorCode status
= U_ZERO_ERROR
;
897 TestStringService service
;
898 service
.registerFactory(new ICUResourceBundleFactory(), status
);
900 // list all of the resources
902 UErrorCode status
= U_ZERO_ERROR
;
903 UVector
ids(uprv_deleteUObject
, uhash_compareUnicodeString
, 0, status
);
904 service
.getVisibleIDs(ids
, status
);
905 logln("all visible ids:");
906 for (int i
= 0; i
< ids
.size(); ++i
) {
907 const UnicodeString
* id
= (const UnicodeString
*)ids
[i
];
912 // get all the display names of these resources
913 // this should be fast since the display names were cached.
915 UErrorCode status
= U_ZERO_ERROR
;
916 UVector
names(status
);
917 service
.getDisplayNames(names
, Locale::getGermany(), status
);
918 logln("service display names for de_DE");
919 for (int i
= 0; i
< names
.size(); ++i
) {
920 const StringPair
* pair
= (const StringPair
*)names
[i
];
921 logln(" " + pair
->displayName
+ " --> " + pair
->id
);
925 service
.registerFactory(new CalifornioLanguageFactory(), status
);
927 // get all the display names of these resources
929 logln("californio language factory:");
930 const char* idNames
[] = {
931 CalifornioLanguageFactory::californio
,
932 CalifornioLanguageFactory::valley
,
933 CalifornioLanguageFactory::surfer
,
934 CalifornioLanguageFactory::geek
,
936 int32_t count
= UPRV_LENGTHOF(idNames
);
938 for (int i
= 0; i
< count
; ++i
) {
939 logln(UnicodeString("\n --- ") + idNames
[i
] + " ---");
941 UErrorCode status
= U_ZERO_ERROR
;
942 UVector
names(status
);
943 service
.getDisplayNames(names
, idNames
[i
], status
);
944 for (int i
= 0; i
< names
.size(); ++i
) {
945 const StringPair
* pair
= (const StringPair
*)names
[i
];
946 logln(" " + pair
->displayName
+ " --> " + pair
->id
);
951 CalifornioLanguageFactory::cleanup();
954 class SimpleListener
: public ServiceListener
{
955 ICUServiceTest
* _test
;
959 SimpleListener(ICUServiceTest
* test
, const UnicodeString
& name
) : _test(test
), _name(name
) {}
961 virtual void serviceChanged(const ICUService
& service
) const {
962 UnicodeString serviceName
= "listener ";
963 serviceName
.append(_name
);
964 serviceName
.append(" n++");
965 serviceName
.append(" service changed: " );
966 service
.getName(serviceName
);
967 _test
->logln(serviceName
);
972 ICUServiceTest::testNotification()
974 SimpleListener
one(this, "one");
975 SimpleListener
two(this, "two");
977 UErrorCode status
= U_ZERO_ERROR
;
979 logln("simple registration notification");
980 TestStringService ls
;
981 ls
.addListener(&one
, status
);
982 ls
.addListener(&two
, status
);
984 logln("registering foo... ");
985 ls
.registerInstance(new UnicodeString("Foo"), "en_FOO", status
);
986 logln("registering bar... ");
987 ls
.registerInstance(new UnicodeString("Bar"), "en_BAR", status
);
988 logln("getting foo...");
989 UnicodeString
* result
= (UnicodeString
*)ls
.get("en_FOO", status
);
993 logln("removing listener 2...");
994 ls
.removeListener(&two
, status
);
995 logln("registering baz...");
996 ls
.registerInstance(new UnicodeString("Baz"), "en_BAZ", status
);
997 logln("removing listener 1");
998 ls
.removeListener(&one
, status
);
999 logln("registering burp...");
1000 ls
.registerInstance(new UnicodeString("Burp"), "en_BURP", status
);
1002 // should only get one notification even if register multiple times
1003 logln("... trying multiple registration");
1004 ls
.addListener(&one
, status
);
1005 ls
.addListener(&one
, status
);
1006 ls
.addListener(&one
, status
);
1007 ls
.addListener(&two
, status
);
1008 ls
.registerInstance(new UnicodeString("Foo"), "en_FOO", status
);
1009 logln("... registered foo");
1012 // same thread, so we can't callback within notification, unlike Java
1013 ServiceListener l3
= new ServiceListener() {
1015 public void serviceChanged(ICUService s
) {
1016 logln("listener 3 report " + n
++ + " service changed...");
1017 if (s
.get("en_BOINK") == null
) { // don't recurse on ourselves!!!
1018 logln("registering boink...");
1019 s
.registerInstance("boink", "en_BOINK");
1024 logln("registering boo...");
1025 ls
.registerInstance("Boo", "en_BOO");
1031 class TestStringLocaleService
: public ICULocaleService
{
1033 virtual UObject
* cloneInstance(UObject
* instance
) const {
1034 return instance
? new UnicodeString(*(UnicodeString
*)instance
) : NULL
;
1038 void ICUServiceTest::testLocale() {
1039 UErrorCode status
= U_ZERO_ERROR
;
1040 TestStringLocaleService service
;
1042 UnicodeString
* root
= new UnicodeString("root");
1043 UnicodeString
* german
= new UnicodeString("german");
1044 UnicodeString
* germany
= new UnicodeString("german_Germany");
1045 UnicodeString
* japanese
= new UnicodeString("japanese");
1046 UnicodeString
* japan
= new UnicodeString("japanese_Japan");
1048 service
.registerInstance(root
, "", status
);
1049 service
.registerInstance(german
, "de", status
);
1050 service
.registerInstance(germany
, Locale::getGermany(), status
);
1051 service
.registerInstance(japanese
, (UnicodeString
)"ja", TRUE
, status
);
1052 service
.registerInstance(japan
, Locale::getJapan(), status
);
1055 UErrorCode status
= U_ZERO_ERROR
;
1056 UnicodeString
* target
= (UnicodeString
*)service
.get("de_US", status
);
1057 confirmEqual("test de_US", german
, target
);
1062 UErrorCode status
= U_ZERO_ERROR
;
1063 UnicodeString
* target
= (UnicodeString
*)service
.get("de_US", LocaleKey::KIND_ANY
, status
);
1064 confirmEqual("test de_US 2", german
, target
);
1069 UErrorCode status
= U_ZERO_ERROR
;
1070 UnicodeString
* target
= (UnicodeString
*)service
.get("de_US", 1234, status
);
1071 confirmEqual("test de_US 3", german
, target
);
1076 UErrorCode status
= U_ZERO_ERROR
;
1077 Locale actualReturn
;
1078 UnicodeString
* target
= (UnicodeString
*)service
.get("de_US", &actualReturn
, status
);
1079 confirmEqual("test de_US 5", german
, target
);
1080 confirmEqual("test de_US 6", &actualReturn
, &Locale::getGerman());
1085 UErrorCode status
= U_ZERO_ERROR
;
1086 Locale actualReturn
;
1087 UnicodeString
* target
= (UnicodeString
*)service
.get("de_US", LocaleKey::KIND_ANY
, &actualReturn
, status
);
1088 confirmEqual("test de_US 7", &actualReturn
, &Locale::getGerman());
1093 UErrorCode status
= U_ZERO_ERROR
;
1094 Locale actualReturn
;
1095 UnicodeString
* target
= (UnicodeString
*)service
.get("de_US", 1234, &actualReturn
, status
);
1096 confirmEqual("test de_US 8", german
, target
);
1097 confirmEqual("test de_US 9", &actualReturn
, &Locale::getGerman());
1101 UnicodeString
* one
= new UnicodeString("one/de_US");
1102 UnicodeString
* two
= new UnicodeString("two/de_US");
1104 service
.registerInstance(one
, Locale("de_US"), 1, status
);
1105 service
.registerInstance(two
, Locale("de_US"), 2, status
);
1108 UErrorCode status
= U_ZERO_ERROR
;
1109 UnicodeString
* target
= (UnicodeString
*)service
.get("de_US", 1, status
);
1110 confirmEqual("test de_US kind 1", one
, target
);
1115 UErrorCode status
= U_ZERO_ERROR
;
1116 UnicodeString
* target
= (UnicodeString
*)service
.get("de_US", 2, status
);
1117 confirmEqual("test de_US kind 2", two
, target
);
1122 UErrorCode status
= U_ZERO_ERROR
;
1123 UnicodeString
* target
= (UnicodeString
*)service
.get("de_US", status
);
1124 confirmEqual("test de_US kind 3", german
, target
);
1129 UErrorCode status
= U_ZERO_ERROR
;
1130 UnicodeString english
= "en";
1131 Locale localeResult
;
1132 UnicodeString result
;
1133 LocaleKey
* lkey
= LocaleKey::createWithCanonicalFallback(&english
, NULL
, 1234, status
);
1134 logln("lkey prefix: " + lkey
->prefix(result
));
1136 logln("lkey descriptor: " + lkey
->currentDescriptor(result
));
1138 logln(UnicodeString("lkey current locale: ") + lkey
->currentLocale(localeResult
).getName());
1142 logln("lkey descriptor 2: " + lkey
->currentDescriptor(result
));
1146 logln("lkey descriptor 3: " + lkey
->currentDescriptor(result
));
1148 delete lkey
; // tentatively weiv
1152 UErrorCode status
= U_ZERO_ERROR
;
1153 UnicodeString
* target
= (UnicodeString
*)service
.get("za_PPP", status
);
1154 confirmEqual("test zappp", root
, target
);
1158 Locale loc
= Locale::getDefault();
1159 Locale::setDefault(Locale::getJapanese(), status
);
1161 UErrorCode status
= U_ZERO_ERROR
;
1162 UnicodeString
* target
= (UnicodeString
*)service
.get("za_PPP", status
);
1163 confirmEqual("test with ja locale", japanese
, target
);
1168 UErrorCode status
= U_ZERO_ERROR
;
1169 UVector
ids(uprv_deleteUObject
, uhash_compareUnicodeString
, 0, status
);
1170 service
.getVisibleIDs(ids
, status
);
1171 logln("all visible ids:");
1172 for (int i
= 0; i
< ids
.size(); ++i
) {
1173 const UnicodeString
* id
= (const UnicodeString
*)ids
[i
];
1178 Locale::setDefault(loc
, status
);
1180 UErrorCode status
= U_ZERO_ERROR
;
1181 UVector
ids(uprv_deleteUObject
, uhash_compareUnicodeString
, 0, status
);
1182 service
.getVisibleIDs(ids
, status
);
1183 logln("all visible ids:");
1184 for (int i
= 0; i
< ids
.size(); ++i
) {
1185 const UnicodeString
* id
= (const UnicodeString
*)ids
[i
];
1191 UErrorCode status
= U_ZERO_ERROR
;
1192 UnicodeString
* target
= (UnicodeString
*)service
.get("za_PPP", status
);
1193 confirmEqual("test with en locale", root
, target
);
1198 UErrorCode status
= U_ZERO_ERROR
;
1199 StringEnumeration
* locales
= service
.getAvailableLocales();
1201 confirmIdentical("test available locales", locales
->count(status
), 6);
1205 while ((p
= locales
->next(NULL
, status
))) {
1212 errln("could not create available locales");
1217 class WrapFactory
: public ICUServiceFactory
{
1219 static const UnicodeString
& getGreetingID() {
1220 if (greetingID
== NULL
) {
1221 greetingID
= new UnicodeString("greeting");
1226 static void cleanup() {
1231 UObject
* create(const ICUServiceKey
& key
, const ICUService
* service
, UErrorCode
& status
) const {
1232 if (U_SUCCESS(status
)) {
1234 if (key
.currentID(temp
).compare(getGreetingID()) == 0) {
1235 UnicodeString
* previous
= (UnicodeString
*)service
->getKey((ICUServiceKey
&)key
, NULL
, this, status
);
1237 previous
->insert(0, "A different greeting: \"");
1238 previous
->append("\"");
1246 void updateVisibleIDs(Hashtable
& result
, UErrorCode
& status
) const {
1247 if (U_SUCCESS(status
)) {
1248 result
.put("greeting", (void*)this, status
);
1252 UnicodeString
& getDisplayName(const UnicodeString
& id
, const Locale
& /* locale */, UnicodeString
& result
) const {
1253 result
.append("wrap '");
1260 * UObject boilerplate.
1262 static UClassID
getStaticClassID() {
1263 return (UClassID
)&fgClassID
;
1266 virtual UClassID
getDynamicClassID() const {
1267 return getStaticClassID();
1271 static const char fgClassID
;
1272 static UnicodeString
* greetingID
;
1275 UnicodeString
* WrapFactory::greetingID
= NULL
;
1276 const char WrapFactory::fgClassID
= '\0';
1279 ICUServiceTest::testWrapFactory()
1281 UnicodeString
* greeting
= new UnicodeString("Hello There");
1282 UnicodeString greetingID
= "greeting";
1283 UErrorCode status
= U_ZERO_ERROR
;
1284 TestStringService service
;
1285 service
.registerInstance(greeting
, greetingID
, status
);
1288 UErrorCode status
= U_ZERO_ERROR
;
1289 UnicodeString
* result
= (UnicodeString
*)service
.get(greetingID
, status
);
1291 logln("test one: " + *result
);
1296 service
.registerFactory(new WrapFactory(), status
);
1298 UErrorCode status
= U_ZERO_ERROR
;
1299 UnicodeString
* result
= (UnicodeString
*)service
.get(greetingID
, status
);
1300 UnicodeString target
= "A different greeting: \"Hello There\"";
1301 confirmEqual("wrap test: ", result
, &target
);
1305 WrapFactory::cleanup();
1308 // misc coverage tests
1309 void ICUServiceTest::testCoverage()
1314 ICUServiceKey
key("foobar");
1315 logln("ID: " + key
.getID());
1316 logln("canonicalID: " + key
.canonicalID(temp
));
1317 logln("currentID: " + key
.currentID(temp
.remove()));
1318 logln("has fallback: " + UnicodeString(key
.fallback() ? "true" : "false"));
1320 if (key
.getDynamicClassID() != ICUServiceKey::getStaticClassID()) {
1321 errln("service key rtt failed.");
1327 UErrorCode status
= U_ZERO_ERROR
;
1329 UnicodeString
* obj
= new UnicodeString("An Object");
1330 SimpleFactory
* sf
= new SimpleFactory(obj
, "object");
1333 logln(sf
->getDisplayName("object", Locale::getDefault(), temp
));
1335 if (sf
->getDynamicClassID() != SimpleFactory::getStaticClassID()) {
1336 errln("simple factory rtti failed.");
1341 TestStringService service
;
1342 service
.registerFactory(sf
, status
);
1345 UnicodeString
* result
= (UnicodeString
*)service
.get("object", status
);
1347 logln("object is: " + *result
);
1350 errln("could not get object");
1358 UErrorCode status
= U_ZERO_ERROR
;
1359 UnicodeString
* howdy
= new UnicodeString("Howdy");
1361 TestStringSimpleKeyService service
;
1362 service
.registerInstance(howdy
, "Greetings", status
);
1364 UnicodeString
* result
= (UnicodeString
*)service
.get("Greetings", status
);
1366 logln("object is: " + *result
);
1369 errln("could not get object");
1373 UVector
ids(uprv_deleteUObject
, uhash_compareUnicodeString
, status
);
1374 // yuck, this is awkward to use. All because we pass null in an overload.
1375 // TODO: change this.
1376 UnicodeString
str("Greet");
1377 service
.getVisibleIDs(ids
, &str
, status
);
1378 confirmIdentical("no fallback of greet", ids
.size(), 0);
1385 UnicodeString
primary("en_US");
1386 UnicodeString
fallback("ja_JP");
1387 UErrorCode status
= U_ZERO_ERROR
;
1388 LocaleKey
* key
= LocaleKey::createWithCanonicalFallback(&primary
, &fallback
, status
);
1390 if (key
->getDynamicClassID() != LocaleKey::getStaticClassID()) {
1391 errln("localekey rtti error");
1394 if (!key
->isFallbackOf("en_US_FOOBAR")) {
1395 errln("localekey should be fallback for en_US_FOOBAR");
1397 if (!key
->isFallbackOf("en_US")) {
1398 errln("localekey should be fallback for en_US");
1400 if (key
->isFallbackOf("en")) {
1401 errln("localekey should not be fallback for en");
1406 logln(UnicodeString("current locale: ") + key
->currentLocale(loc
).getName());
1407 logln(UnicodeString("canonical locale: ") + key
->canonicalLocale(loc
).getName());
1408 logln(UnicodeString("is fallback of en: ") + (key
->isFallbackOf("en") ? "true" : " false"));
1409 } while (key
->fallback());
1413 key
= LocaleKey::createWithCanonicalFallback(&primary
, &fallback
, status
);
1415 UnicodeString result
;
1416 LKFSubclass
lkf(TRUE
); // empty
1419 UObject
*obj
= lkf
.create(*key
, NULL
, status
);
1420 logln("obj: " + UnicodeString(obj
? "obj" : "null"));
1421 logln(lkf
.getDisplayName("en_US", Locale::getDefault(), result
));
1422 lkf
.updateVisibleIDs(table
, status
);
1424 if (table
.count() != 1) {
1425 errln("visible IDs does not contain en_US");
1428 LKFSubclass
invisibleLKF(FALSE
);
1429 obj
= lkf
.create(*key
, NULL
, status
);
1430 logln("obj: " + UnicodeString(obj
? "obj" : "null"));
1431 logln(invisibleLKF
.getDisplayName("en_US", Locale::getDefault(), result
.remove()));
1432 invisibleLKF
.updateVisibleIDs(table
, status
);
1433 if (table
.count() != 0) {
1434 errln("visible IDs contains en_US");
1439 key
= LocaleKey::createWithCanonicalFallback(&primary
, &fallback
, 123, status
);
1440 if (U_SUCCESS(status
)) {
1442 key
->currentDescriptor(str
);
1443 key
->parsePrefix(str
);
1445 errln("did not get expected prefix");
1450 // coverage, getSupportedIDs is either overridden or the calling method is
1451 LKFSubclass0 lkFactory
;
1453 lkFactory
.updateVisibleIDs(table0
, status
);
1454 if (table0
.count() != 0) {
1455 errln("LKF returned non-empty hashtable");
1459 // ResourceBundleFactory
1460 key
= LocaleKey::createWithCanonicalFallback(&primary
, &fallback
, status
);
1461 ICUResourceBundleFactory rbf
;
1462 UObject
* icurb
= rbf
.create(*key
, NULL
, status
);
1463 if (icurb
!= NULL
) {
1464 logln("got resource bundle for key");
1472 ICUNotifier nf
= new ICUNSubclass();
1474 nf
.addListener(null
);
1475 errln("added null listener");
1477 catch (NullPointerException e
) {
1478 logln(e
.getMessage());
1480 catch (Exception e
) {
1481 errln("got wrong exception");
1485 nf
.addListener(new WrongListener());
1486 errln("added wrong listener");
1488 catch (InternalError e
) {
1489 logln(e
.getMessage());
1491 catch (Exception e
) {
1492 errln("got wrong exception");
1496 nf
.removeListener(null
);
1497 errln("removed null listener");
1499 catch (NullPointerException e
) {
1500 logln(e
.getMessage());
1502 catch (Exception e
) {
1503 errln("got wrong exception");
1506 nf
.removeListener(new MyListener());
1508 nf
.addListener(new MyListener());
1509 nf
.removeListener(new MyListener());
1514 /* !UCONFIG_NO_SERVICE */