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