Home | History | Annotate | Download | only in intltest
      1 /**
      2  *******************************************************************************
      3  * Copyright (C) 2001-2009, International Business Machines Corporation and    *
      4  * others. All Rights Reserved.                                                *
      5  *******************************************************************************
      6  *
      7  *******************************************************************************
      8  */
      9 
     10 #include "unicode/utypes.h"
     11 
     12 #if !UCONFIG_NO_SERVICE
     13 
     14 #include "icusvtst.h"
     15 #include "servloc.h"
     16 #include <stdio.h>
     17 
     18 
     19 class MyListener : public EventListener {
     20 };
     21 
     22 class WrongListener : public EventListener {
     23 };
     24 
     25 class ICUNSubclass : public ICUNotifier {
     26     public:
     27     UBool acceptsListener(const EventListener& /*l*/) const {
     28         return TRUE;
     29         // return l instanceof MyListener;
     30     }
     31 
     32     virtual void notifyListener(EventListener& /*l*/) const {
     33     }
     34 };
     35 
     36 // This factory does nothing
     37 class LKFSubclass0 : public LocaleKeyFactory {
     38 public:
     39         LKFSubclass0()
     40                 : LocaleKeyFactory(VISIBLE, "LKFSubclass0")
     41         {
     42         }
     43 };
     44 
     45 class LKFSubclass : public LocaleKeyFactory {
     46     Hashtable table;
     47 
     48     public:
     49     LKFSubclass(UBool visible)
     50         : LocaleKeyFactory(visible ? VISIBLE : INVISIBLE, "LKFSubclass")
     51     {
     52         UErrorCode status = U_ZERO_ERROR;
     53         table.put("en_US", this, status);
     54     }
     55 
     56     protected:
     57     virtual const Hashtable* getSupportedIDs(UErrorCode &/*status*/) const {
     58         return &table;
     59     }
     60 };
     61 
     62 class Integer : public UObject {
     63     public:
     64     const int32_t _val;
     65 
     66     Integer(int32_t val) : _val(val) {
     67     }
     68 
     69     Integer(const Integer& rhs) : UObject(rhs), _val(rhs._val) {
     70     }
     71     virtual ~Integer() {
     72     }
     73 
     74     public:
     75     /**
     76      * UObject boilerplate.
     77      */
     78     static UClassID getStaticClassID() {
     79         return (UClassID)&fgClassID;
     80     }
     81 
     82     virtual UClassID getDynamicClassID() const {
     83         return getStaticClassID();
     84     }
     85 
     86     virtual UBool operator==(const UObject& other) const
     87     {
     88         return other.getDynamicClassID() == getStaticClassID() &&
     89             _val == ((Integer&)other)._val;
     90     }
     91 
     92     public:
     93     virtual UnicodeString& debug(UnicodeString& result) const {
     94         debugClass(result);
     95         result.append(" val: ");
     96         result.append(_val);
     97         return result;
     98     }
     99 
    100     virtual UnicodeString& debugClass(UnicodeString& result) const {
    101         return result.append("Integer");
    102     }
    103 
    104     private:
    105     static const char fgClassID;
    106 };
    107 
    108 const char Integer::fgClassID = '\0';
    109 
    110 // use locale keys
    111 class TestIntegerService : public ICUService {
    112     public:
    113     ICUServiceKey* createKey(const UnicodeString* id, UErrorCode& status) const {
    114         return LocaleKey::createWithCanonicalFallback(id, NULL, status); // no fallback locale
    115     }
    116 
    117     virtual ICUServiceFactory* createSimpleFactory(UObject* obj, const UnicodeString& id, UBool visible, UErrorCode& status)
    118     {
    119         if (U_SUCCESS(status) && obj && obj->getDynamicClassID() == Integer::getStaticClassID()) {
    120             return new SimpleFactory((Integer*)obj, id, visible);
    121         }
    122         return NULL;
    123     }
    124 
    125     virtual UObject* cloneInstance(UObject* instance) const {
    126         return instance ? new Integer(*(Integer*)instance) : NULL;
    127     }
    128 };
    129 
    130 
    131 ICUServiceTest::ICUServiceTest() {
    132 }
    133 
    134 ICUServiceTest::~ICUServiceTest() {
    135 }
    136 
    137 void
    138 ICUServiceTest::runIndexedTest(int32_t index, UBool exec, const char* &name,
    139 char* /*par*/)
    140 {
    141     switch (index) {
    142         TESTCASE(0,testAPI_One);
    143         TESTCASE(1,testAPI_Two);
    144         TESTCASE(2,testRBF);
    145         TESTCASE(3,testNotification);
    146         TESTCASE(4,testLocale);
    147         TESTCASE(5,testWrapFactory);
    148         TESTCASE(6,testCoverage);
    149     default: name = ""; break;
    150     }
    151 }
    152 
    153 UnicodeString append(UnicodeString& result, const UObject* obj)
    154 {
    155     char buffer[128];
    156     if (obj == NULL) {
    157         result.append("NULL");
    158     } else {
    159         UClassID id = obj->getDynamicClassID();
    160         if (id == UnicodeString::getStaticClassID()) {
    161             result.append(*(UnicodeString*)obj);
    162         } else if (id == Locale::getStaticClassID()) {
    163             result.append(((Locale*)obj)->getName());
    164         } else if (id == Integer::getStaticClassID()) {
    165             sprintf(buffer, "%d", (int)((Integer*)obj)->_val);
    166             result.append(buffer);
    167         } else {
    168             sprintf(buffer, "%p", (const void*)obj);
    169             result.append(buffer);
    170         }
    171     }
    172     return result;
    173 }
    174 
    175 UnicodeString&
    176 ICUServiceTest::lrmsg(UnicodeString& result, const UnicodeString& message, const UObject* lhs, const UObject* rhs) const
    177 {
    178     result.append(message);
    179     result.append(" lhs: ");
    180     append(result, lhs);
    181     result.append(", rhs: ");
    182     append(result, rhs);
    183     return result;
    184 }
    185 
    186 void
    187 ICUServiceTest::confirmBoolean(const UnicodeString& message, UBool val)
    188 {
    189     if (val) {
    190         logln(message);
    191     } else {
    192         errln(message);
    193     }
    194 }
    195 
    196 #if 0
    197 void
    198 ICUServiceTest::confirmEqual(const UnicodeString& message, const UObject* lhs, const UObject* rhs)
    199 {
    200     UBool equ = (lhs == NULL)
    201         ? (rhs == NULL)
    202         : (rhs != NULL && lhs->operator==(*rhs));
    203 
    204     UnicodeString temp;
    205     lrmsg(temp, message, lhs, rhs);
    206 
    207     if (equ) {
    208         logln(temp);
    209     } else {
    210         errln(temp);
    211     }
    212 }
    213 #else
    214 void
    215 ICUServiceTest::confirmEqual(const UnicodeString& message, const Integer* lhs, const Integer* rhs)
    216 {
    217     UBool equ = (lhs == NULL)
    218         ? (rhs == NULL)
    219         : (rhs != NULL && lhs->operator==(*rhs));
    220 
    221     UnicodeString temp;
    222     lrmsg(temp, message, lhs, rhs);
    223 
    224     if (equ) {
    225         logln(temp);
    226     } else {
    227         errln(temp);
    228     }
    229 }
    230 
    231 void
    232 ICUServiceTest::confirmEqual(const UnicodeString& message, const UnicodeString* lhs, const UnicodeString* rhs)
    233 {
    234     UBool equ = (lhs == NULL)
    235         ? (rhs == NULL)
    236         : (rhs != NULL && lhs->operator==(*rhs));
    237 
    238     UnicodeString temp;
    239     lrmsg(temp, message, lhs, rhs);
    240 
    241     if (equ) {
    242         logln(temp);
    243     } else {
    244         errln(temp);
    245     }
    246 }
    247 
    248 void
    249 ICUServiceTest::confirmEqual(const UnicodeString& message, const Locale* lhs, const Locale* rhs)
    250 {
    251     UBool equ = (lhs == NULL)
    252         ? (rhs == NULL)
    253         : (rhs != NULL && lhs->operator==(*rhs));
    254 
    255     UnicodeString temp;
    256     lrmsg(temp, message, lhs, rhs);
    257 
    258     if (equ) {
    259         logln(temp);
    260     } else {
    261         errln(temp);
    262     }
    263 }
    264 #endif
    265 
    266 // use these for now
    267 void
    268 ICUServiceTest::confirmStringsEqual(const UnicodeString& message, const UnicodeString& lhs, const UnicodeString& rhs)
    269 {
    270     UBool equ = lhs == rhs;
    271 
    272     UnicodeString temp = message;
    273     temp.append(" lhs: ");
    274     temp.append(lhs);
    275     temp.append(" rhs: ");
    276     temp.append(rhs);
    277 
    278     if (equ) {
    279         logln(temp);
    280     } else {
    281         dataerrln(temp);
    282     }
    283 }
    284 
    285 
    286 void
    287 ICUServiceTest::confirmIdentical(const UnicodeString& message, const UObject* lhs, const UObject *rhs)
    288 {
    289     UnicodeString temp;
    290     lrmsg(temp, message, lhs, rhs);
    291     if (lhs == rhs) {
    292         logln(temp);
    293     } else {
    294         errln(temp);
    295     }
    296 }
    297 
    298 void
    299 ICUServiceTest::confirmIdentical(const UnicodeString& message, int32_t lhs, int32_t rhs)
    300 {
    301     if (lhs == rhs) {
    302         logln(message + " lhs: " + lhs + " rhs: " + rhs);
    303     } else {
    304         errln(message + " lhs: " + lhs + " rhs: " + rhs);
    305     }
    306 }
    307 
    308 void
    309 ICUServiceTest::msgstr(const UnicodeString& message, UObject* obj, UBool err)
    310 {
    311     if (obj) {
    312     UnicodeString* str = (UnicodeString*)obj;
    313         logln(message + *str);
    314         delete str;
    315     } else if (err) {
    316         errln("Error " + message + "string is NULL");
    317     }
    318 }
    319 
    320 void
    321 ICUServiceTest::testAPI_One()
    322 {
    323     // create a service using locale keys,
    324     TestIntegerService service;
    325 
    326     // register an object with one locale,
    327     // search for an object with a more specific locale
    328     // should return the original object
    329     UErrorCode status = U_ZERO_ERROR;
    330     Integer* singleton0 = new Integer(0);
    331     service.registerInstance(singleton0, "en_US", status);
    332     {
    333         UErrorCode status = U_ZERO_ERROR;
    334         Integer* result = (Integer*)service.get("en_US_FOO", status);
    335         confirmEqual("1) en_US_FOO -> en_US", result, singleton0);
    336         delete result;
    337     }
    338 
    339     // register a new object with the more specific locale
    340     // search for an object with that locale
    341     // should return the new object
    342     Integer* singleton1 = new Integer(1);
    343     service.registerInstance(singleton1, "en_US_FOO", status);
    344     {
    345         UErrorCode status = U_ZERO_ERROR;
    346         Integer* result = (Integer*)service.get("en_US_FOO", status);
    347         confirmEqual("2) en_US_FOO -> en_US_FOO", result, singleton1);
    348         delete result;
    349     }
    350 
    351     // search for an object that falls back to the first registered locale
    352     {
    353         UErrorCode status = U_ZERO_ERROR;
    354         Integer* result = (Integer*)service.get("en_US_BAR", status);
    355         confirmEqual("3) en_US_BAR -> en_US", result, singleton0);
    356         delete result;
    357     }
    358 
    359     // get a list of the factories, should be two
    360     {
    361         confirmIdentical("4) factory size", service.countFactories(), 2);
    362     }
    363 
    364     // register a new object with yet another locale
    365     Integer* singleton2 = new Integer(2);
    366     service.registerInstance(singleton2, "en", status);
    367     {
    368         confirmIdentical("5) factory size", service.countFactories(), 3);
    369     }
    370 
    371     // search for an object with the new locale
    372     // stack of factories is now en, en_US_FOO, en_US
    373     // search for en_US should still find en_US object
    374     {
    375         UErrorCode status = U_ZERO_ERROR;
    376         Integer* result = (Integer*)service.get("en_US_BAR", status);
    377         confirmEqual("6) en_US_BAR -> en_US", result, singleton0);
    378         delete result;
    379     }
    380 
    381     // register a new object with an old id, should hide earlier factory using this id, but leave it there
    382     Integer* singleton3 = new Integer(3);
    383     URegistryKey s3key = service.registerInstance(singleton3, "en_US", status);
    384     {
    385         confirmIdentical("9) factory size", service.countFactories(), 4);
    386     }
    387 
    388     // should get data from that new factory
    389     {
    390         UErrorCode status = U_ZERO_ERROR;
    391         Integer* result = (Integer*)service.get("en_US_BAR", status);
    392         confirmEqual("10) en_US_BAR -> (3)", result, singleton3);
    393         delete result;
    394     }
    395 
    396     // remove new factory
    397     // should have fewer factories again
    398     // singleton3 dead!
    399     {
    400         UErrorCode status = U_ZERO_ERROR;
    401         service.unregister(s3key, status);
    402         confirmIdentical("11) factory size", service.countFactories(), 3);
    403     }
    404 
    405     // should get original data again after remove factory
    406     {
    407         UErrorCode status = U_ZERO_ERROR;
    408         Integer* result = (Integer*)service.get("en_US_BAR", status);
    409         confirmEqual("12) en_US_BAR -> (3)", result, singleton0);
    410         delete result;
    411     }
    412 
    413     // shouldn't find unregistered ids
    414     {
    415         UErrorCode status = U_ZERO_ERROR;
    416         Integer* result = (Integer*)service.get("foo", status);
    417         confirmIdentical("13) foo -> null", result, NULL);
    418         delete result;
    419     }
    420 
    421     // should find non-canonical strings
    422     {
    423         UnicodeString resultID;
    424         UErrorCode status = U_ZERO_ERROR;
    425         Integer* result = (Integer*)service.get("EN_us_fOo", &resultID, status);
    426         confirmEqual("14a) find-non-canonical", result, singleton1);
    427         confirmStringsEqual("14b) find non-canonical", resultID, "en_US_FOO");
    428         delete result;
    429     }
    430 
    431     // should be able to register non-canonical strings and get them canonicalized
    432     Integer* singleton4 = new Integer(4);
    433     service.registerInstance(singleton4, "eN_ca_dUde", status);
    434     {
    435         UnicodeString resultID;
    436         UErrorCode status = U_ZERO_ERROR;
    437         Integer* result = (Integer*)service.get("En_Ca_DuDe", &resultID, status);
    438         confirmEqual("15a) find-non-canonical", result, singleton4);
    439         confirmStringsEqual("15b) register non-canonical", resultID, "en_CA_DUDE");
    440         delete result;
    441     }
    442 
    443     // should be able to register invisible factories, these will not
    444     // be visible by default, but if you know the secret password you
    445     // can still access these services...
    446     Integer* singleton5 = new Integer(5);
    447     service.registerInstance(singleton5, "en_US_BAR", FALSE, status);
    448     {
    449         UErrorCode status = U_ZERO_ERROR;
    450         Integer* result = (Integer*)service.get("en_US_BAR", status);
    451         confirmEqual("17) get invisible", result, singleton5);
    452         delete result;
    453     }
    454 
    455     // should not be able to locate invisible services
    456     {
    457         UErrorCode status = U_ZERO_ERROR;
    458         UVector ids(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
    459         service.getVisibleIDs(ids, status);
    460         UnicodeString target = "en_US_BAR";
    461         confirmBoolean("18) find invisible", !ids.contains(&target));
    462     }
    463 
    464     // clear factory and caches
    465     service.reset();
    466     confirmBoolean("19) is default", service.isDefault());
    467 }
    468 
    469 /*
    470  ******************************************************************
    471  */
    472 class TestStringSimpleKeyService : public ICUService {
    473 public:
    474 
    475         virtual ICUServiceFactory* createSimpleFactory(UObject* obj, const UnicodeString& id, UBool visible, UErrorCode& status)
    476     {
    477                 // We could put this type check into ICUService itself, but we'd still
    478                 // have to implement cloneInstance.  Otherwise we could just tell the service
    479                 // what the object type is when we create it, and the default implementation
    480                 // could handle everything for us.  Phooey.
    481         if (obj && obj->getDynamicClassID() == UnicodeString::getStaticClassID()) {
    482                         return ICUService::createSimpleFactory(obj, id, visible, status);
    483         }
    484         return NULL;
    485     }
    486 
    487     virtual UObject* cloneInstance(UObject* instance) const {
    488         return instance ? new UnicodeString(*(UnicodeString*)instance) : NULL;
    489     }
    490 };
    491 
    492 class TestStringService : public ICUService {
    493     public:
    494     ICUServiceKey* createKey(const UnicodeString* id, UErrorCode& status) const {
    495         return LocaleKey::createWithCanonicalFallback(id, NULL, status); // no fallback locale
    496     }
    497 
    498   virtual ICUServiceFactory* createSimpleFactory(UObject* obj, const UnicodeString& id, UBool visible, UErrorCode& /* status */)
    499     {
    500         if (obj && obj->getDynamicClassID() == UnicodeString::getStaticClassID()) {
    501             return new SimpleFactory((UnicodeString*)obj, id, visible);
    502         }
    503         return NULL;
    504     }
    505 
    506     virtual UObject* cloneInstance(UObject* instance) const {
    507         return instance ? new UnicodeString(*(UnicodeString*)instance) : NULL;
    508     }
    509 };
    510 
    511 // this creates a string for any id, but doesn't report anything
    512 class AnonymousStringFactory : public ICUServiceFactory
    513 {
    514     public:
    515     virtual UObject* create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& /* status */) const {
    516         return new UnicodeString(key.getID());
    517     }
    518 
    519     virtual void updateVisibleIDs(Hashtable& /*result*/, UErrorCode& /*status*/) const {
    520         // do nothing
    521     }
    522 
    523     virtual UnicodeString& getDisplayName(const UnicodeString& /*id*/, const Locale& /*locale*/, UnicodeString& result) const {
    524         // do nothing
    525         return result;
    526     }
    527 
    528     static UClassID getStaticClassID() {
    529         return (UClassID)&fgClassID;
    530     }
    531 
    532     virtual UClassID getDynamicClassID() const {
    533         return getStaticClassID();
    534     }
    535 
    536     private:
    537     static const char fgClassID;
    538 };
    539 
    540 const char AnonymousStringFactory::fgClassID = '\0';
    541 
    542 class TestMultipleKeyStringFactory : public ICUServiceFactory {
    543     UErrorCode _status;
    544     UVector _ids;
    545     UnicodeString _factoryID;
    546 
    547     public:
    548     TestMultipleKeyStringFactory(const UnicodeString ids[], int32_t count, const UnicodeString& factoryID)
    549         : _status(U_ZERO_ERROR)
    550         , _ids(uhash_deleteUnicodeString, uhash_compareUnicodeString, count, _status)
    551         , _factoryID(factoryID + ": ")
    552     {
    553         for (int i = 0; i < count; ++i) {
    554             _ids.addElement(new UnicodeString(ids[i]), _status);
    555         }
    556     }
    557 
    558     ~TestMultipleKeyStringFactory() {
    559     }
    560 
    561     UObject* create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const {
    562         if (U_FAILURE(status)) {
    563         return NULL;
    564         }
    565         UnicodeString temp;
    566         key.currentID(temp);
    567         if (U_SUCCESS(_status)) {
    568         if (_ids.contains(&temp)) {
    569                 return new UnicodeString(_factoryID + temp);
    570         }
    571         } else {
    572         status = _status;
    573     }
    574         return NULL;
    575     }
    576 
    577     void updateVisibleIDs(Hashtable& result, UErrorCode& status) const {
    578         if (U_SUCCESS(_status)) {
    579             for (int32_t i = 0; i < _ids.size(); ++i) {
    580                 result.put(*(UnicodeString*)_ids[i], (void*)this, status);
    581             }
    582         }
    583     }
    584 
    585     UnicodeString& getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const {
    586         if (U_SUCCESS(_status) && _ids.contains((void*)&id)) {
    587             char buffer[128];
    588             UErrorCode status = U_ZERO_ERROR;
    589             int32_t len = id.extract(buffer, sizeof(buffer), NULL, status);
    590             if (U_SUCCESS(status)) {
    591                 if (len == sizeof(buffer)) {
    592                     --len;
    593                 }
    594                 buffer[len] = 0;
    595                 Locale loc = Locale::createFromName(buffer);
    596                 loc.getDisplayName(locale, result);
    597                 return result;
    598             }
    599         }
    600         result.setToBogus(); // shouldn't happen
    601         return result;
    602     }
    603 
    604     static UClassID getStaticClassID() {
    605         return (UClassID)&fgClassID;
    606     }
    607 
    608     virtual UClassID getDynamicClassID() const {
    609         return getStaticClassID();
    610     }
    611 
    612     private:
    613     static const char fgClassID;
    614 };
    615 
    616 const char TestMultipleKeyStringFactory::fgClassID = '\0';
    617 
    618 void
    619 ICUServiceTest::testAPI_Two()
    620 {
    621     UErrorCode status = U_ZERO_ERROR;
    622     TestStringService service;
    623     service.registerFactory(new AnonymousStringFactory(), status);
    624 
    625     // anonymous factory will still handle the id
    626     {
    627         UErrorCode status = U_ZERO_ERROR;
    628         const UnicodeString en_US = "en_US";
    629         UnicodeString* result = (UnicodeString*)service.get(en_US, status);
    630         confirmEqual("21) locale", result, &en_US);
    631         delete result;
    632     }
    633 
    634     // still normalizes id
    635     {
    636         UErrorCode status = U_ZERO_ERROR;
    637         const UnicodeString en_US_BAR = "en_US_BAR";
    638         UnicodeString resultID;
    639         UnicodeString* result = (UnicodeString*)service.get("EN_us_bar", &resultID, status);
    640         confirmEqual("22) locale", &resultID, &en_US_BAR);
    641         delete result;
    642     }
    643 
    644     // we can override for particular ids
    645     UnicodeString* singleton0 = new UnicodeString("Zero");
    646     service.registerInstance(singleton0, "en_US_BAR", status);
    647     {
    648         UErrorCode status = U_ZERO_ERROR;
    649         UnicodeString* result = (UnicodeString*)service.get("en_US_BAR", status);
    650         confirmEqual("23) override super", result, singleton0);
    651         delete result;
    652     }
    653 
    654     // empty service should not recognize anything
    655     service.reset();
    656     {
    657         UErrorCode status = U_ZERO_ERROR;
    658         UnicodeString* result = (UnicodeString*)service.get("en_US", status);
    659         confirmIdentical("24) empty", result, NULL);
    660     }
    661 
    662     // create a custom multiple key factory
    663     {
    664         UnicodeString xids[] = {
    665             "en_US_VALLEY_GIRL",
    666             "en_US_VALLEY_BOY",
    667             "en_US_SURFER_GAL",
    668             "en_US_SURFER_DUDE"
    669         };
    670         int32_t count = sizeof(xids)/sizeof(UnicodeString);
    671 
    672         ICUServiceFactory* f = new TestMultipleKeyStringFactory(xids, count, "Later");
    673         service.registerFactory(f, status);
    674     }
    675 
    676     // iterate over the visual ids returned by the multiple factory
    677     {
    678         UErrorCode status = U_ZERO_ERROR;
    679         UVector ids(uhash_deleteUnicodeString, uhash_compareUnicodeString, 0, status);
    680         service.getVisibleIDs(ids, status);
    681         for (int i = 0; i < ids.size(); ++i) {
    682             const UnicodeString* id = (const UnicodeString*)ids[i];
    683             UnicodeString* result = (UnicodeString*)service.get(*id, status);
    684             if (result) {
    685                 logln("  " + *id + " --> " + *result);
    686                 delete result;
    687             } else {
    688                 errln("could not find " + *id);
    689             }
    690         }
    691         // four visible ids
    692         confirmIdentical("25) visible ids", ids.size(), 4);
    693     }
    694 
    695     // iterate over the display names
    696     {
    697         UErrorCode status = U_ZERO_ERROR;
    698         UVector names(status);
    699         service.getDisplayNames(names, status);
    700         for (int i = 0; i < names.size(); ++i) {
    701             const StringPair* pair = (const StringPair*)names[i];
    702             logln("  " + pair->displayName + " --> " + pair->id);
    703         }
    704         confirmIdentical("26) display names", names.size(), 4);
    705     }
    706 
    707     // no valid display name
    708     {
    709         UnicodeString name;
    710         service.getDisplayName("en_US_VALLEY_GEEK", name);
    711         confirmBoolean("27) get display name", name.isBogus());
    712     }
    713 
    714     {
    715         UnicodeString name;
    716         service.getDisplayName("en_US_SURFER_DUDE", name, Locale::getEnglish());
    717         confirmStringsEqual("28) get display name", name, "English (United States, SURFER_DUDE)");
    718     }
    719 
    720     // register another multiple factory
    721     {
    722         UnicodeString xids[] = {
    723             "en_US_SURFER",
    724             "en_US_SURFER_GAL",
    725             "en_US_SILICON",
    726             "en_US_SILICON_GEEK",
    727         };
    728         int32_t count = sizeof(xids)/sizeof(UnicodeString);
    729 
    730         ICUServiceFactory* f = new TestMultipleKeyStringFactory(xids, count, "Rad dude");
    731         service.registerFactory(f, status);
    732     }
    733 
    734     // this time, we have seven display names
    735     // Rad dude's surfer gal 'replaces' Later's surfer gal
    736     {
    737         UErrorCode status = U_ZERO_ERROR;
    738         UVector names(status);
    739         service.getDisplayNames(names, Locale("es"), status);
    740         for (int i = 0; i < names.size(); ++i) {
    741             const StringPair* pair = (const StringPair*)names[i];
    742             logln("  " + pair->displayName + " --> " + pair->id);
    743         }
    744         confirmIdentical("29) display names", names.size(), 7);
    745     }
    746 
    747     // we should get the display name corresponding to the actual id
    748     // returned by the id we used.
    749     {
    750         UErrorCode status = U_ZERO_ERROR;
    751         UnicodeString actualID;
    752         UnicodeString id = "en_us_surfer_gal";
    753         UnicodeString* gal = (UnicodeString*)service.get(id, &actualID, status);
    754         if (gal != NULL) {
    755             UnicodeString displayName;
    756             logln("actual id: " + actualID);
    757             service.getDisplayName(actualID, displayName, Locale::getEnglish());
    758             logln("found actual: " + *gal + " with display name: " + displayName);
    759             confirmBoolean("30) found display name for actual", !displayName.isBogus());
    760 
    761             service.getDisplayName(id, displayName, Locale::getEnglish());
    762             logln("found actual: " + *gal + " with display name: " + displayName);
    763             confirmBoolean("31) found display name for query", displayName.isBogus());
    764 
    765             delete gal;
    766         } else {
    767             errln("30) service could not find entry for " + id);
    768         }
    769     }
    770 
    771     // this should be handled by the 'dude' factory, since it overrides en_US_SURFER.
    772     {
    773         UErrorCode status = U_ZERO_ERROR;
    774         UnicodeString actualID;
    775         UnicodeString id = "en_US_SURFER_BOZO";
    776         UnicodeString* bozo = (UnicodeString*)service.get(id, &actualID, status);
    777         if (bozo != NULL) {
    778             UnicodeString displayName;
    779             service.getDisplayName(actualID, displayName, Locale::getEnglish());
    780             logln("found actual: " + *bozo + " with display name: " + displayName);
    781             confirmBoolean("32) found display name for actual", !displayName.isBogus());
    782 
    783             service.getDisplayName(id, displayName, Locale::getEnglish());
    784             logln("found actual: " + *bozo + " with display name: " + displayName);
    785             confirmBoolean("33) found display name for query", displayName.isBogus());
    786 
    787             delete bozo;
    788         } else {
    789             errln("32) service could not find entry for " + id);
    790         }
    791     }
    792 
    793     // certainly not default...
    794     {
    795         confirmBoolean("34) is default ", !service.isDefault());
    796     }
    797 
    798     {
    799         UErrorCode status = U_ZERO_ERROR;
    800         UVector ids(uhash_deleteUnicodeString, uhash_compareUnicodeString, 0, status);
    801         service.getVisibleIDs(ids, status);
    802         for (int i = 0; i < ids.size(); ++i) {
    803             const UnicodeString* id = (const UnicodeString*)ids[i];
    804             msgstr(*id + "? ", service.get(*id, status));
    805         }
    806 
    807         logstr("valleygirl?  ", service.get("en_US_VALLEY_GIRL", status));
    808         logstr("valleyboy?   ", service.get("en_US_VALLEY_BOY", status));
    809         logstr("valleydude?  ", service.get("en_US_VALLEY_DUDE", status));
    810         logstr("surfergirl?  ", service.get("en_US_SURFER_GIRL", status));
    811     }
    812 }
    813 
    814 
    815 class CalifornioLanguageFactory : public ICUResourceBundleFactory
    816 {
    817     public:
    818     static const char* californio; // = "en_US_CA";
    819     static const char* valley; // = californio ## "_VALLEY";
    820     static const char* surfer; // = californio ## "_SURFER";
    821     static const char* geek; // = californio ## "_GEEK";
    822     static Hashtable* supportedIDs; // = NULL;
    823 
    824     static void cleanup(void) {
    825       delete supportedIDs;
    826       supportedIDs = NULL;
    827     }
    828 
    829     const Hashtable* getSupportedIDs(UErrorCode& status) const
    830     {
    831         if (supportedIDs == NULL) {
    832             Hashtable* table = new Hashtable();
    833             table->put(UnicodeString(californio), (void*)table, status);
    834             table->put(UnicodeString(valley), (void*)table, status);
    835             table->put(UnicodeString(surfer), (void*)table, status);
    836             table->put(UnicodeString(geek), (void*)table, status);
    837 
    838             // not necessarily atomic, but this is a test...
    839             supportedIDs = table;
    840         }
    841         return supportedIDs;
    842     }
    843 
    844     UnicodeString& getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const
    845     {
    846         UnicodeString prefix = "";
    847         UnicodeString suffix = "";
    848         UnicodeString ls = locale.getName();
    849         if (LocaleUtility::isFallbackOf(californio, ls)) {
    850             if (!ls.caseCompare(valley, 0)) {
    851                 prefix = "Like, you know, it's so totally ";
    852             } else if (!ls.caseCompare(surfer, 0)) {
    853                 prefix = "Dude, it's ";
    854             } else if (!ls.caseCompare(geek, 0)) {
    855                 prefix = "I'd estimate it is approximately ";
    856             } else {
    857                 prefix = "Huh?  Maybe ";
    858             }
    859         }
    860         if (LocaleUtility::isFallbackOf(californio, id)) {
    861             if (!id.caseCompare(valley, 0)) {
    862                 suffix = "like the Valley, you know?  Let's go to the mall!";
    863             } else if (!id.caseCompare(surfer, 0)) {
    864                 suffix = "time to hit those gnarly waves, Dude!!!";
    865             } else if (!id.caseCompare(geek, 0)) {
    866                 suffix = "all systems go.  T-Minus 9, 8, 7...";
    867             } else {
    868                 suffix = "No Habla Englais";
    869             }
    870         } else {
    871             suffix = ICUResourceBundleFactory::getDisplayName(id, locale, result);
    872         }
    873 
    874         result = prefix + suffix;
    875         return result;
    876     }
    877 };
    878 
    879 const char* CalifornioLanguageFactory::californio = "en_US_CA";
    880 const char* CalifornioLanguageFactory::valley = "en_US_CA_VALLEY";
    881 const char* CalifornioLanguageFactory::surfer = "en_US_CA_SURFER";
    882 const char* CalifornioLanguageFactory::geek = "en_US_CA_GEEK";
    883 Hashtable* CalifornioLanguageFactory::supportedIDs = NULL;
    884 
    885 void
    886 ICUServiceTest::testRBF()
    887 {
    888     // resource bundle factory.
    889     UErrorCode status = U_ZERO_ERROR;
    890     TestStringService service;
    891     service.registerFactory(new ICUResourceBundleFactory(), status);
    892 
    893     // list all of the resources
    894     {
    895         UErrorCode status = U_ZERO_ERROR;
    896         UVector ids(uhash_deleteUnicodeString, uhash_compareUnicodeString, 0, status);
    897         service.getVisibleIDs(ids, status);
    898         logln("all visible ids:");
    899         for (int i = 0; i < ids.size(); ++i) {
    900             const UnicodeString* id = (const UnicodeString*)ids[i];
    901             logln(*id);
    902         }
    903     }
    904 
    905     // get all the display names of these resources
    906     // this should be fast since the display names were cached.
    907     {
    908         UErrorCode status = U_ZERO_ERROR;
    909         UVector names(status);
    910         service.getDisplayNames(names, Locale::getGermany(), status);
    911         logln("service display names for de_DE");
    912         for (int i = 0; i < names.size(); ++i) {
    913             const StringPair* pair = (const StringPair*)names[i];
    914             logln("  " + pair->displayName + " --> " + pair->id);
    915         }
    916     }
    917 
    918     service.registerFactory(new CalifornioLanguageFactory(), status);
    919 
    920     // get all the display names of these resources
    921     {
    922         logln("californio language factory:");
    923         const char* idNames[] = {
    924             CalifornioLanguageFactory::californio,
    925             CalifornioLanguageFactory::valley,
    926             CalifornioLanguageFactory::surfer,
    927             CalifornioLanguageFactory::geek,
    928         };
    929         int32_t count = sizeof(idNames)/sizeof(idNames[0]);
    930 
    931         for (int i = 0; i < count; ++i) {
    932             logln(UnicodeString("\n  --- ") + idNames[i] + " ---");
    933             {
    934                 UErrorCode status = U_ZERO_ERROR;
    935                 UVector names(status);
    936                 service.getDisplayNames(names, idNames[i], status);
    937                 for (int i = 0; i < names.size(); ++i) {
    938                     const StringPair* pair = (const StringPair*)names[i];
    939                     logln("  " + pair->displayName + " --> " + pair->id);
    940                 }
    941             }
    942         }
    943     }
    944     CalifornioLanguageFactory::cleanup();
    945 }
    946 
    947 class SimpleListener : public ServiceListener {
    948     ICUServiceTest* _test;
    949     int32_t _n;
    950     UnicodeString _name;
    951 
    952     public:
    953     SimpleListener(ICUServiceTest* test, const UnicodeString& name) : _test(test), _n(0), _name(name) {}
    954 
    955     virtual void serviceChanged(const ICUService& service) const {
    956         UnicodeString serviceName = "listener ";
    957         serviceName.append(_name);
    958         serviceName.append(" n++");
    959         serviceName.append(" service changed: " );
    960         service.getName(serviceName);
    961         _test->logln(serviceName);
    962     }
    963 };
    964 
    965 void
    966 ICUServiceTest::testNotification()
    967 {
    968     SimpleListener one(this, "one");
    969     SimpleListener two(this, "two");
    970     {
    971         UErrorCode status = U_ZERO_ERROR;
    972 
    973         logln("simple registration notification");
    974         TestStringService ls;
    975         ls.addListener(&one, status);
    976         ls.addListener(&two, status);
    977 
    978         logln("registering foo... ");
    979         ls.registerInstance(new UnicodeString("Foo"), "en_FOO", status);
    980         logln("registering bar... ");
    981         ls.registerInstance(new UnicodeString("Bar"), "en_BAR", status);
    982         logln("getting foo...");
    983         UnicodeString* result = (UnicodeString*)ls.get("en_FOO", status);
    984         logln(*result);
    985         delete result;
    986 
    987         logln("removing listener 2...");
    988         ls.removeListener(&two, status);
    989         logln("registering baz...");
    990         ls.registerInstance(new UnicodeString("Baz"), "en_BAZ", status);
    991         logln("removing listener 1");
    992         ls.removeListener(&one, status);
    993         logln("registering burp...");
    994         ls.registerInstance(new UnicodeString("Burp"), "en_BURP", status);
    995 
    996         // should only get one notification even if register multiple times
    997         logln("... trying multiple registration");
    998         ls.addListener(&one, status);
    999         ls.addListener(&one, status);
   1000         ls.addListener(&one, status);
   1001         ls.addListener(&two, status);
   1002         ls.registerInstance(new UnicodeString("Foo"), "en_FOO", status);
   1003         logln("... registered foo");
   1004     }
   1005 #if 0
   1006     // same thread, so we can't callback within notification, unlike Java
   1007     ServiceListener l3 = new ServiceListener() {
   1008 private int n;
   1009 public void serviceChanged(ICUService s) {
   1010     logln("listener 3 report " + n++ + " service changed...");
   1011     if (s.get("en_BOINK") == null) { // don't recurse on ourselves!!!
   1012         logln("registering boink...");
   1013         s.registerInstance("boink", "en_BOINK");
   1014     }
   1015 }
   1016     };
   1017     ls.addListener(l3);
   1018     logln("registering boo...");
   1019     ls.registerInstance("Boo", "en_BOO");
   1020 #endif
   1021 
   1022     logln("...done");
   1023 }
   1024 
   1025 class TestStringLocaleService : public ICULocaleService {
   1026     public:
   1027     virtual UObject* cloneInstance(UObject* instance) const {
   1028         return instance ? new UnicodeString(*(UnicodeString*)instance) : NULL;
   1029     }
   1030 };
   1031 
   1032 void ICUServiceTest::testLocale() {
   1033     UErrorCode status = U_ZERO_ERROR;
   1034     TestStringLocaleService service;
   1035 
   1036     UnicodeString* root = new UnicodeString("root");
   1037     UnicodeString* german = new UnicodeString("german");
   1038     UnicodeString* germany = new UnicodeString("german_Germany");
   1039     UnicodeString* japanese = new UnicodeString("japanese");
   1040     UnicodeString* japan = new UnicodeString("japanese_Japan");
   1041 
   1042     service.registerInstance(root, "", status);
   1043     service.registerInstance(german, "de", status);
   1044     service.registerInstance(germany, Locale::getGermany(), status);
   1045     service.registerInstance(japanese, (UnicodeString)"ja", TRUE, status);
   1046     service.registerInstance(japan, Locale::getJapan(), status);
   1047 
   1048     {
   1049         UErrorCode status = U_ZERO_ERROR;
   1050         UnicodeString* target = (UnicodeString*)service.get("de_US", status);
   1051         confirmEqual("test de_US", german, target);
   1052         delete target;
   1053     }
   1054 
   1055     {
   1056         UErrorCode status = U_ZERO_ERROR;
   1057         UnicodeString* target = (UnicodeString*)service.get("de_US", LocaleKey::KIND_ANY, status);
   1058         confirmEqual("test de_US 2", german, target);
   1059         delete target;
   1060     }
   1061 
   1062     {
   1063         UErrorCode status = U_ZERO_ERROR;
   1064         UnicodeString* target = (UnicodeString*)service.get("de_US", 1234, status);
   1065         confirmEqual("test de_US 3", german, target);
   1066         delete target;
   1067     }
   1068 
   1069     {
   1070         UErrorCode status = U_ZERO_ERROR;
   1071         Locale actualReturn;
   1072         UnicodeString* target = (UnicodeString*)service.get("de_US", &actualReturn, status);
   1073         confirmEqual("test de_US 5", german, target);
   1074         confirmEqual("test de_US 6", &actualReturn, &Locale::getGerman());
   1075         delete target;
   1076     }
   1077 
   1078     {
   1079         UErrorCode status = U_ZERO_ERROR;
   1080         Locale actualReturn;
   1081         UnicodeString* target = (UnicodeString*)service.get("de_US", LocaleKey::KIND_ANY, &actualReturn, status);
   1082         confirmEqual("test de_US 7", &actualReturn, &Locale::getGerman());
   1083         delete target;
   1084     }
   1085 
   1086     {
   1087         UErrorCode status = U_ZERO_ERROR;
   1088         Locale actualReturn;
   1089         UnicodeString* target = (UnicodeString*)service.get("de_US", 1234, &actualReturn, status);
   1090         confirmEqual("test de_US 8", german, target);
   1091         confirmEqual("test de_US 9", &actualReturn, &Locale::getGerman());
   1092         delete target;
   1093     }
   1094 
   1095     UnicodeString* one = new UnicodeString("one/de_US");
   1096     UnicodeString* two = new UnicodeString("two/de_US");
   1097 
   1098     service.registerInstance(one, Locale("de_US"), 1, status);
   1099     service.registerInstance(two, Locale("de_US"), 2, status);
   1100 
   1101     {
   1102         UErrorCode status = U_ZERO_ERROR;
   1103         UnicodeString* target = (UnicodeString*)service.get("de_US", 1, status);
   1104         confirmEqual("test de_US kind 1", one, target);
   1105         delete target;
   1106     }
   1107 
   1108     {
   1109         UErrorCode status = U_ZERO_ERROR;
   1110         UnicodeString* target = (UnicodeString*)service.get("de_US", 2, status);
   1111         confirmEqual("test de_US kind 2", two, target);
   1112         delete target;
   1113     }
   1114 
   1115     {
   1116         UErrorCode status = U_ZERO_ERROR;
   1117         UnicodeString* target = (UnicodeString*)service.get("de_US", status);
   1118         confirmEqual("test de_US kind 3", german, target);
   1119         delete target;
   1120     }
   1121 
   1122     {
   1123         UErrorCode status = U_ZERO_ERROR;
   1124         UnicodeString english = "en";
   1125         Locale localeResult;
   1126         UnicodeString result;
   1127         LocaleKey* lkey = LocaleKey::createWithCanonicalFallback(&english, NULL, 1234, status);
   1128         logln("lkey prefix: " + lkey->prefix(result));
   1129         result.remove();
   1130         logln("lkey descriptor: " + lkey->currentDescriptor(result));
   1131         result.remove();
   1132         logln(UnicodeString("lkey current locale: ") + lkey->currentLocale(localeResult).getName());
   1133         result.remove();
   1134 
   1135         lkey->fallback();
   1136         logln("lkey descriptor 2: " + lkey->currentDescriptor(result));
   1137         result.remove();
   1138 
   1139         lkey->fallback();
   1140         logln("lkey descriptor 3: " + lkey->currentDescriptor(result));
   1141         result.remove();
   1142         delete lkey; // tentatively weiv
   1143     }
   1144 
   1145     {
   1146         UErrorCode status = U_ZERO_ERROR;
   1147         UnicodeString* target = (UnicodeString*)service.get("za_PPP", status);
   1148         confirmEqual("test zappp", root, target);
   1149         delete target;
   1150     }
   1151 
   1152     Locale loc = Locale::getDefault();
   1153     Locale::setDefault(Locale::getJapanese(), status);
   1154     {
   1155         UErrorCode status = U_ZERO_ERROR;
   1156         UnicodeString* target = (UnicodeString*)service.get("za_PPP", status);
   1157         confirmEqual("test with ja locale", japanese, target);
   1158         delete target;
   1159     }
   1160 
   1161     {
   1162         UErrorCode status = U_ZERO_ERROR;
   1163         UVector ids(uhash_deleteUnicodeString, uhash_compareUnicodeString, 0, status);
   1164         service.getVisibleIDs(ids, status);
   1165         logln("all visible ids:");
   1166         for (int i = 0; i < ids.size(); ++i) {
   1167             const UnicodeString* id = (const UnicodeString*)ids[i];
   1168             logln(*id);
   1169         }
   1170     }
   1171 
   1172     Locale::setDefault(loc, status);
   1173     {
   1174         UErrorCode status = U_ZERO_ERROR;
   1175         UVector ids(uhash_deleteUnicodeString, uhash_compareUnicodeString, 0, status);
   1176         service.getVisibleIDs(ids, status);
   1177         logln("all visible ids:");
   1178         for (int i = 0; i < ids.size(); ++i) {
   1179             const UnicodeString* id = (const UnicodeString*)ids[i];
   1180             logln(*id);
   1181         }
   1182     }
   1183 
   1184     {
   1185         UErrorCode status = U_ZERO_ERROR;
   1186         UnicodeString* target = (UnicodeString*)service.get("za_PPP", status);
   1187         confirmEqual("test with en locale", root, target);
   1188         delete target;
   1189     }
   1190 
   1191     {
   1192         UErrorCode status = U_ZERO_ERROR;
   1193         StringEnumeration* locales = service.getAvailableLocales();
   1194         if (locales) {
   1195             confirmIdentical("test available locales", locales->count(status), 6);
   1196             logln("locales: ");
   1197             {
   1198                 const char* p;
   1199                 while ((p = locales->next(NULL, status))) {
   1200                     logln(p);
   1201                 }
   1202             }
   1203             logln(" ");
   1204             delete locales;
   1205         } else {
   1206             errln("could not create available locales");
   1207         }
   1208     }
   1209 }
   1210 
   1211 class WrapFactory : public ICUServiceFactory {
   1212     public:
   1213     static const UnicodeString& getGreetingID() {
   1214       if (greetingID == NULL) {
   1215     greetingID = new UnicodeString("greeting");
   1216       }
   1217       return *greetingID;
   1218     }
   1219 
   1220   static void cleanup() {
   1221     delete greetingID;
   1222     greetingID = NULL;
   1223   }
   1224 
   1225     UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const {
   1226         if (U_SUCCESS(status)) {
   1227             UnicodeString temp;
   1228             if (key.currentID(temp).compare(getGreetingID()) == 0) {
   1229                 UnicodeString* previous = (UnicodeString*)service->getKey((ICUServiceKey&)key, NULL, this, status);
   1230                 if (previous) {
   1231                     previous->insert(0, "A different greeting: \"");
   1232                     previous->append("\"");
   1233                     return previous;
   1234                 }
   1235             }
   1236         }
   1237         return NULL;
   1238     }
   1239 
   1240     void updateVisibleIDs(Hashtable& result, UErrorCode& status) const {
   1241         if (U_SUCCESS(status)) {
   1242             result.put("greeting", (void*)this, status);
   1243         }
   1244     }
   1245 
   1246     UnicodeString& getDisplayName(const UnicodeString& id, const Locale& /* locale */, UnicodeString& result) const {
   1247         result.append("wrap '");
   1248         result.append(id);
   1249         result.append("'");
   1250         return result;
   1251     }
   1252 
   1253     /**
   1254      * UObject boilerplate.
   1255      */
   1256     static UClassID getStaticClassID() {
   1257         return (UClassID)&fgClassID;
   1258     }
   1259 
   1260     virtual UClassID getDynamicClassID() const {
   1261         return getStaticClassID();
   1262     }
   1263 
   1264     private:
   1265     static const char fgClassID;
   1266     static UnicodeString* greetingID;
   1267 };
   1268 
   1269 UnicodeString* WrapFactory::greetingID = NULL;
   1270 const char WrapFactory::fgClassID = '\0';
   1271 
   1272 void
   1273 ICUServiceTest::testWrapFactory()
   1274 {
   1275     UnicodeString* greeting = new UnicodeString("Hello There");
   1276     UnicodeString greetingID = "greeting";
   1277     UErrorCode status = U_ZERO_ERROR;
   1278     TestStringService service;
   1279     service.registerInstance(greeting, greetingID, status);
   1280 
   1281     {
   1282         UErrorCode status = U_ZERO_ERROR;
   1283         UnicodeString* result = (UnicodeString*)service.get(greetingID, status);
   1284         if (result) {
   1285             logln("test one: " + *result);
   1286             delete result;
   1287         }
   1288     }
   1289 
   1290     service.registerFactory(new WrapFactory(), status);
   1291     {
   1292         UErrorCode status = U_ZERO_ERROR;
   1293         UnicodeString* result = (UnicodeString*)service.get(greetingID, status);
   1294         UnicodeString target = "A different greeting: \"Hello There\"";
   1295         confirmEqual("wrap test: ", result, &target);
   1296         delete result;
   1297     }
   1298 
   1299     WrapFactory::cleanup();
   1300 }
   1301 
   1302   // misc coverage tests
   1303 void ICUServiceTest::testCoverage()
   1304 {
   1305   // ICUServiceKey
   1306   {
   1307     UnicodeString temp;
   1308     ICUServiceKey key("foobar");
   1309     logln("ID: " + key.getID());
   1310     logln("canonicalID: " + key.canonicalID(temp));
   1311     logln("currentID: " + key.currentID(temp.remove()));
   1312     logln("has fallback: " + UnicodeString(key.fallback() ? "true" : "false"));
   1313 
   1314     if (key.getDynamicClassID() != ICUServiceKey::getStaticClassID()) {
   1315       errln("service key rtt failed.");
   1316     }
   1317   }
   1318 
   1319   // SimpleFactory
   1320   {
   1321     UErrorCode status = U_ZERO_ERROR;
   1322 
   1323     UnicodeString* obj = new UnicodeString("An Object");
   1324     SimpleFactory* sf = new SimpleFactory(obj, "object");
   1325 
   1326     UnicodeString temp;
   1327     logln(sf->getDisplayName("object", Locale::getDefault(), temp));
   1328 
   1329     if (sf->getDynamicClassID() != SimpleFactory::getStaticClassID()) {
   1330       errln("simple factory rtti failed.");
   1331     }
   1332 
   1333     // ICUService
   1334         {
   1335                 TestStringService service;
   1336                 service.registerFactory(sf,     status);
   1337 
   1338                 {
   1339                         UnicodeString* result   = (UnicodeString*)service.get("object", status);
   1340                         if (result) {
   1341                                 logln("object is: "     + *result);
   1342                                 delete result;
   1343                         }       else {
   1344                                 errln("could not get object");
   1345                         }
   1346                 }
   1347         }
   1348   }
   1349 
   1350   // ICUServiceKey
   1351   {
   1352       UErrorCode status = U_ZERO_ERROR;
   1353           UnicodeString* howdy = new UnicodeString("Howdy");
   1354 
   1355           TestStringSimpleKeyService service;
   1356           service.registerInstance(howdy, "Greetings", status);
   1357           {
   1358                   UnicodeString* result = (UnicodeString*)service.get("Greetings",      status);
   1359                   if (result) {
   1360                           logln("object is: "   + *result);
   1361                           delete result;
   1362                   }     else {
   1363                           errln("could not get object");
   1364                   }
   1365           }
   1366 
   1367       UVector ids(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
   1368           // yuck, this is awkward to use.  All because we pass null in an overload.
   1369           // TODO: change this.
   1370           UnicodeString str("Greet");
   1371       service.getVisibleIDs(ids, &str, status);
   1372       confirmIdentical("no fallback of greet", ids.size(), 0);
   1373   }
   1374 
   1375   // ICULocaleService
   1376 
   1377   // LocaleKey
   1378   {
   1379     UnicodeString primary("en_US");
   1380     UnicodeString fallback("ja_JP");
   1381     UErrorCode status = U_ZERO_ERROR;
   1382     LocaleKey* key = LocaleKey::createWithCanonicalFallback(&primary, &fallback, status);
   1383 
   1384     if (key->getDynamicClassID() != LocaleKey::getStaticClassID()) {
   1385       errln("localekey rtti error");
   1386     }
   1387 
   1388     if (!key->isFallbackOf("en_US_FOOBAR")) {
   1389       errln("localekey should be fallback for en_US_FOOBAR");
   1390     }
   1391     if (!key->isFallbackOf("en_US")) {
   1392       errln("localekey should be fallback for en_US");
   1393     }
   1394     if (key->isFallbackOf("en")) {
   1395       errln("localekey should not be fallback for en");
   1396     }
   1397 
   1398     do {
   1399       Locale loc;
   1400       logln(UnicodeString("current locale: ") + key->currentLocale(loc).getName());
   1401       logln(UnicodeString("canonical locale: ") + key->canonicalLocale(loc).getName());
   1402       logln(UnicodeString("is fallback of en: ") + (key->isFallbackOf("en") ? "true" : " false"));
   1403     } while (key->fallback());
   1404     delete key;
   1405 
   1406     // LocaleKeyFactory
   1407     key = LocaleKey::createWithCanonicalFallback(&primary, &fallback, status);
   1408 
   1409     UnicodeString result;
   1410     LKFSubclass lkf(TRUE); // empty
   1411     Hashtable table;
   1412 
   1413     UObject *obj = lkf.create(*key, NULL, status);
   1414     logln("obj: " + UnicodeString(obj ? "obj" : "null"));
   1415     logln(lkf.getDisplayName("en_US", Locale::getDefault(), result));
   1416     lkf.updateVisibleIDs(table, status);
   1417     delete obj;
   1418     if (table.count() != 1) {
   1419       errln("visible IDs does not contain en_US");
   1420     }
   1421 
   1422     LKFSubclass invisibleLKF(FALSE);
   1423     obj = lkf.create(*key, NULL, status);
   1424     logln("obj: " + UnicodeString(obj ? "obj" : "null"));
   1425     logln(invisibleLKF.getDisplayName("en_US", Locale::getDefault(), result.remove()));
   1426     invisibleLKF.updateVisibleIDs(table, status);
   1427     if (table.count() != 0) {
   1428       errln("visible IDs contains en_US");
   1429     }
   1430     delete obj;
   1431     delete key;
   1432 
   1433         key = LocaleKey::createWithCanonicalFallback(&primary, &fallback, 123, status);
   1434         if (U_SUCCESS(status)) {
   1435                 UnicodeString str;
   1436                 key->currentDescriptor(str);
   1437                 key->parsePrefix(str);
   1438                 if (str != "123") {
   1439                         errln("did not get expected prefix");
   1440                 }
   1441                 delete key;
   1442         }
   1443 
   1444         // coverage, getSupportedIDs is either overridden or the calling method is
   1445         LKFSubclass0 lkFactory;
   1446         Hashtable table0;
   1447         lkFactory.updateVisibleIDs(table0, status);
   1448         if (table0.count() != 0) {
   1449                 errln("LKF returned non-empty hashtable");
   1450         }
   1451 
   1452 
   1453         // ResourceBundleFactory
   1454     key = LocaleKey::createWithCanonicalFallback(&primary, &fallback, status);
   1455         ICUResourceBundleFactory rbf;
   1456         UObject* icurb = rbf.create(*key, NULL, status);
   1457         if (icurb != NULL) {
   1458                 logln("got resource bundle for key");
   1459                 delete icurb;
   1460         }
   1461         delete key;
   1462   }
   1463 
   1464  #if 0
   1465  // ICUNotifier
   1466   ICUNotifier nf = new ICUNSubclass();
   1467   try {
   1468     nf.addListener(null);
   1469     errln("added null listener");
   1470   }
   1471   catch (NullPointerException e) {
   1472     logln(e.getMessage());
   1473   }
   1474   catch (Exception e) {
   1475     errln("got wrong exception");
   1476   }
   1477 
   1478   try {
   1479     nf.addListener(new WrongListener());
   1480     errln("added wrong listener");
   1481   }
   1482   catch (InternalError e) {
   1483     logln(e.getMessage());
   1484   }
   1485   catch (Exception e) {
   1486     errln("got wrong exception");
   1487   }
   1488 
   1489   try {
   1490     nf.removeListener(null);
   1491     errln("removed null listener");
   1492   }
   1493   catch (NullPointerException e) {
   1494     logln(e.getMessage());
   1495   }
   1496   catch (Exception e) {
   1497     errln("got wrong exception");
   1498   }
   1499 
   1500   nf.removeListener(new MyListener());
   1501   nf.notifyChanged();
   1502   nf.addListener(new MyListener());
   1503   nf.removeListener(new MyListener());
   1504 #endif
   1505 }
   1506 
   1507 
   1508 /* !UCONFIG_NO_SERVICE */
   1509 #endif
   1510 
   1511 
   1512