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