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