Home | History | Annotate | Download | only in intltest
      1 /**
      2  *******************************************************************************
      3  * Copyright (C) 2001-2010, International Business Machines Corporation and
      4  * others. All Rights Reserved.
      5  *******************************************************************************
      6  */
      7 
      8 #include <typeinfo>  // 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(uhash_deleteUnicodeString, 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(uhash_deleteUnicodeString, 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(uhash_deleteUnicodeString, 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(uhash_deleteUnicodeString, 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(uhash_deleteUnicodeString, 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     int32_t _n;
    954     UnicodeString _name;
    955 
    956     public:
    957     SimpleListener(ICUServiceTest* test, const UnicodeString& name) : _test(test), _n(0), _name(name) {}
    958 
    959     virtual void serviceChanged(const ICUService& service) const {
    960         UnicodeString serviceName = "listener ";
    961         serviceName.append(_name);
    962         serviceName.append(" n++");
    963         serviceName.append(" service changed: " );
    964         service.getName(serviceName);
    965         _test->logln(serviceName);
    966     }
    967 };
    968 
    969 void
    970 ICUServiceTest::testNotification()
    971 {
    972     SimpleListener one(this, "one");
    973     SimpleListener two(this, "two");
    974     {
    975         UErrorCode status = U_ZERO_ERROR;
    976 
    977         logln("simple registration notification");
    978         TestStringService ls;
    979         ls.addListener(&one, status);
    980         ls.addListener(&two, status);
    981 
    982         logln("registering foo... ");
    983         ls.registerInstance(new UnicodeString("Foo"), "en_FOO", status);
    984         logln("registering bar... ");
    985         ls.registerInstance(new UnicodeString("Bar"), "en_BAR", status);
    986         logln("getting foo...");
    987         UnicodeString* result = (UnicodeString*)ls.get("en_FOO", status);
    988         logln(*result);
    989         delete result;
    990 
    991         logln("removing listener 2...");
    992         ls.removeListener(&two, status);
    993         logln("registering baz...");
    994         ls.registerInstance(new UnicodeString("Baz"), "en_BAZ", status);
    995         logln("removing listener 1");
    996         ls.removeListener(&one, status);
    997         logln("registering burp...");
    998         ls.registerInstance(new UnicodeString("Burp"), "en_BURP", status);
    999 
   1000         // should only get one notification even if register multiple times
   1001         logln("... trying multiple registration");
   1002         ls.addListener(&one, status);
   1003         ls.addListener(&one, status);
   1004         ls.addListener(&one, status);
   1005         ls.addListener(&two, status);
   1006         ls.registerInstance(new UnicodeString("Foo"), "en_FOO", status);
   1007         logln("... registered foo");
   1008     }
   1009 #if 0
   1010     // same thread, so we can't callback within notification, unlike Java
   1011     ServiceListener l3 = new ServiceListener() {
   1012 private int n;
   1013 public void serviceChanged(ICUService s) {
   1014     logln("listener 3 report " + n++ + " service changed...");
   1015     if (s.get("en_BOINK") == null) { // don't recurse on ourselves!!!
   1016         logln("registering boink...");
   1017         s.registerInstance("boink", "en_BOINK");
   1018     }
   1019 }
   1020     };
   1021     ls.addListener(l3);
   1022     logln("registering boo...");
   1023     ls.registerInstance("Boo", "en_BOO");
   1024 #endif
   1025 
   1026     logln("...done");
   1027 }
   1028 
   1029 class TestStringLocaleService : public ICULocaleService {
   1030     public:
   1031     virtual UObject* cloneInstance(UObject* instance) const {
   1032         return instance ? new UnicodeString(*(UnicodeString*)instance) : NULL;
   1033     }
   1034 };
   1035 
   1036 void ICUServiceTest::testLocale() {
   1037     UErrorCode status = U_ZERO_ERROR;
   1038     TestStringLocaleService service;
   1039 
   1040     UnicodeString* root = new UnicodeString("root");
   1041     UnicodeString* german = new UnicodeString("german");
   1042     UnicodeString* germany = new UnicodeString("german_Germany");
   1043     UnicodeString* japanese = new UnicodeString("japanese");
   1044     UnicodeString* japan = new UnicodeString("japanese_Japan");
   1045 
   1046     service.registerInstance(root, "", status);
   1047     service.registerInstance(german, "de", status);
   1048     service.registerInstance(germany, Locale::getGermany(), status);
   1049     service.registerInstance(japanese, (UnicodeString)"ja", TRUE, status);
   1050     service.registerInstance(japan, Locale::getJapan(), status);
   1051 
   1052     {
   1053         UErrorCode status = U_ZERO_ERROR;
   1054         UnicodeString* target = (UnicodeString*)service.get("de_US", status);
   1055         confirmEqual("test de_US", german, target);
   1056         delete target;
   1057     }
   1058 
   1059     {
   1060         UErrorCode status = U_ZERO_ERROR;
   1061         UnicodeString* target = (UnicodeString*)service.get("de_US", LocaleKey::KIND_ANY, status);
   1062         confirmEqual("test de_US 2", german, target);
   1063         delete target;
   1064     }
   1065 
   1066     {
   1067         UErrorCode status = U_ZERO_ERROR;
   1068         UnicodeString* target = (UnicodeString*)service.get("de_US", 1234, status);
   1069         confirmEqual("test de_US 3", german, target);
   1070         delete target;
   1071     }
   1072 
   1073     {
   1074         UErrorCode status = U_ZERO_ERROR;
   1075         Locale actualReturn;
   1076         UnicodeString* target = (UnicodeString*)service.get("de_US", &actualReturn, status);
   1077         confirmEqual("test de_US 5", german, target);
   1078         confirmEqual("test de_US 6", &actualReturn, &Locale::getGerman());
   1079         delete target;
   1080     }
   1081 
   1082     {
   1083         UErrorCode status = U_ZERO_ERROR;
   1084         Locale actualReturn;
   1085         UnicodeString* target = (UnicodeString*)service.get("de_US", LocaleKey::KIND_ANY, &actualReturn, status);
   1086         confirmEqual("test de_US 7", &actualReturn, &Locale::getGerman());
   1087         delete target;
   1088     }
   1089 
   1090     {
   1091         UErrorCode status = U_ZERO_ERROR;
   1092         Locale actualReturn;
   1093         UnicodeString* target = (UnicodeString*)service.get("de_US", 1234, &actualReturn, status);
   1094         confirmEqual("test de_US 8", german, target);
   1095         confirmEqual("test de_US 9", &actualReturn, &Locale::getGerman());
   1096         delete target;
   1097     }
   1098 
   1099     UnicodeString* one = new UnicodeString("one/de_US");
   1100     UnicodeString* two = new UnicodeString("two/de_US");
   1101 
   1102     service.registerInstance(one, Locale("de_US"), 1, status);
   1103     service.registerInstance(two, Locale("de_US"), 2, status);
   1104 
   1105     {
   1106         UErrorCode status = U_ZERO_ERROR;
   1107         UnicodeString* target = (UnicodeString*)service.get("de_US", 1, status);
   1108         confirmEqual("test de_US kind 1", one, target);
   1109         delete target;
   1110     }
   1111 
   1112     {
   1113         UErrorCode status = U_ZERO_ERROR;
   1114         UnicodeString* target = (UnicodeString*)service.get("de_US", 2, status);
   1115         confirmEqual("test de_US kind 2", two, target);
   1116         delete target;
   1117     }
   1118 
   1119     {
   1120         UErrorCode status = U_ZERO_ERROR;
   1121         UnicodeString* target = (UnicodeString*)service.get("de_US", status);
   1122         confirmEqual("test de_US kind 3", german, target);
   1123         delete target;
   1124     }
   1125 
   1126     {
   1127         UErrorCode status = U_ZERO_ERROR;
   1128         UnicodeString english = "en";
   1129         Locale localeResult;
   1130         UnicodeString result;
   1131         LocaleKey* lkey = LocaleKey::createWithCanonicalFallback(&english, NULL, 1234, status);
   1132         logln("lkey prefix: " + lkey->prefix(result));
   1133         result.remove();
   1134         logln("lkey descriptor: " + lkey->currentDescriptor(result));
   1135         result.remove();
   1136         logln(UnicodeString("lkey current locale: ") + lkey->currentLocale(localeResult).getName());
   1137         result.remove();
   1138 
   1139         lkey->fallback();
   1140         logln("lkey descriptor 2: " + lkey->currentDescriptor(result));
   1141         result.remove();
   1142 
   1143         lkey->fallback();
   1144         logln("lkey descriptor 3: " + lkey->currentDescriptor(result));
   1145         result.remove();
   1146         delete lkey; // tentatively weiv
   1147     }
   1148 
   1149     {
   1150         UErrorCode status = U_ZERO_ERROR;
   1151         UnicodeString* target = (UnicodeString*)service.get("za_PPP", status);
   1152         confirmEqual("test zappp", root, target);
   1153         delete target;
   1154     }
   1155 
   1156     Locale loc = Locale::getDefault();
   1157     Locale::setDefault(Locale::getJapanese(), status);
   1158     {
   1159         UErrorCode status = U_ZERO_ERROR;
   1160         UnicodeString* target = (UnicodeString*)service.get("za_PPP", status);
   1161         confirmEqual("test with ja locale", japanese, target);
   1162         delete target;
   1163     }
   1164 
   1165     {
   1166         UErrorCode status = U_ZERO_ERROR;
   1167         UVector ids(uhash_deleteUnicodeString, uhash_compareUnicodeString, 0, status);
   1168         service.getVisibleIDs(ids, status);
   1169         logln("all visible ids:");
   1170         for (int i = 0; i < ids.size(); ++i) {
   1171             const UnicodeString* id = (const UnicodeString*)ids[i];
   1172             logln(*id);
   1173         }
   1174     }
   1175 
   1176     Locale::setDefault(loc, status);
   1177     {
   1178         UErrorCode status = U_ZERO_ERROR;
   1179         UVector ids(uhash_deleteUnicodeString, uhash_compareUnicodeString, 0, status);
   1180         service.getVisibleIDs(ids, status);
   1181         logln("all visible ids:");
   1182         for (int i = 0; i < ids.size(); ++i) {
   1183             const UnicodeString* id = (const UnicodeString*)ids[i];
   1184             logln(*id);
   1185         }
   1186     }
   1187 
   1188     {
   1189         UErrorCode status = U_ZERO_ERROR;
   1190         UnicodeString* target = (UnicodeString*)service.get("za_PPP", status);
   1191         confirmEqual("test with en locale", root, target);
   1192         delete target;
   1193     }
   1194 
   1195     {
   1196         UErrorCode status = U_ZERO_ERROR;
   1197         StringEnumeration* locales = service.getAvailableLocales();
   1198         if (locales) {
   1199             confirmIdentical("test available locales", locales->count(status), 6);
   1200             logln("locales: ");
   1201             {
   1202                 const char* p;
   1203                 while ((p = locales->next(NULL, status))) {
   1204                     logln(p);
   1205                 }
   1206             }
   1207             logln(" ");
   1208             delete locales;
   1209         } else {
   1210             errln("could not create available locales");
   1211         }
   1212     }
   1213 }
   1214 
   1215 class WrapFactory : public ICUServiceFactory {
   1216     public:
   1217     static const UnicodeString& getGreetingID() {
   1218       if (greetingID == NULL) {
   1219     greetingID = new UnicodeString("greeting");
   1220       }
   1221       return *greetingID;
   1222     }
   1223 
   1224   static void cleanup() {
   1225     delete greetingID;
   1226     greetingID = NULL;
   1227   }
   1228 
   1229     UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const {
   1230         if (U_SUCCESS(status)) {
   1231             UnicodeString temp;
   1232             if (key.currentID(temp).compare(getGreetingID()) == 0) {
   1233                 UnicodeString* previous = (UnicodeString*)service->getKey((ICUServiceKey&)key, NULL, this, status);
   1234                 if (previous) {
   1235                     previous->insert(0, "A different greeting: \"");
   1236                     previous->append("\"");
   1237                     return previous;
   1238                 }
   1239             }
   1240         }
   1241         return NULL;
   1242     }
   1243 
   1244     void updateVisibleIDs(Hashtable& result, UErrorCode& status) const {
   1245         if (U_SUCCESS(status)) {
   1246             result.put("greeting", (void*)this, status);
   1247         }
   1248     }
   1249 
   1250     UnicodeString& getDisplayName(const UnicodeString& id, const Locale& /* locale */, UnicodeString& result) const {
   1251         result.append("wrap '");
   1252         result.append(id);
   1253         result.append("'");
   1254         return result;
   1255     }
   1256 
   1257     /**
   1258      * UObject boilerplate.
   1259      */
   1260     static UClassID getStaticClassID() {
   1261         return (UClassID)&fgClassID;
   1262     }
   1263 
   1264     virtual UClassID getDynamicClassID() const {
   1265         return getStaticClassID();
   1266     }
   1267 
   1268     private:
   1269     static const char fgClassID;
   1270     static UnicodeString* greetingID;
   1271 };
   1272 
   1273 UnicodeString* WrapFactory::greetingID = NULL;
   1274 const char WrapFactory::fgClassID = '\0';
   1275 
   1276 void
   1277 ICUServiceTest::testWrapFactory()
   1278 {
   1279     UnicodeString* greeting = new UnicodeString("Hello There");
   1280     UnicodeString greetingID = "greeting";
   1281     UErrorCode status = U_ZERO_ERROR;
   1282     TestStringService service;
   1283     service.registerInstance(greeting, greetingID, status);
   1284 
   1285     {
   1286         UErrorCode status = U_ZERO_ERROR;
   1287         UnicodeString* result = (UnicodeString*)service.get(greetingID, status);
   1288         if (result) {
   1289             logln("test one: " + *result);
   1290             delete result;
   1291         }
   1292     }
   1293 
   1294     service.registerFactory(new WrapFactory(), status);
   1295     {
   1296         UErrorCode status = U_ZERO_ERROR;
   1297         UnicodeString* result = (UnicodeString*)service.get(greetingID, status);
   1298         UnicodeString target = "A different greeting: \"Hello There\"";
   1299         confirmEqual("wrap test: ", result, &target);
   1300         delete result;
   1301     }
   1302 
   1303     WrapFactory::cleanup();
   1304 }
   1305 
   1306   // misc coverage tests
   1307 void ICUServiceTest::testCoverage()
   1308 {
   1309   // ICUServiceKey
   1310   {
   1311     UnicodeString temp;
   1312     ICUServiceKey key("foobar");
   1313     logln("ID: " + key.getID());
   1314     logln("canonicalID: " + key.canonicalID(temp));
   1315     logln("currentID: " + key.currentID(temp.remove()));
   1316     logln("has fallback: " + UnicodeString(key.fallback() ? "true" : "false"));
   1317 
   1318     if (key.getDynamicClassID() != ICUServiceKey::getStaticClassID()) {
   1319       errln("service key rtt failed.");
   1320     }
   1321   }
   1322 
   1323   // SimpleFactory
   1324   {
   1325     UErrorCode status = U_ZERO_ERROR;
   1326 
   1327     UnicodeString* obj = new UnicodeString("An Object");
   1328     SimpleFactory* sf = new SimpleFactory(obj, "object");
   1329 
   1330     UnicodeString temp;
   1331     logln(sf->getDisplayName("object", Locale::getDefault(), temp));
   1332 
   1333     if (sf->getDynamicClassID() != SimpleFactory::getStaticClassID()) {
   1334       errln("simple factory rtti failed.");
   1335     }
   1336 
   1337     // ICUService
   1338         {
   1339                 TestStringService service;
   1340                 service.registerFactory(sf,     status);
   1341 
   1342                 {
   1343                         UnicodeString* result   = (UnicodeString*)service.get("object", status);
   1344                         if (result) {
   1345                                 logln("object is: "     + *result);
   1346                                 delete result;
   1347                         }       else {
   1348                                 errln("could not get object");
   1349                         }
   1350                 }
   1351         }
   1352   }
   1353 
   1354   // ICUServiceKey
   1355   {
   1356       UErrorCode status = U_ZERO_ERROR;
   1357           UnicodeString* howdy = new UnicodeString("Howdy");
   1358 
   1359           TestStringSimpleKeyService service;
   1360           service.registerInstance(howdy, "Greetings", status);
   1361           {
   1362                   UnicodeString* result = (UnicodeString*)service.get("Greetings",      status);
   1363                   if (result) {
   1364                           logln("object is: "   + *result);
   1365                           delete result;
   1366                   }     else {
   1367                           errln("could not get object");
   1368                   }
   1369           }
   1370 
   1371       UVector ids(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
   1372           // yuck, this is awkward to use.  All because we pass null in an overload.
   1373           // TODO: change this.
   1374           UnicodeString str("Greet");
   1375       service.getVisibleIDs(ids, &str, status);
   1376       confirmIdentical("no fallback of greet", ids.size(), 0);
   1377   }
   1378 
   1379   // ICULocaleService
   1380 
   1381   // LocaleKey
   1382   {
   1383     UnicodeString primary("en_US");
   1384     UnicodeString fallback("ja_JP");
   1385     UErrorCode status = U_ZERO_ERROR;
   1386     LocaleKey* key = LocaleKey::createWithCanonicalFallback(&primary, &fallback, status);
   1387 
   1388     if (key->getDynamicClassID() != LocaleKey::getStaticClassID()) {
   1389       errln("localekey rtti error");
   1390     }
   1391 
   1392     if (!key->isFallbackOf("en_US_FOOBAR")) {
   1393       errln("localekey should be fallback for en_US_FOOBAR");
   1394     }
   1395     if (!key->isFallbackOf("en_US")) {
   1396       errln("localekey should be fallback for en_US");
   1397     }
   1398     if (key->isFallbackOf("en")) {
   1399       errln("localekey should not be fallback for en");
   1400     }
   1401 
   1402     do {
   1403       Locale loc;
   1404       logln(UnicodeString("current locale: ") + key->currentLocale(loc).getName());
   1405       logln(UnicodeString("canonical locale: ") + key->canonicalLocale(loc).getName());
   1406       logln(UnicodeString("is fallback of en: ") + (key->isFallbackOf("en") ? "true" : " false"));
   1407     } while (key->fallback());
   1408     delete key;
   1409 
   1410     // LocaleKeyFactory
   1411     key = LocaleKey::createWithCanonicalFallback(&primary, &fallback, status);
   1412 
   1413     UnicodeString result;
   1414     LKFSubclass lkf(TRUE); // empty
   1415     Hashtable table;
   1416 
   1417     UObject *obj = lkf.create(*key, NULL, status);
   1418     logln("obj: " + UnicodeString(obj ? "obj" : "null"));
   1419     logln(lkf.getDisplayName("en_US", Locale::getDefault(), result));
   1420     lkf.updateVisibleIDs(table, status);
   1421     delete obj;
   1422     if (table.count() != 1) {
   1423       errln("visible IDs does not contain en_US");
   1424     }
   1425 
   1426     LKFSubclass invisibleLKF(FALSE);
   1427     obj = lkf.create(*key, NULL, status);
   1428     logln("obj: " + UnicodeString(obj ? "obj" : "null"));
   1429     logln(invisibleLKF.getDisplayName("en_US", Locale::getDefault(), result.remove()));
   1430     invisibleLKF.updateVisibleIDs(table, status);
   1431     if (table.count() != 0) {
   1432       errln("visible IDs contains en_US");
   1433     }
   1434     delete obj;
   1435     delete key;
   1436 
   1437         key = LocaleKey::createWithCanonicalFallback(&primary, &fallback, 123, status);
   1438         if (U_SUCCESS(status)) {
   1439                 UnicodeString str;
   1440                 key->currentDescriptor(str);
   1441                 key->parsePrefix(str);
   1442                 if (str != "123") {
   1443                         errln("did not get expected prefix");
   1444                 }
   1445                 delete key;
   1446         }
   1447 
   1448         // coverage, getSupportedIDs is either overridden or the calling method is
   1449         LKFSubclass0 lkFactory;
   1450         Hashtable table0;
   1451         lkFactory.updateVisibleIDs(table0, status);
   1452         if (table0.count() != 0) {
   1453                 errln("LKF returned non-empty hashtable");
   1454         }
   1455 
   1456 
   1457         // ResourceBundleFactory
   1458     key = LocaleKey::createWithCanonicalFallback(&primary, &fallback, status);
   1459         ICUResourceBundleFactory rbf;
   1460         UObject* icurb = rbf.create(*key, NULL, status);
   1461         if (icurb != NULL) {
   1462                 logln("got resource bundle for key");
   1463                 delete icurb;
   1464         }
   1465         delete key;
   1466   }
   1467 
   1468  #if 0
   1469  // ICUNotifier
   1470   ICUNotifier nf = new ICUNSubclass();
   1471   try {
   1472     nf.addListener(null);
   1473     errln("added null listener");
   1474   }
   1475   catch (NullPointerException e) {
   1476     logln(e.getMessage());
   1477   }
   1478   catch (Exception e) {
   1479     errln("got wrong exception");
   1480   }
   1481 
   1482   try {
   1483     nf.addListener(new WrongListener());
   1484     errln("added wrong listener");
   1485   }
   1486   catch (InternalError e) {
   1487     logln(e.getMessage());
   1488   }
   1489   catch (Exception e) {
   1490     errln("got wrong exception");
   1491   }
   1492 
   1493   try {
   1494     nf.removeListener(null);
   1495     errln("removed null listener");
   1496   }
   1497   catch (NullPointerException e) {
   1498     logln(e.getMessage());
   1499   }
   1500   catch (Exception e) {
   1501     errln("got wrong exception");
   1502   }
   1503 
   1504   nf.removeListener(new MyListener());
   1505   nf.notifyChanged();
   1506   nf.addListener(new MyListener());
   1507   nf.removeListener(new MyListener());
   1508 #endif
   1509 }
   1510 
   1511 
   1512 /* !UCONFIG_NO_SERVICE */
   1513 #endif
   1514 
   1515 
   1516