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
19class MyListener : public EventListener {
20};
21
22class WrongListener : public EventListener {
23};
24
25class ICUNSubclass : public ICUNotifier {
26    public:
27    UBool acceptsListener(const EventListener& /*l*/) const {
28        return TRUE;
29        // return l instanceof MyListener;
30    }
31
32    virtual void notifyListener(EventListener& /*l*/) const {
33    }
34};
35
36// This factory does nothing
37class LKFSubclass0 : public LocaleKeyFactory {
38public:
39        LKFSubclass0()
40                : LocaleKeyFactory(VISIBLE, "LKFSubclass0")
41        {
42        }
43};
44
45class LKFSubclass : public LocaleKeyFactory {
46    Hashtable table;
47
48    public:
49    LKFSubclass(UBool visible)
50        : LocaleKeyFactory(visible ? VISIBLE : INVISIBLE, "LKFSubclass")
51    {
52        UErrorCode status = U_ZERO_ERROR;
53        table.put("en_US", this, status);
54    }
55
56    protected:
57    virtual const Hashtable* getSupportedIDs(UErrorCode &/*status*/) const {
58        return &table;
59    }
60};
61
62class Integer : public UObject {
63    public:
64    const int32_t _val;
65
66    Integer(int32_t val) : _val(val) {
67    }
68
69    Integer(const Integer& rhs) : UObject(rhs), _val(rhs._val) {
70    }
71    virtual ~Integer() {
72    }
73
74    public:
75    /**
76     * UObject boilerplate.
77     */
78    static UClassID getStaticClassID() {
79        return (UClassID)&fgClassID;
80    }
81
82    virtual UClassID getDynamicClassID() const {
83        return getStaticClassID();
84    }
85
86    virtual UBool operator==(const UObject& other) const
87    {
88        return typeid(*this) == typeid(other) &&
89            _val == ((Integer&)other)._val;
90    }
91
92    public:
93    virtual UnicodeString& debug(UnicodeString& result) const {
94        debugClass(result);
95        result.append(" val: ");
96        result.append(_val);
97        return result;
98    }
99
100    virtual UnicodeString& debugClass(UnicodeString& result) const {
101        return result.append("Integer");
102    }
103
104    private:
105    static const char fgClassID;
106};
107
108const char Integer::fgClassID = '\0';
109
110// use locale keys
111class TestIntegerService : public ICUService {
112    public:
113    ICUServiceKey* createKey(const UnicodeString* id, UErrorCode& status) const {
114        return LocaleKey::createWithCanonicalFallback(id, NULL, status); // no fallback locale
115    }
116
117    virtual ICUServiceFactory* createSimpleFactory(UObject* obj, const UnicodeString& id, UBool visible, UErrorCode& status)
118    {
119        Integer* i;
120        if (U_SUCCESS(status) && obj && (i = dynamic_cast<Integer*>(obj)) != NULL) {
121            return new SimpleFactory(i, id, visible);
122        }
123        return NULL;
124    }
125
126    virtual UObject* cloneInstance(UObject* instance) const {
127        return instance ? new Integer(*(Integer*)instance) : NULL;
128    }
129};
130
131
132ICUServiceTest::ICUServiceTest() {
133}
134
135ICUServiceTest::~ICUServiceTest() {
136}
137
138void
139ICUServiceTest::runIndexedTest(int32_t index, UBool exec, const char* &name,
140char* /*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
154UnicodeString 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
178UnicodeString&
179ICUServiceTest::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
189void
190ICUServiceTest::confirmBoolean(const UnicodeString& message, UBool val)
191{
192    if (val) {
193        logln(message);
194    } else {
195        errln(message);
196    }
197}
198
199#if 0
200void
201ICUServiceTest::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
217void
218ICUServiceTest::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
234void
235ICUServiceTest::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
251void
252ICUServiceTest::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
270void
271ICUServiceTest::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
289void
290ICUServiceTest::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
301void
302ICUServiceTest::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
311void
312ICUServiceTest::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
323void
324ICUServiceTest::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 */
475class TestStringSimpleKeyService : public ICUService {
476public:
477
478        virtual ICUServiceFactory* createSimpleFactory(UObject* obj, const UnicodeString& id, UBool visible, UErrorCode& status)
479    {
480                // We could put this type check into ICUService itself, but we'd still
481                // have to implement cloneInstance.  Otherwise we could just tell the service
482                // what the object type is when we create it, and the default implementation
483                // could handle everything for us.  Phooey.
484        if (obj && dynamic_cast<UnicodeString*>(obj) != NULL) {
485                        return ICUService::createSimpleFactory(obj, id, visible, status);
486        }
487        return NULL;
488    }
489
490    virtual UObject* cloneInstance(UObject* instance) const {
491        return instance ? new UnicodeString(*(UnicodeString*)instance) : NULL;
492    }
493};
494
495class TestStringService : public ICUService {
496    public:
497    ICUServiceKey* createKey(const UnicodeString* id, UErrorCode& status) const {
498        return LocaleKey::createWithCanonicalFallback(id, NULL, status); // no fallback locale
499    }
500
501  virtual ICUServiceFactory* createSimpleFactory(UObject* obj, const UnicodeString& id, UBool visible, UErrorCode& /* status */)
502    {
503        UnicodeString* s;
504        if (obj && (s = dynamic_cast<UnicodeString*>(obj)) != NULL) {
505            return new SimpleFactory(s, id, visible);
506        }
507        return NULL;
508    }
509
510    virtual UObject* cloneInstance(UObject* instance) const {
511        return instance ? new UnicodeString(*(UnicodeString*)instance) : NULL;
512    }
513};
514
515// this creates a string for any id, but doesn't report anything
516class AnonymousStringFactory : public ICUServiceFactory
517{
518    public:
519    virtual UObject* create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& /* status */) const {
520        return new UnicodeString(key.getID());
521    }
522
523    virtual void updateVisibleIDs(Hashtable& /*result*/, UErrorCode& /*status*/) const {
524        // do nothing
525    }
526
527    virtual UnicodeString& getDisplayName(const UnicodeString& /*id*/, const Locale& /*locale*/, UnicodeString& result) const {
528        // do nothing
529        return result;
530    }
531
532    static UClassID getStaticClassID() {
533        return (UClassID)&fgClassID;
534    }
535
536    virtual UClassID getDynamicClassID() const {
537        return getStaticClassID();
538    }
539
540    private:
541    static const char fgClassID;
542};
543
544const char AnonymousStringFactory::fgClassID = '\0';
545
546class TestMultipleKeyStringFactory : public ICUServiceFactory {
547    UErrorCode _status;
548    UVector _ids;
549    UnicodeString _factoryID;
550
551    public:
552    TestMultipleKeyStringFactory(const UnicodeString ids[], int32_t count, const UnicodeString& factoryID)
553        : _status(U_ZERO_ERROR)
554        , _ids(uhash_deleteUnicodeString, uhash_compareUnicodeString, count, _status)
555        , _factoryID(factoryID + ": ")
556    {
557        for (int i = 0; i < count; ++i) {
558            _ids.addElement(new UnicodeString(ids[i]), _status);
559        }
560    }
561
562    ~TestMultipleKeyStringFactory() {
563    }
564
565    UObject* create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const {
566        if (U_FAILURE(status)) {
567        return NULL;
568        }
569        UnicodeString temp;
570        key.currentID(temp);
571        if (U_SUCCESS(_status)) {
572        if (_ids.contains(&temp)) {
573                return new UnicodeString(_factoryID + temp);
574        }
575        } else {
576        status = _status;
577    }
578        return NULL;
579    }
580
581    void updateVisibleIDs(Hashtable& result, UErrorCode& status) const {
582        if (U_SUCCESS(_status)) {
583            for (int32_t i = 0; i < _ids.size(); ++i) {
584                result.put(*(UnicodeString*)_ids[i], (void*)this, status);
585            }
586        }
587    }
588
589    UnicodeString& getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const {
590        if (U_SUCCESS(_status) && _ids.contains((void*)&id)) {
591            char buffer[128];
592            UErrorCode status = U_ZERO_ERROR;
593            int32_t len = id.extract(buffer, sizeof(buffer), NULL, status);
594            if (U_SUCCESS(status)) {
595                if (len == sizeof(buffer)) {
596                    --len;
597                }
598                buffer[len] = 0;
599                Locale loc = Locale::createFromName(buffer);
600                loc.getDisplayName(locale, result);
601                return result;
602            }
603        }
604        result.setToBogus(); // shouldn't happen
605        return result;
606    }
607
608    static UClassID getStaticClassID() {
609        return (UClassID)&fgClassID;
610    }
611
612    virtual UClassID getDynamicClassID() const {
613        return getStaticClassID();
614    }
615
616    private:
617    static const char fgClassID;
618};
619
620const char TestMultipleKeyStringFactory::fgClassID = '\0';
621
622void
623ICUServiceTest::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
819class CalifornioLanguageFactory : public ICUResourceBundleFactory
820{
821    public:
822    static const char* californio; // = "en_US_CA";
823    static const char* valley; // = californio ## "_VALLEY";
824    static const char* surfer; // = californio ## "_SURFER";
825    static const char* geek; // = californio ## "_GEEK";
826    static Hashtable* supportedIDs; // = NULL;
827
828    static void cleanup(void) {
829      delete supportedIDs;
830      supportedIDs = NULL;
831    }
832
833    const Hashtable* getSupportedIDs(UErrorCode& status) const
834    {
835        if (supportedIDs == NULL) {
836            Hashtable* table = new Hashtable();
837            table->put(UnicodeString(californio), (void*)table, status);
838            table->put(UnicodeString(valley), (void*)table, status);
839            table->put(UnicodeString(surfer), (void*)table, status);
840            table->put(UnicodeString(geek), (void*)table, status);
841
842            // not necessarily atomic, but this is a test...
843            supportedIDs = table;
844        }
845        return supportedIDs;
846    }
847
848    UnicodeString& getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const
849    {
850        UnicodeString prefix = "";
851        UnicodeString suffix = "";
852        UnicodeString ls = locale.getName();
853        if (LocaleUtility::isFallbackOf(californio, ls)) {
854            if (!ls.caseCompare(valley, 0)) {
855                prefix = "Like, you know, it's so totally ";
856            } else if (!ls.caseCompare(surfer, 0)) {
857                prefix = "Dude, it's ";
858            } else if (!ls.caseCompare(geek, 0)) {
859                prefix = "I'd estimate it is approximately ";
860            } else {
861                prefix = "Huh?  Maybe ";
862            }
863        }
864        if (LocaleUtility::isFallbackOf(californio, id)) {
865            if (!id.caseCompare(valley, 0)) {
866                suffix = "like the Valley, you know?  Let's go to the mall!";
867            } else if (!id.caseCompare(surfer, 0)) {
868                suffix = "time to hit those gnarly waves, Dude!!!";
869            } else if (!id.caseCompare(geek, 0)) {
870                suffix = "all systems go.  T-Minus 9, 8, 7...";
871            } else {
872                suffix = "No Habla Englais";
873            }
874        } else {
875            suffix = ICUResourceBundleFactory::getDisplayName(id, locale, result);
876        }
877
878        result = prefix + suffix;
879        return result;
880    }
881};
882
883const char* CalifornioLanguageFactory::californio = "en_US_CA";
884const char* CalifornioLanguageFactory::valley = "en_US_CA_VALLEY";
885const char* CalifornioLanguageFactory::surfer = "en_US_CA_SURFER";
886const char* CalifornioLanguageFactory::geek = "en_US_CA_GEEK";
887Hashtable* CalifornioLanguageFactory::supportedIDs = NULL;
888
889void
890ICUServiceTest::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
951class SimpleListener : public ServiceListener {
952    ICUServiceTest* _test;
953    int32_t _n;
954    UnicodeString _name;
955
956    public:
957    SimpleListener(ICUServiceTest* test, const UnicodeString& name) : _test(test), _n(0), _name(name) {}
958
959    virtual void serviceChanged(const ICUService& service) const {
960        UnicodeString serviceName = "listener ";
961        serviceName.append(_name);
962        serviceName.append(" n++");
963        serviceName.append(" service changed: " );
964        service.getName(serviceName);
965        _test->logln(serviceName);
966    }
967};
968
969void
970ICUServiceTest::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() {
1012private int n;
1013public 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
1029class TestStringLocaleService : public ICULocaleService {
1030    public:
1031    virtual UObject* cloneInstance(UObject* instance) const {
1032        return instance ? new UnicodeString(*(UnicodeString*)instance) : NULL;
1033    }
1034};
1035
1036void 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
1215class WrapFactory : public ICUServiceFactory {
1216    public:
1217    static const UnicodeString& getGreetingID() {
1218      if (greetingID == NULL) {
1219    greetingID = new UnicodeString("greeting");
1220      }
1221      return *greetingID;
1222    }
1223
1224  static void cleanup() {
1225    delete greetingID;
1226    greetingID = NULL;
1227  }
1228
1229    UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const {
1230        if (U_SUCCESS(status)) {
1231            UnicodeString temp;
1232            if (key.currentID(temp).compare(getGreetingID()) == 0) {
1233                UnicodeString* previous = (UnicodeString*)service->getKey((ICUServiceKey&)key, NULL, this, status);
1234                if (previous) {
1235                    previous->insert(0, "A different greeting: \"");
1236                    previous->append("\"");
1237                    return previous;
1238                }
1239            }
1240        }
1241        return NULL;
1242    }
1243
1244    void updateVisibleIDs(Hashtable& result, UErrorCode& status) const {
1245        if (U_SUCCESS(status)) {
1246            result.put("greeting", (void*)this, status);
1247        }
1248    }
1249
1250    UnicodeString& getDisplayName(const UnicodeString& id, const Locale& /* locale */, UnicodeString& result) const {
1251        result.append("wrap '");
1252        result.append(id);
1253        result.append("'");
1254        return result;
1255    }
1256
1257    /**
1258     * UObject boilerplate.
1259     */
1260    static UClassID getStaticClassID() {
1261        return (UClassID)&fgClassID;
1262    }
1263
1264    virtual UClassID getDynamicClassID() const {
1265        return getStaticClassID();
1266    }
1267
1268    private:
1269    static const char fgClassID;
1270    static UnicodeString* greetingID;
1271};
1272
1273UnicodeString* WrapFactory::greetingID = NULL;
1274const char WrapFactory::fgClassID = '\0';
1275
1276void
1277ICUServiceTest::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
1307void 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