• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
acceptsListener(const EventListener &) const27     UBool acceptsListener(const EventListener& /*l*/) const {
28         return TRUE;
29         // return l instanceof MyListener;
30     }
31 
notifyListener(EventListener &) const32     virtual void notifyListener(EventListener& /*l*/) const {
33     }
34 };
35 
36 // This factory does nothing
37 class LKFSubclass0 : public LocaleKeyFactory {
38 public:
LKFSubclass0()39         LKFSubclass0()
40                 : LocaleKeyFactory(VISIBLE, "LKFSubclass0")
41         {
42         }
43 };
44 
45 class LKFSubclass : public LocaleKeyFactory {
46     Hashtable table;
47 
48     public:
LKFSubclass(UBool visible)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:
getSupportedIDs(UErrorCode &) const57     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 
Integer(int32_t val)66     Integer(int32_t val) : _val(val) {
67     }
68 
Integer(const Integer & rhs)69     Integer(const Integer& rhs) : UObject(rhs), _val(rhs._val) {
70     }
~Integer()71     virtual ~Integer() {
72     }
73 
74     public:
75     /**
76      * UObject boilerplate.
77      */
getStaticClassID()78     static UClassID getStaticClassID() {
79         return (UClassID)&fgClassID;
80     }
81 
getDynamicClassID() const82     virtual UClassID getDynamicClassID() const {
83         return getStaticClassID();
84     }
85 
operator ==(const UObject & other) const86     virtual UBool operator==(const UObject& other) const
87     {
88         return typeid(*this) == typeid(other) &&
89             _val == ((Integer&)other)._val;
90     }
91 
92     public:
debug(UnicodeString & result) const93     virtual UnicodeString& debug(UnicodeString& result) const {
94         debugClass(result);
95         result.append(" val: ");
96         result.append(_val);
97         return result;
98     }
99 
debugClass(UnicodeString & result) const100     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:
createKey(const UnicodeString * id,UErrorCode & status) const113     ICUServiceKey* createKey(const UnicodeString* id, UErrorCode& status) const {
114         return LocaleKey::createWithCanonicalFallback(id, NULL, status); // no fallback locale
115     }
116 
createSimpleFactory(UObject * obj,const UnicodeString & id,UBool visible,UErrorCode & status)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 
cloneInstance(UObject * instance) const126     virtual UObject* cloneInstance(UObject* instance) const {
127         return instance ? new Integer(*(Integer*)instance) : NULL;
128     }
129 };
130 
131 
ICUServiceTest()132 ICUServiceTest::ICUServiceTest() {
133 }
134 
~ICUServiceTest()135 ICUServiceTest::~ICUServiceTest() {
136 }
137 
138 void
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)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 
append(UnicodeString & result,const UObject * obj)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&
lrmsg(UnicodeString & result,const UnicodeString & message,const UObject * lhs,const UObject * rhs) const179 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
confirmBoolean(const UnicodeString & message,UBool val)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
confirmEqual(const UnicodeString & message,const Integer * lhs,const Integer * rhs)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
confirmEqual(const UnicodeString & message,const UnicodeString * lhs,const UnicodeString * rhs)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
confirmEqual(const UnicodeString & message,const Locale * lhs,const Locale * rhs)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
confirmStringsEqual(const UnicodeString & message,const UnicodeString & lhs,const UnicodeString & rhs)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
confirmIdentical(const UnicodeString & message,const UObject * lhs,const UObject * rhs)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
confirmIdentical(const UnicodeString & message,int32_t lhs,int32_t rhs)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
msgstr(const UnicodeString & message,UObject * obj,UBool err)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
testAPI_One()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 
createSimpleFactory(UObject * obj,const UnicodeString & id,UBool visible,UErrorCode & status)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 
cloneInstance(UObject * instance) const490     virtual UObject* cloneInstance(UObject* instance) const {
491         return instance ? new UnicodeString(*(UnicodeString*)instance) : NULL;
492     }
493 };
494 
495 class TestStringService : public ICUService {
496     public:
createKey(const UnicodeString * id,UErrorCode & status) const497     ICUServiceKey* createKey(const UnicodeString* id, UErrorCode& status) const {
498         return LocaleKey::createWithCanonicalFallback(id, NULL, status); // no fallback locale
499     }
500 
createSimpleFactory(UObject * obj,const UnicodeString & id,UBool visible,UErrorCode &)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 
cloneInstance(UObject * instance) const510     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:
create(const ICUServiceKey & key,const ICUService *,UErrorCode &) const519     virtual UObject* create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& /* status */) const {
520         return new UnicodeString(key.getID());
521     }
522 
updateVisibleIDs(Hashtable &,UErrorCode &) const523     virtual void updateVisibleIDs(Hashtable& /*result*/, UErrorCode& /*status*/) const {
524         // do nothing
525     }
526 
getDisplayName(const UnicodeString &,const Locale &,UnicodeString & result) const527     virtual UnicodeString& getDisplayName(const UnicodeString& /*id*/, const Locale& /*locale*/, UnicodeString& result) const {
528         // do nothing
529         return result;
530     }
531 
getStaticClassID()532     static UClassID getStaticClassID() {
533         return (UClassID)&fgClassID;
534     }
535 
getDynamicClassID() const536     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:
TestMultipleKeyStringFactory(const UnicodeString ids[],int32_t count,const UnicodeString & factoryID)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 
~TestMultipleKeyStringFactory()562     ~TestMultipleKeyStringFactory() {
563     }
564 
create(const ICUServiceKey & key,const ICUService *,UErrorCode & status) const565     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 
updateVisibleIDs(Hashtable & result,UErrorCode & status) const581     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 
getDisplayName(const UnicodeString & id,const Locale & locale,UnicodeString & result) const589     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 
getStaticClassID()608     static UClassID getStaticClassID() {
609         return (UClassID)&fgClassID;
610     }
611 
getDynamicClassID() const612     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
testAPI_Two()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 
cleanup(void)828     static void cleanup(void) {
829       delete supportedIDs;
830       supportedIDs = NULL;
831     }
832 
getSupportedIDs(UErrorCode & status) const833     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 
getDisplayName(const UnicodeString & id,const Locale & locale,UnicodeString & result) const848     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
testRBF()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:
SimpleListener(ICUServiceTest * test,const UnicodeString & name)957     SimpleListener(ICUServiceTest* test, const UnicodeString& name) : _test(test), _n(0), _name(name) {}
958 
serviceChanged(const ICUService & service) const959     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
testNotification()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:
cloneInstance(UObject * instance) const1031     virtual UObject* cloneInstance(UObject* instance) const {
1032         return instance ? new UnicodeString(*(UnicodeString*)instance) : NULL;
1033     }
1034 };
1035 
testLocale()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:
getGreetingID()1217     static const UnicodeString& getGreetingID() {
1218       if (greetingID == NULL) {
1219     greetingID = new UnicodeString("greeting");
1220       }
1221       return *greetingID;
1222     }
1223 
cleanup()1224   static void cleanup() {
1225     delete greetingID;
1226     greetingID = NULL;
1227   }
1228 
create(const ICUServiceKey & key,const ICUService * service,UErrorCode & status) const1229     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 
updateVisibleIDs(Hashtable & result,UErrorCode & status) const1244     void updateVisibleIDs(Hashtable& result, UErrorCode& status) const {
1245         if (U_SUCCESS(status)) {
1246             result.put("greeting", (void*)this, status);
1247         }
1248     }
1249 
getDisplayName(const UnicodeString & id,const Locale &,UnicodeString & result) const1250     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      */
getStaticClassID()1260     static UClassID getStaticClassID() {
1261         return (UClassID)&fgClassID;
1262     }
1263 
getDynamicClassID() const1264     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
testWrapFactory()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
testCoverage()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