2  ******************************************************************************* 
   3  * Copyright (C) 2001-2016, International Business Machines Corporation and 
   4  * others. All Rights Reserved. 
   5  ******************************************************************************* 
   8 #include "utypeinfo.h"  // for 'typeid' to work 
  10 #include "unicode/utypes.h" 
  12 #if !UCONFIG_NO_SERVICE 
  20 class MyListener 
: public EventListener 
{ 
  23 class WrongListener 
: public EventListener 
{ 
  26 class ICUNSubclass 
: public ICUNotifier 
{ 
  28     UBool 
acceptsListener(const EventListener
& /*l*/) const { 
  30         // return l instanceof MyListener; 
  33     virtual void notifyListener(EventListener
& /*l*/) const { 
  37 // This factory does nothing 
  38 class LKFSubclass0 
: public LocaleKeyFactory 
{ 
  41                 : LocaleKeyFactory(VISIBLE
, "LKFSubclass0") 
  46 class LKFSubclass 
: public LocaleKeyFactory 
{ 
  50     LKFSubclass(UBool visible
)  
  51         : LocaleKeyFactory(visible 
? VISIBLE 
: INVISIBLE
, "LKFSubclass") 
  53         UErrorCode status 
= U_ZERO_ERROR
; 
  54         table
.put("en_US", this, status
); 
  58     virtual const Hashtable
* getSupportedIDs(UErrorCode 
&/*status*/) const { 
  63 class Integer 
: public UObject 
{ 
  67     Integer(int32_t val
) : _val(val
) { 
  70     Integer(const Integer
& rhs
) : UObject(rhs
), _val(rhs
._val
) { 
  77      * UObject boilerplate. 
  79     static UClassID 
getStaticClassID() {  
  80         return (UClassID
)&fgClassID
; 
  83     virtual UClassID 
getDynamicClassID() const { 
  84         return getStaticClassID(); 
  87     virtual UBool 
operator==(const UObject
& other
) const  
  89         return typeid(*this) == typeid(other
) && 
  90             _val 
== ((Integer
&)other
)._val
; 
  94     virtual UnicodeString
& debug(UnicodeString
& result
) const { 
  96         result
.append(" val: "); 
 101     virtual UnicodeString
& debugClass(UnicodeString
& result
) const { 
 102         return result
.append("Integer"); 
 106     static const char fgClassID
; 
 109 const char Integer::fgClassID 
= '\0'; 
 112 class TestIntegerService 
: public ICUService 
{ 
 114     ICUServiceKey
* createKey(const UnicodeString
* id
, UErrorCode
& status
) const { 
 115         return LocaleKey::createWithCanonicalFallback(id
, NULL
, status
); // no fallback locale 
 118     virtual ICUServiceFactory
* createSimpleFactory(UObject
* obj
, const UnicodeString
& id
, UBool visible
, UErrorCode
& status
)  
 121         if (U_SUCCESS(status
) && obj 
&& (i 
= dynamic_cast<Integer
*>(obj
)) != NULL
) { 
 122             return new SimpleFactory(i
, id
, visible
); 
 127     virtual UObject
* cloneInstance(UObject
* instance
) const { 
 128         return instance 
? new Integer(*(Integer
*)instance
) : NULL
; 
 133 ICUServiceTest::ICUServiceTest() { 
 136 ICUServiceTest::~ICUServiceTest() { 
 140 ICUServiceTest::runIndexedTest(int32_t index
, UBool exec
, const char* &name
, 
 144         TESTCASE(0,testAPI_One
); 
 145         TESTCASE(1,testAPI_Two
); 
 147         TESTCASE(3,testNotification
); 
 148         TESTCASE(4,testLocale
); 
 149         TESTCASE(5,testWrapFactory
); 
 150         TESTCASE(6,testCoverage
); 
 151     default: name 
= ""; break; 
 155 UnicodeString 
append(UnicodeString
& result
, const UObject
* obj
)  
 159         result
.append("NULL"); 
 161         const UnicodeString
* s
; 
 164         if ((s 
= dynamic_cast<const UnicodeString
*>(obj
)) != NULL
) { 
 166         } else if ((loc 
= dynamic_cast<const Locale
*>(obj
)) != NULL
) { 
 167             result
.append(loc
->getName()); 
 168         } else if ((i 
= dynamic_cast<const Integer
*>(obj
)) != NULL
) { 
 169             sprintf(buffer
, "%d", (int)i
->_val
); 
 170             result
.append(buffer
); 
 172             sprintf(buffer
, "%p", (const void*)obj
); 
 173             result
.append(buffer
); 
 180 ICUServiceTest::lrmsg(UnicodeString
& result
, const UnicodeString
& message
, const UObject
* lhs
, const UObject
* rhs
) const  
 182     result
.append(message
); 
 183     result
.append(" lhs: "); 
 185     result
.append(", rhs: "); 
 191 ICUServiceTest::confirmBoolean(const UnicodeString
& message
, UBool val
) 
 202 ICUServiceTest::confirmEqual(const UnicodeString
& message
, const UObject
* lhs
, const UObject
* rhs
)  
 204     UBool equ 
= (lhs 
== NULL
) 
 206         : (rhs 
!= NULL 
&& lhs
->operator==(*rhs
)); 
 209     lrmsg(temp
, message
, lhs
, rhs
); 
 219 ICUServiceTest::confirmEqual(const UnicodeString
& message
, const Integer
* lhs
, const Integer
* rhs
)  
 221     UBool equ 
= (lhs 
== NULL
) 
 223         : (rhs 
!= NULL 
&& lhs
->operator==(*rhs
)); 
 226     lrmsg(temp
, message
, lhs
, rhs
); 
 236 ICUServiceTest::confirmEqual(const UnicodeString
& message
, const UnicodeString
* lhs
, const UnicodeString
* rhs
)  
 238     UBool equ 
= (lhs 
== NULL
) 
 240         : (rhs 
!= NULL 
&& lhs
->operator==(*rhs
)); 
 243     lrmsg(temp
, message
, lhs
, rhs
); 
 253 ICUServiceTest::confirmEqual(const UnicodeString
& message
, const Locale
* lhs
, const Locale
* rhs
)  
 255     UBool equ 
= (lhs 
== NULL
) 
 257         : (rhs 
!= NULL 
&& lhs
->operator==(*rhs
)); 
 260     lrmsg(temp
, message
, lhs
, rhs
); 
 272 ICUServiceTest::confirmStringsEqual(const UnicodeString
& message
, const UnicodeString
& lhs
, const UnicodeString
& rhs
)  
 274     UBool equ 
= lhs 
== rhs
; 
 276     UnicodeString temp 
= message
; 
 277     temp
.append(" lhs: "); 
 279     temp
.append(" rhs: "); 
 291 ICUServiceTest::confirmIdentical(const UnicodeString
& message
, const UObject
* lhs
, const UObject 
*rhs
)  
 294     lrmsg(temp
, message
, lhs
, rhs
); 
 303 ICUServiceTest::confirmIdentical(const UnicodeString
& message
, int32_t lhs
, int32_t rhs
)   
 306         logln(message 
+ " lhs: " + lhs 
+ " rhs: " + rhs
); 
 308         errln(message 
+ " lhs: " + lhs 
+ " rhs: " + rhs
); 
 313 ICUServiceTest::msgstr(const UnicodeString
& message
, UObject
* obj
, UBool err
) 
 316     UnicodeString
* str 
= (UnicodeString
*)obj
; 
 317         logln(message 
+ *str
); 
 320         errln("Error " + message 
+ "string is NULL"); 
 325 ICUServiceTest::testAPI_One()  
 327     // create a service using locale keys, 
 328     TestIntegerService service
; 
 330     // register an object with one locale,  
 331     // search for an object with a more specific locale 
 332     // should return the original object 
 333     UErrorCode status 
= U_ZERO_ERROR
; 
 334     Integer
* singleton0 
= new Integer(0); 
 335     service
.registerInstance(singleton0
, "en_US", status
); 
 337         UErrorCode status 
= U_ZERO_ERROR
; 
 338         Integer
* result 
= (Integer
*)service
.get("en_US_FOO", status
); 
 339         confirmEqual("1) en_US_FOO -> en_US", result
, singleton0
); 
 343     // register a new object with the more specific locale 
 344     // search for an object with that locale 
 345     // should return the new object 
 346     Integer
* singleton1 
= new Integer(1); 
 347     service
.registerInstance(singleton1
, "en_US_FOO", status
); 
 349         UErrorCode status 
= U_ZERO_ERROR
; 
 350         Integer
* result 
= (Integer
*)service
.get("en_US_FOO", status
); 
 351         confirmEqual("2) en_US_FOO -> en_US_FOO", result
, singleton1
); 
 355     // search for an object that falls back to the first registered locale 
 357         UErrorCode status 
= U_ZERO_ERROR
; 
 358         Integer
* result 
= (Integer
*)service
.get("en_US_BAR", status
); 
 359         confirmEqual("3) en_US_BAR -> en_US", result
, singleton0
); 
 363     // get a list of the factories, should be two 
 365         confirmIdentical("4) factory size", service
.countFactories(), 2); 
 368     // register a new object with yet another locale 
 369     Integer
* singleton2 
= new Integer(2); 
 370     service
.registerInstance(singleton2
, "en", status
); 
 372         confirmIdentical("5) factory size", service
.countFactories(), 3); 
 375     // search for an object with the new locale 
 376     // stack of factories is now en, en_US_FOO, en_US 
 377     // search for en_US should still find en_US object 
 379         UErrorCode status 
= U_ZERO_ERROR
; 
 380         Integer
* result 
= (Integer
*)service
.get("en_US_BAR", status
); 
 381         confirmEqual("6) en_US_BAR -> en_US", result
, singleton0
); 
 385     // register a new object with an old id, should hide earlier factory using this id, but leave it there 
 386     Integer
* singleton3 
= new Integer(3); 
 387     URegistryKey s3key 
= service
.registerInstance(singleton3
, "en_US", status
); 
 389         confirmIdentical("9) factory size", service
.countFactories(), 4); 
 392     // should get data from that new factory 
 394         UErrorCode status 
= U_ZERO_ERROR
; 
 395         Integer
* result 
= (Integer
*)service
.get("en_US_BAR", status
); 
 396         confirmEqual("10) en_US_BAR -> (3)", result
, singleton3
); 
 400     // remove new factory 
 401     // should have fewer factories again 
 404         UErrorCode status 
= U_ZERO_ERROR
; 
 405         service
.unregister(s3key
, status
); 
 406         confirmIdentical("11) factory size", service
.countFactories(), 3); 
 409     // should get original data again after remove factory 
 411         UErrorCode status 
= U_ZERO_ERROR
; 
 412         Integer
* result 
= (Integer
*)service
.get("en_US_BAR", status
); 
 413         confirmEqual("12) en_US_BAR -> (3)", result
, singleton0
); 
 417     // shouldn't find unregistered ids 
 419         UErrorCode status 
= U_ZERO_ERROR
; 
 420         Integer
* result 
= (Integer
*)service
.get("foo", status
); 
 421         confirmIdentical("13) foo -> null", result
, NULL
); 
 425     // should find non-canonical strings 
 427         UnicodeString resultID
; 
 428         UErrorCode status 
= U_ZERO_ERROR
; 
 429         Integer
* result 
= (Integer
*)service
.get("EN_us_fOo", &resultID
, status
); 
 430         confirmEqual("14a) find-non-canonical", result
, singleton1
); 
 431         confirmStringsEqual("14b) find non-canonical", resultID
, "en_US_FOO"); 
 435     // should be able to register non-canonical strings and get them canonicalized 
 436     Integer
* singleton4 
= new Integer(4); 
 437     service
.registerInstance(singleton4
, "eN_ca_dUde", status
); 
 439         UnicodeString resultID
; 
 440         UErrorCode status 
= U_ZERO_ERROR
; 
 441         Integer
* result 
= (Integer
*)service
.get("En_Ca_DuDe", &resultID
, status
); 
 442         confirmEqual("15a) find-non-canonical", result
, singleton4
); 
 443         confirmStringsEqual("15b) register non-canonical", resultID
, "en_CA_DUDE"); 
 447     // should be able to register invisible factories, these will not 
 448     // be visible by default, but if you know the secret password you 
 449     // can still access these services... 
 450     Integer
* singleton5 
= new Integer(5); 
 451     service
.registerInstance(singleton5
, "en_US_BAR", FALSE
, status
); 
 453         UErrorCode status 
= U_ZERO_ERROR
; 
 454         Integer
* result 
= (Integer
*)service
.get("en_US_BAR", status
); 
 455         confirmEqual("17) get invisible", result
, singleton5
); 
 459     // should not be able to locate invisible services 
 461         UErrorCode status 
= U_ZERO_ERROR
; 
 462         UVector 
ids(uprv_deleteUObject
, uhash_compareUnicodeString
, status
); 
 463         service
.getVisibleIDs(ids
, status
); 
 464         UnicodeString target 
= "en_US_BAR"; 
 465         confirmBoolean("18) find invisible", !ids
.contains(&target
)); 
 468     // clear factory and caches 
 470     confirmBoolean("19) is default", service
.isDefault()); 
 474  ****************************************************************** 
 476 class TestStringSimpleKeyService 
: public ICUService 
{ 
 479         virtual ICUServiceFactory
* createSimpleFactory(UObject
* obj
, const UnicodeString
& id
, UBool visible
, UErrorCode
& status
)  
 481                 // We could put this type check into ICUService itself, but we'd still 
 482                 // have to implement cloneInstance.  Otherwise we could just tell the service 
 483                 // what the object type is when we create it, and the default implementation 
 484                 // could handle everything for us.  Phooey. 
 485         if (obj 
&& dynamic_cast<UnicodeString
*>(obj
) != NULL
) { 
 486                         return ICUService::createSimpleFactory(obj
, id
, visible
, status
); 
 491     virtual UObject
* cloneInstance(UObject
* instance
) const { 
 492         return instance 
? new UnicodeString(*(UnicodeString
*)instance
) : NULL
; 
 496 class TestStringService 
: public ICUService 
{ 
 498     ICUServiceKey
* createKey(const UnicodeString
* id
, UErrorCode
& status
) const { 
 499         return LocaleKey::createWithCanonicalFallback(id
, NULL
, status
); // no fallback locale 
 502   virtual ICUServiceFactory
* createSimpleFactory(UObject
* obj
, const UnicodeString
& id
, UBool visible
, UErrorCode
& /* status */)  
 505         if (obj 
&& (s 
= dynamic_cast<UnicodeString
*>(obj
)) != NULL
) { 
 506             return new SimpleFactory(s
, id
, visible
); 
 511     virtual UObject
* cloneInstance(UObject
* instance
) const { 
 512         return instance 
? new UnicodeString(*(UnicodeString
*)instance
) : NULL
; 
 516 // this creates a string for any id, but doesn't report anything 
 517 class AnonymousStringFactory 
: public ICUServiceFactory
 
 520     virtual UObject
* create(const ICUServiceKey
& key
, const ICUService
* /* service */, UErrorCode
& /* status */) const { 
 521         return new UnicodeString(key
.getID()); 
 524     virtual void updateVisibleIDs(Hashtable
& /*result*/, UErrorCode
& /*status*/) const { 
 528     virtual UnicodeString
& getDisplayName(const UnicodeString
& /*id*/, const Locale
& /*locale*/, UnicodeString
& result
) const { 
 533     static UClassID 
getStaticClassID() { 
 534         return (UClassID
)&fgClassID
; 
 537     virtual UClassID 
getDynamicClassID() const { 
 538         return getStaticClassID(); 
 542     static const char fgClassID
; 
 545 const char AnonymousStringFactory::fgClassID 
= '\0'; 
 547 class TestMultipleKeyStringFactory 
: public ICUServiceFactory 
{ 
 550     UnicodeString _factoryID
; 
 553     TestMultipleKeyStringFactory(const UnicodeString ids
[], int32_t count
, const UnicodeString
& factoryID
) 
 554         : _status(U_ZERO_ERROR
) 
 555         , _ids(uprv_deleteUObject
, uhash_compareUnicodeString
, count
, _status
) 
 556         , _factoryID(factoryID 
+ ": ")  
 558         for (int i 
= 0; i 
< count
; ++i
) { 
 559             _ids
.addElement(new UnicodeString(ids
[i
]), _status
); 
 563     ~TestMultipleKeyStringFactory() { 
 566     UObject
* create(const ICUServiceKey
& key
, const ICUService
* /* service */, UErrorCode
& status
) const { 
 567         if (U_FAILURE(status
)) { 
 572         if (U_SUCCESS(_status
)) { 
 573         if (_ids
.contains(&temp
)) { 
 574                 return new UnicodeString(_factoryID 
+ temp
); 
 582     void updateVisibleIDs(Hashtable
& result
, UErrorCode
& status
) const { 
 583         if (U_SUCCESS(_status
)) { 
 584             for (int32_t i 
= 0; i 
< _ids
.size(); ++i
) { 
 585                 result
.put(*(UnicodeString
*)_ids
[i
], (void*)this, status
); 
 590     UnicodeString
& getDisplayName(const UnicodeString
& id
, const Locale
& locale
, UnicodeString
& result
) const { 
 591         if (U_SUCCESS(_status
) && _ids
.contains((void*)&id
)) { 
 593             UErrorCode status 
= U_ZERO_ERROR
; 
 594             int32_t len 
= id
.extract(buffer
, sizeof(buffer
), NULL
, status
); 
 595             if (U_SUCCESS(status
)) { 
 596                 if (len 
== sizeof(buffer
)) { 
 600                 Locale loc 
= Locale::createFromName(buffer
); 
 601                 loc
.getDisplayName(locale
, result
); 
 605         result
.setToBogus(); // shouldn't happen 
 609     static UClassID 
getStaticClassID() { 
 610         return (UClassID
)&fgClassID
; 
 613     virtual UClassID 
getDynamicClassID() const { 
 614         return getStaticClassID(); 
 618     static const char fgClassID
; 
 621 const char TestMultipleKeyStringFactory::fgClassID 
= '\0'; 
 624 ICUServiceTest::testAPI_Two() 
 626     UErrorCode status 
= U_ZERO_ERROR
; 
 627     TestStringService service
; 
 628     service
.registerFactory(new AnonymousStringFactory(), status
); 
 630     // anonymous factory will still handle the id 
 632         UErrorCode status 
= U_ZERO_ERROR
; 
 633         const UnicodeString en_US 
= "en_US"; 
 634         UnicodeString
* result 
= (UnicodeString
*)service
.get(en_US
, status
); 
 635         confirmEqual("21) locale", result
, &en_US
); 
 639     // still normalizes id 
 641         UErrorCode status 
= U_ZERO_ERROR
; 
 642         const UnicodeString en_US_BAR 
= "en_US_BAR"; 
 643         UnicodeString resultID
; 
 644         UnicodeString
* result 
= (UnicodeString
*)service
.get("EN_us_bar", &resultID
, status
); 
 645         confirmEqual("22) locale", &resultID
, &en_US_BAR
); 
 649     // we can override for particular ids 
 650     UnicodeString
* singleton0 
= new UnicodeString("Zero"); 
 651     service
.registerInstance(singleton0
, "en_US_BAR", status
); 
 653         UErrorCode status 
= U_ZERO_ERROR
; 
 654         UnicodeString
* result 
= (UnicodeString
*)service
.get("en_US_BAR", status
); 
 655         confirmEqual("23) override super", result
, singleton0
); 
 659     // empty service should not recognize anything  
 662         UErrorCode status 
= U_ZERO_ERROR
; 
 663         UnicodeString
* result 
= (UnicodeString
*)service
.get("en_US", status
); 
 664         confirmIdentical("24) empty", result
, NULL
); 
 667     // create a custom multiple key factory 
 669         UnicodeString xids
[] = { 
 675         int32_t count 
= UPRV_LENGTHOF(xids
); 
 677         ICUServiceFactory
* f 
= new TestMultipleKeyStringFactory(xids
, count
, "Later"); 
 678         service
.registerFactory(f
, status
); 
 681     // iterate over the visual ids returned by the multiple factory 
 683         UErrorCode status 
= U_ZERO_ERROR
; 
 684         UVector 
ids(uprv_deleteUObject
, uhash_compareUnicodeString
, 0, status
); 
 685         service
.getVisibleIDs(ids
, status
); 
 686         for (int i 
= 0; i 
< ids
.size(); ++i
) { 
 687             const UnicodeString
* id 
= (const UnicodeString
*)ids
[i
]; 
 688             UnicodeString
* result 
= (UnicodeString
*)service
.get(*id
, status
); 
 690                 logln("  " + *id 
+ " --> " + *result
); 
 693                 errln("could not find " + *id
); 
 697         confirmIdentical("25) visible ids", ids
.size(), 4); 
 700     // iterate over the display names 
 702         UErrorCode status 
= U_ZERO_ERROR
; 
 703         UVector 
names(status
); 
 704         service
.getDisplayNames(names
, status
); 
 705         for (int i 
= 0; i 
< names
.size(); ++i
) { 
 706             const StringPair
* pair 
= (const StringPair
*)names
[i
]; 
 707             logln("  " + pair
->displayName 
+ " --> " + pair
->id
); 
 709         confirmIdentical("26) display names", names
.size(), 4); 
 712     // no valid display name 
 715         service
.getDisplayName("en_US_VALLEY_GEEK", name
); 
 716         confirmBoolean("27) get display name", name
.isBogus()); 
 721         service
.getDisplayName("en_US_SURFER_DUDE", name
, Locale::getEnglish()); 
 722         confirmStringsEqual("28) get display name", name
, "English (United States, SURFER_DUDE)"); 
 725     // register another multiple factory 
 727         UnicodeString xids
[] = { 
 731             "en_US_SILICON_GEEK", 
 733         int32_t count 
= UPRV_LENGTHOF(xids
); 
 735         ICUServiceFactory
* f 
= new TestMultipleKeyStringFactory(xids
, count
, "Rad dude"); 
 736         service
.registerFactory(f
, status
); 
 739     // this time, we have seven display names 
 740     // Rad dude's surfer gal 'replaces' Later's surfer gal 
 742         UErrorCode status 
= U_ZERO_ERROR
; 
 743         UVector 
names(status
); 
 744         service
.getDisplayNames(names
, Locale("es"), status
); 
 745         for (int i 
= 0; i 
< names
.size(); ++i
) { 
 746             const StringPair
* pair 
= (const StringPair
*)names
[i
]; 
 747             logln("  " + pair
->displayName 
+ " --> " + pair
->id
); 
 749         confirmIdentical("29) display names", names
.size(), 7); 
 752     // we should get the display name corresponding to the actual id 
 753     // returned by the id we used. 
 755         UErrorCode status 
= U_ZERO_ERROR
; 
 756         UnicodeString actualID
; 
 757         UnicodeString id 
= "en_us_surfer_gal"; 
 758         UnicodeString
* gal 
= (UnicodeString
*)service
.get(id
, &actualID
, status
); 
 760             UnicodeString displayName
; 
 761             logln("actual id: " + actualID
); 
 762             service
.getDisplayName(actualID
, displayName
, Locale::getEnglish()); 
 763             logln("found actual: " + *gal 
+ " with display name: " + displayName
); 
 764             confirmBoolean("30) found display name for actual", !displayName
.isBogus()); 
 766             service
.getDisplayName(id
, displayName
, Locale::getEnglish()); 
 767             logln("found actual: " + *gal 
+ " with display name: " + displayName
); 
 768             confirmBoolean("31) found display name for query", displayName
.isBogus()); 
 772             errln("30) service could not find entry for " + id
); 
 776     // this should be handled by the 'dude' factory, since it overrides en_US_SURFER. 
 778         UErrorCode status 
= U_ZERO_ERROR
; 
 779         UnicodeString actualID
; 
 780         UnicodeString id 
= "en_US_SURFER_BOZO"; 
 781         UnicodeString
* bozo 
= (UnicodeString
*)service
.get(id
, &actualID
, status
); 
 783             UnicodeString displayName
; 
 784             service
.getDisplayName(actualID
, displayName
, Locale::getEnglish()); 
 785             logln("found actual: " + *bozo 
+ " with display name: " + displayName
); 
 786             confirmBoolean("32) found display name for actual", !displayName
.isBogus()); 
 788             service
.getDisplayName(id
, displayName
, Locale::getEnglish()); 
 789             logln("found actual: " + *bozo 
+ " with display name: " + displayName
); 
 790             confirmBoolean("33) found display name for query", displayName
.isBogus()); 
 794             errln("32) service could not find entry for " + id
); 
 798     // certainly not default... 
 800         confirmBoolean("34) is default ", !service
.isDefault()); 
 804         UErrorCode status 
= U_ZERO_ERROR
; 
 805         UVector 
ids(uprv_deleteUObject
, uhash_compareUnicodeString
, 0, status
); 
 806         service
.getVisibleIDs(ids
, status
); 
 807         for (int i 
= 0; i 
< ids
.size(); ++i
) { 
 808             const UnicodeString
* id 
= (const UnicodeString
*)ids
[i
]; 
 809             msgstr(*id 
+ "? ", service
.get(*id
, status
)); 
 812         logstr("valleygirl?  ", service
.get("en_US_VALLEY_GIRL", status
)); 
 813         logstr("valleyboy?   ", service
.get("en_US_VALLEY_BOY", status
)); 
 814         logstr("valleydude?  ", service
.get("en_US_VALLEY_DUDE", status
)); 
 815         logstr("surfergirl?  ", service
.get("en_US_SURFER_GIRL", status
)); 
 820 class CalifornioLanguageFactory 
: public ICUResourceBundleFactory 
 
 823     static const char* californio
; // = "en_US_CA"; 
 824     static const char* valley
; // = californio ## "_VALLEY"; 
 825     static const char* surfer
; // = californio ## "_SURFER"; 
 826     static const char* geek
; // = californio ## "_GEEK"; 
 827     static Hashtable
* supportedIDs
; // = NULL; 
 829     static void cleanup(void) { 
 834     const Hashtable
* getSupportedIDs(UErrorCode
& status
) const  
 836         if (supportedIDs 
== NULL
) { 
 837             Hashtable
* table 
= new Hashtable(); 
 838             table
->put(UnicodeString(californio
), (void*)table
, status
); 
 839             table
->put(UnicodeString(valley
), (void*)table
, status
); 
 840             table
->put(UnicodeString(surfer
), (void*)table
, status
); 
 841             table
->put(UnicodeString(geek
), (void*)table
, status
); 
 843             // not necessarily atomic, but this is a test... 
 844             supportedIDs 
= table
; 
 849     UnicodeString
& getDisplayName(const UnicodeString
& id
, const Locale
& locale
, UnicodeString
& result
) const  
 851         UnicodeString prefix 
= ""; 
 852         UnicodeString suffix 
= ""; 
 853         UnicodeString ls 
= locale
.getName(); 
 854         if (LocaleUtility::isFallbackOf(californio
, ls
)) { 
 855             if (!ls
.caseCompare(valley
, 0)) { 
 856                 prefix 
= "Like, you know, it's so totally "; 
 857             } else if (!ls
.caseCompare(surfer
, 0)) { 
 858                 prefix 
= "Dude, it's "; 
 859             } else if (!ls
.caseCompare(geek
, 0)) { 
 860                 prefix 
= "I'd estimate it is approximately "; 
 862                 prefix 
= "Huh?  Maybe "; 
 865         if (LocaleUtility::isFallbackOf(californio
, id
)) { 
 866             if (!id
.caseCompare(valley
, 0)) { 
 867                 suffix 
= "like the Valley, you know?  Let's go to the mall!"; 
 868             } else if (!id
.caseCompare(surfer
, 0)) { 
 869                 suffix 
= "time to hit those gnarly waves, Dude!!!"; 
 870             } else if (!id
.caseCompare(geek
, 0)) { 
 871                 suffix 
= "all systems go.  T-Minus 9, 8, 7..."; 
 873                 suffix 
= "No Habla Englais"; 
 876             suffix 
= ICUResourceBundleFactory::getDisplayName(id
, locale
, result
); 
 879         result 
= prefix 
+ suffix
; 
 884 const char* CalifornioLanguageFactory::californio 
= "en_US_CA"; 
 885 const char* CalifornioLanguageFactory::valley 
= "en_US_CA_VALLEY"; 
 886 const char* CalifornioLanguageFactory::surfer 
= "en_US_CA_SURFER"; 
 887 const char* CalifornioLanguageFactory::geek 
= "en_US_CA_GEEK"; 
 888 Hashtable
* CalifornioLanguageFactory::supportedIDs 
= NULL
; 
 891 ICUServiceTest::testRBF() 
 893     // resource bundle factory. 
 894     UErrorCode status 
= U_ZERO_ERROR
; 
 895     TestStringService service
; 
 896     service
.registerFactory(new ICUResourceBundleFactory(), status
); 
 898     // list all of the resources  
 900         UErrorCode status 
= U_ZERO_ERROR
; 
 901         UVector 
ids(uprv_deleteUObject
, uhash_compareUnicodeString
, 0, status
); 
 902         service
.getVisibleIDs(ids
, status
); 
 903         logln("all visible ids:"); 
 904         for (int i 
= 0; i 
< ids
.size(); ++i
) { 
 905             const UnicodeString
* id 
= (const UnicodeString
*)ids
[i
]; 
 910     // get all the display names of these resources 
 911     // this should be fast since the display names were cached. 
 913         UErrorCode status 
= U_ZERO_ERROR
; 
 914         UVector 
names(status
); 
 915         service
.getDisplayNames(names
, Locale::getGermany(), status
); 
 916         logln("service display names for de_DE"); 
 917         for (int i 
= 0; i 
< names
.size(); ++i
) { 
 918             const StringPair
* pair 
= (const StringPair
*)names
[i
]; 
 919             logln("  " + pair
->displayName 
+ " --> " + pair
->id
); 
 923     service
.registerFactory(new CalifornioLanguageFactory(), status
); 
 925     // get all the display names of these resources 
 927         logln("californio language factory:"); 
 928         const char* idNames
[] = { 
 929             CalifornioLanguageFactory::californio
,  
 930             CalifornioLanguageFactory::valley
,  
 931             CalifornioLanguageFactory::surfer
,  
 932             CalifornioLanguageFactory::geek
, 
 934         int32_t count 
= UPRV_LENGTHOF(idNames
); 
 936         for (int i 
= 0; i 
< count
; ++i
) { 
 937             logln(UnicodeString("\n  --- ") + idNames
[i
] + " ---"); 
 939                 UErrorCode status 
= U_ZERO_ERROR
; 
 940                 UVector 
names(status
); 
 941                 service
.getDisplayNames(names
, idNames
[i
], status
); 
 942                 for (int i 
= 0; i 
< names
.size(); ++i
) { 
 943                     const StringPair
* pair 
= (const StringPair
*)names
[i
]; 
 944                     logln("  " + pair
->displayName 
+ " --> " + pair
->id
); 
 949     CalifornioLanguageFactory::cleanup(); 
 952 class SimpleListener 
: public ServiceListener 
{ 
 953     ICUServiceTest
* _test
; 
 957     SimpleListener(ICUServiceTest
* test
, const UnicodeString
& name
) : _test(test
), _name(name
) {} 
 959     virtual void serviceChanged(const ICUService
& service
) const { 
 960         UnicodeString serviceName 
= "listener "; 
 961         serviceName
.append(_name
); 
 962         serviceName
.append(" n++"); 
 963         serviceName
.append(" service changed: " ); 
 964         service
.getName(serviceName
); 
 965         _test
->logln(serviceName
); 
 970 ICUServiceTest::testNotification() 
 972     SimpleListener 
one(this, "one"); 
 973     SimpleListener 
two(this, "two"); 
 975         UErrorCode status 
= U_ZERO_ERROR
; 
 977         logln("simple registration notification"); 
 978         TestStringService ls
; 
 979         ls
.addListener(&one
, status
); 
 980         ls
.addListener(&two
, status
); 
 982         logln("registering foo... "); 
 983         ls
.registerInstance(new UnicodeString("Foo"), "en_FOO", status
); 
 984         logln("registering bar... "); 
 985         ls
.registerInstance(new UnicodeString("Bar"), "en_BAR", status
); 
 986         logln("getting foo..."); 
 987         UnicodeString
* result 
= (UnicodeString
*)ls
.get("en_FOO", status
); 
 991         logln("removing listener 2..."); 
 992         ls
.removeListener(&two
, status
); 
 993         logln("registering baz..."); 
 994         ls
.registerInstance(new UnicodeString("Baz"), "en_BAZ", status
); 
 995         logln("removing listener 1"); 
 996         ls
.removeListener(&one
, status
); 
 997         logln("registering burp..."); 
 998         ls
.registerInstance(new UnicodeString("Burp"), "en_BURP", status
); 
1000         // should only get one notification even if register multiple times 
1001         logln("... trying multiple registration"); 
1002         ls
.addListener(&one
, status
); 
1003         ls
.addListener(&one
, status
); 
1004         ls
.addListener(&one
, status
); 
1005         ls
.addListener(&two
, status
); 
1006         ls
.registerInstance(new UnicodeString("Foo"), "en_FOO", status
); 
1007         logln("... registered foo"); 
1010     // same thread, so we can't callback within notification, unlike Java 
1011     ServiceListener l3 
= new ServiceListener() { 
1013 public void serviceChanged(ICUService s
) { 
1014     logln("listener 3 report " + n
++ + " service changed..."); 
1015     if (s
.get("en_BOINK") == null
) { // don't recurse on ourselves!!! 
1016         logln("registering boink..."); 
1017         s
.registerInstance("boink", "en_BOINK"); 
1022     logln("registering boo..."); 
1023     ls
.registerInstance("Boo", "en_BOO"); 
1029 class TestStringLocaleService 
: public ICULocaleService 
{ 
1031     virtual UObject
* cloneInstance(UObject
* instance
) const { 
1032         return instance 
? new UnicodeString(*(UnicodeString
*)instance
) : NULL
; 
1036 void ICUServiceTest::testLocale() { 
1037     UErrorCode status 
= U_ZERO_ERROR
; 
1038     TestStringLocaleService service
; 
1040     UnicodeString
* root 
= new UnicodeString("root"); 
1041     UnicodeString
* german 
= new UnicodeString("german"); 
1042     UnicodeString
* germany 
= new UnicodeString("german_Germany"); 
1043     UnicodeString
* japanese 
= new UnicodeString("japanese"); 
1044     UnicodeString
* japan 
= new UnicodeString("japanese_Japan"); 
1046     service
.registerInstance(root
, "", status
); 
1047     service
.registerInstance(german
, "de", status
); 
1048     service
.registerInstance(germany
, Locale::getGermany(), status
); 
1049     service
.registerInstance(japanese
, (UnicodeString
)"ja", TRUE
, status
); 
1050     service
.registerInstance(japan
, Locale::getJapan(), status
); 
1053         UErrorCode status 
= U_ZERO_ERROR
; 
1054         UnicodeString
* target 
= (UnicodeString
*)service
.get("de_US", status
); 
1055         confirmEqual("test de_US", german
, target
); 
1060         UErrorCode status 
= U_ZERO_ERROR
; 
1061         UnicodeString
* target 
= (UnicodeString
*)service
.get("de_US", LocaleKey::KIND_ANY
, status
); 
1062         confirmEqual("test de_US 2", german
, target
); 
1067         UErrorCode status 
= U_ZERO_ERROR
; 
1068         UnicodeString
* target 
= (UnicodeString
*)service
.get("de_US", 1234, status
); 
1069         confirmEqual("test de_US 3", german
, target
); 
1074         UErrorCode status 
= U_ZERO_ERROR
; 
1075         Locale actualReturn
; 
1076         UnicodeString
* target 
= (UnicodeString
*)service
.get("de_US", &actualReturn
, status
); 
1077         confirmEqual("test de_US 5", german
, target
); 
1078         confirmEqual("test de_US 6", &actualReturn
, &Locale::getGerman()); 
1083         UErrorCode status 
= U_ZERO_ERROR
; 
1084         Locale actualReturn
; 
1085         UnicodeString
* target 
= (UnicodeString
*)service
.get("de_US", LocaleKey::KIND_ANY
, &actualReturn
, status
); 
1086         confirmEqual("test de_US 7", &actualReturn
, &Locale::getGerman()); 
1091         UErrorCode status 
= U_ZERO_ERROR
; 
1092         Locale actualReturn
; 
1093         UnicodeString
* target 
= (UnicodeString
*)service
.get("de_US", 1234, &actualReturn
, status
); 
1094         confirmEqual("test de_US 8", german
, target
); 
1095         confirmEqual("test de_US 9", &actualReturn
, &Locale::getGerman()); 
1099     UnicodeString
* one 
= new UnicodeString("one/de_US"); 
1100     UnicodeString
* two 
= new UnicodeString("two/de_US"); 
1102     service
.registerInstance(one
, Locale("de_US"), 1, status
); 
1103     service
.registerInstance(two
, Locale("de_US"), 2, status
); 
1106         UErrorCode status 
= U_ZERO_ERROR
; 
1107         UnicodeString
* target 
= (UnicodeString
*)service
.get("de_US", 1, status
); 
1108         confirmEqual("test de_US kind 1", one
, target
); 
1113         UErrorCode status 
= U_ZERO_ERROR
; 
1114         UnicodeString
* target 
= (UnicodeString
*)service
.get("de_US", 2, status
); 
1115         confirmEqual("test de_US kind 2", two
, target
); 
1120         UErrorCode status 
= U_ZERO_ERROR
; 
1121         UnicodeString
* target 
= (UnicodeString
*)service
.get("de_US", status
); 
1122         confirmEqual("test de_US kind 3", german
, target
); 
1127         UErrorCode status 
= U_ZERO_ERROR
; 
1128         UnicodeString english 
= "en"; 
1129         Locale localeResult
; 
1130         UnicodeString result
; 
1131         LocaleKey
* lkey 
= LocaleKey::createWithCanonicalFallback(&english
, NULL
, 1234, status
); 
1132         logln("lkey prefix: " + lkey
->prefix(result
)); 
1134         logln("lkey descriptor: " + lkey
->currentDescriptor(result
)); 
1136         logln(UnicodeString("lkey current locale: ") + lkey
->currentLocale(localeResult
).getName()); 
1140         logln("lkey descriptor 2: " + lkey
->currentDescriptor(result
)); 
1144         logln("lkey descriptor 3: " + lkey
->currentDescriptor(result
)); 
1146         delete lkey
; // tentatively weiv 
1150         UErrorCode status 
= U_ZERO_ERROR
; 
1151         UnicodeString
* target 
= (UnicodeString
*)service
.get("za_PPP", status
); 
1152         confirmEqual("test zappp", root
, target
); 
1156     Locale loc 
= Locale::getDefault(); 
1157     Locale::setDefault(Locale::getJapanese(), status
); 
1159         UErrorCode status 
= U_ZERO_ERROR
; 
1160         UnicodeString
* target 
= (UnicodeString
*)service
.get("za_PPP", status
); 
1161         confirmEqual("test with ja locale", japanese
, target
); 
1166         UErrorCode status 
= U_ZERO_ERROR
; 
1167         UVector 
ids(uprv_deleteUObject
, uhash_compareUnicodeString
, 0, status
); 
1168         service
.getVisibleIDs(ids
, status
); 
1169         logln("all visible ids:"); 
1170         for (int i 
= 0; i 
< ids
.size(); ++i
) { 
1171             const UnicodeString
* id 
= (const UnicodeString
*)ids
[i
]; 
1176     Locale::setDefault(loc
, status
); 
1178         UErrorCode status 
= U_ZERO_ERROR
; 
1179         UVector 
ids(uprv_deleteUObject
, uhash_compareUnicodeString
, 0, status
); 
1180         service
.getVisibleIDs(ids
, status
); 
1181         logln("all visible ids:"); 
1182         for (int i 
= 0; i 
< ids
.size(); ++i
) { 
1183             const UnicodeString
* id 
= (const UnicodeString
*)ids
[i
]; 
1189         UErrorCode status 
= U_ZERO_ERROR
; 
1190         UnicodeString
* target 
= (UnicodeString
*)service
.get("za_PPP", status
); 
1191         confirmEqual("test with en locale", root
, target
); 
1196         UErrorCode status 
= U_ZERO_ERROR
; 
1197         StringEnumeration
* locales 
= service
.getAvailableLocales(); 
1199             confirmIdentical("test available locales", locales
->count(status
), 6); 
1203                 while ((p 
= locales
->next(NULL
, status
))) { 
1210             errln("could not create available locales"); 
1215 class WrapFactory 
: public ICUServiceFactory 
{ 
1217     static const UnicodeString
& getGreetingID() { 
1218       if (greetingID 
== NULL
) { 
1219     greetingID 
= new UnicodeString("greeting"); 
1224   static void cleanup() { 
1229     UObject
* create(const ICUServiceKey
& key
, const ICUService
* service
, UErrorCode
& status
) const { 
1230         if (U_SUCCESS(status
)) { 
1232             if (key
.currentID(temp
).compare(getGreetingID()) == 0) { 
1233                 UnicodeString
* previous 
= (UnicodeString
*)service
->getKey((ICUServiceKey
&)key
, NULL
, this, status
); 
1235                     previous
->insert(0, "A different greeting: \""); 
1236                     previous
->append("\""); 
1244     void updateVisibleIDs(Hashtable
& result
, UErrorCode
& status
) const { 
1245         if (U_SUCCESS(status
)) { 
1246             result
.put("greeting", (void*)this, status
); 
1250     UnicodeString
& getDisplayName(const UnicodeString
& id
, const Locale
& /* locale */, UnicodeString
& result
) const { 
1251         result
.append("wrap '"); 
1258      * UObject boilerplate. 
1260     static UClassID 
getStaticClassID() {  
1261         return (UClassID
)&fgClassID
; 
1264     virtual UClassID 
getDynamicClassID() const { 
1265         return getStaticClassID(); 
1269     static const char fgClassID
; 
1270     static UnicodeString
* greetingID
; 
1273 UnicodeString
* WrapFactory::greetingID 
= NULL
; 
1274 const char WrapFactory::fgClassID 
= '\0'; 
1277 ICUServiceTest::testWrapFactory()  
1279     UnicodeString
* greeting 
= new UnicodeString("Hello There"); 
1280     UnicodeString greetingID 
= "greeting"; 
1281     UErrorCode status 
= U_ZERO_ERROR
; 
1282     TestStringService service
; 
1283     service
.registerInstance(greeting
, greetingID
, status
); 
1286         UErrorCode status 
= U_ZERO_ERROR
; 
1287         UnicodeString
* result 
= (UnicodeString
*)service
.get(greetingID
, status
); 
1289             logln("test one: " + *result
); 
1294     service
.registerFactory(new WrapFactory(), status
); 
1296         UErrorCode status 
= U_ZERO_ERROR
; 
1297         UnicodeString
* result 
= (UnicodeString
*)service
.get(greetingID
, status
); 
1298         UnicodeString target 
= "A different greeting: \"Hello There\""; 
1299         confirmEqual("wrap test: ", result
, &target
); 
1303     WrapFactory::cleanup(); 
1306   // misc coverage tests 
1307 void ICUServiceTest::testCoverage()  
1312     ICUServiceKey 
key("foobar"); 
1313     logln("ID: " + key
.getID()); 
1314     logln("canonicalID: " + key
.canonicalID(temp
)); 
1315     logln("currentID: " + key
.currentID(temp
.remove())); 
1316     logln("has fallback: " + UnicodeString(key
.fallback() ? "true" : "false")); 
1318     if (key
.getDynamicClassID() != ICUServiceKey::getStaticClassID()) { 
1319       errln("service key rtt failed."); 
1325     UErrorCode status 
= U_ZERO_ERROR
; 
1327     UnicodeString
* obj 
= new UnicodeString("An Object"); 
1328     SimpleFactory
* sf 
= new SimpleFactory(obj
, "object"); 
1331     logln(sf
->getDisplayName("object", Locale::getDefault(), temp
)); 
1333     if (sf
->getDynamicClassID() != SimpleFactory::getStaticClassID()) { 
1334       errln("simple factory rtti failed."); 
1339                 TestStringService service
; 
1340                 service
.registerFactory(sf
,     status
); 
1343                         UnicodeString
* result   
= (UnicodeString
*)service
.get("object", status
); 
1345                                 logln("object is: "     + *result
); 
1348                                 errln("could not get object"); 
1356       UErrorCode status 
= U_ZERO_ERROR
; 
1357           UnicodeString
* howdy 
= new UnicodeString("Howdy"); 
1359           TestStringSimpleKeyService service
; 
1360           service
.registerInstance(howdy
, "Greetings", status
); 
1362                   UnicodeString
* result 
= (UnicodeString
*)service
.get("Greetings",      status
); 
1364                           logln("object is: "   + *result
); 
1367                           errln("could not get object"); 
1371       UVector 
ids(uprv_deleteUObject
, uhash_compareUnicodeString
, status
); 
1372           // yuck, this is awkward to use.  All because we pass null in an overload. 
1373           // TODO: change this. 
1374           UnicodeString 
str("Greet"); 
1375       service
.getVisibleIDs(ids
, &str
, status
); 
1376       confirmIdentical("no fallback of greet", ids
.size(), 0); 
1383     UnicodeString 
primary("en_US"); 
1384     UnicodeString 
fallback("ja_JP"); 
1385     UErrorCode status 
= U_ZERO_ERROR
; 
1386     LocaleKey
* key 
= LocaleKey::createWithCanonicalFallback(&primary
, &fallback
, status
); 
1388     if (key
->getDynamicClassID() != LocaleKey::getStaticClassID()) { 
1389       errln("localekey rtti error"); 
1392     if (!key
->isFallbackOf("en_US_FOOBAR")) { 
1393       errln("localekey should be fallback for en_US_FOOBAR"); 
1395     if (!key
->isFallbackOf("en_US")) { 
1396       errln("localekey should be fallback for en_US"); 
1398     if (key
->isFallbackOf("en")) { 
1399       errln("localekey should not be fallback for en"); 
1404       logln(UnicodeString("current locale: ") + key
->currentLocale(loc
).getName()); 
1405       logln(UnicodeString("canonical locale: ") + key
->canonicalLocale(loc
).getName()); 
1406       logln(UnicodeString("is fallback of en: ") + (key
->isFallbackOf("en") ? "true" : " false")); 
1407     } while (key
->fallback()); 
1411     key 
= LocaleKey::createWithCanonicalFallback(&primary
, &fallback
, status
); 
1413     UnicodeString result
; 
1414     LKFSubclass 
lkf(TRUE
); // empty 
1417     UObject 
*obj 
= lkf
.create(*key
, NULL
, status
); 
1418     logln("obj: " + UnicodeString(obj 
? "obj" : "null")); 
1419     logln(lkf
.getDisplayName("en_US", Locale::getDefault(), result
)); 
1420     lkf
.updateVisibleIDs(table
, status
); 
1422     if (table
.count() != 1) { 
1423       errln("visible IDs does not contain en_US"); 
1426     LKFSubclass 
invisibleLKF(FALSE
); 
1427     obj 
= lkf
.create(*key
, NULL
, status
); 
1428     logln("obj: " + UnicodeString(obj 
? "obj" : "null")); 
1429     logln(invisibleLKF
.getDisplayName("en_US", Locale::getDefault(), result
.remove())); 
1430     invisibleLKF
.updateVisibleIDs(table
, status
); 
1431     if (table
.count() != 0) { 
1432       errln("visible IDs contains en_US"); 
1437         key 
= LocaleKey::createWithCanonicalFallback(&primary
, &fallback
, 123, status
); 
1438         if (U_SUCCESS(status
)) { 
1440                 key
->currentDescriptor(str
); 
1441                 key
->parsePrefix(str
); 
1443                         errln("did not get expected prefix"); 
1448         // coverage, getSupportedIDs is either overridden or the calling method is 
1449         LKFSubclass0 lkFactory
; 
1451         lkFactory
.updateVisibleIDs(table0
, status
); 
1452         if (table0
.count() != 0) { 
1453                 errln("LKF returned non-empty hashtable"); 
1457         // ResourceBundleFactory 
1458     key 
= LocaleKey::createWithCanonicalFallback(&primary
, &fallback
, status
); 
1459         ICUResourceBundleFactory rbf
; 
1460         UObject
* icurb 
= rbf
.create(*key
, NULL
, status
); 
1461         if (icurb 
!= NULL
) { 
1462                 logln("got resource bundle for key"); 
1470   ICUNotifier nf 
= new ICUNSubclass(); 
1472     nf
.addListener(null
); 
1473     errln("added null listener"); 
1475   catch (NullPointerException e
) { 
1476     logln(e
.getMessage()); 
1478   catch (Exception e
) { 
1479     errln("got wrong exception"); 
1483     nf
.addListener(new WrongListener()); 
1484     errln("added wrong listener"); 
1486   catch (InternalError e
) { 
1487     logln(e
.getMessage()); 
1489   catch (Exception e
) { 
1490     errln("got wrong exception"); 
1494     nf
.removeListener(null
); 
1495     errln("removed null listener"); 
1497   catch (NullPointerException e
) { 
1498     logln(e
.getMessage()); 
1500   catch (Exception e
) { 
1501     errln("got wrong exception"); 
1504   nf
.removeListener(new MyListener()); 
1506   nf
.addListener(new MyListener()); 
1507   nf
.removeListener(new MyListener()); 
1512 /* !UCONFIG_NO_SERVICE */