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