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