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
22 class MyListener : public EventListener {
23 };
24
25 class WrongListener : public EventListener {
26 };
27
28 class ICUNSubclass : public ICUNotifier {
29 public:
acceptsListener(const EventListener &) const30 UBool acceptsListener(const EventListener& /*l*/) const {
31 return TRUE;
32 // return l instanceof MyListener;
33 }
34
notifyListener(EventListener &) const35 virtual void notifyListener(EventListener& /*l*/) const {
36 }
37 };
38
39 // This factory does nothing
40 class LKFSubclass0 : public LocaleKeyFactory {
41 public:
LKFSubclass0()42 LKFSubclass0()
43 : LocaleKeyFactory(VISIBLE, "LKFSubclass0")
44 {
45 }
46 };
47
48 class LKFSubclass : public LocaleKeyFactory {
49 Hashtable table;
50
51 public:
LKFSubclass(UBool visible)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:
getSupportedIDs(UErrorCode &) const60 virtual const Hashtable* getSupportedIDs(UErrorCode &/*status*/) const {
61 return &table;
62 }
63 };
64
65 class Integer : public UObject {
66 public:
67 const int32_t _val;
68
Integer(int32_t val)69 Integer(int32_t val) : _val(val) {
70 }
71
Integer(const Integer & rhs)72 Integer(const Integer& rhs) : UObject(rhs), _val(rhs._val) {
73 }
~Integer()74 virtual ~Integer() {
75 }
76
77 public:
78 /**
79 * UObject boilerplate.
80 */
getStaticClassID()81 static UClassID getStaticClassID() {
82 return (UClassID)&fgClassID;
83 }
84
getDynamicClassID() const85 virtual UClassID getDynamicClassID() const {
86 return getStaticClassID();
87 }
88
operator ==(const UObject & other) const89 virtual UBool operator==(const UObject& other) const
90 {
91 return typeid(*this) == typeid(other) &&
92 _val == ((Integer&)other)._val;
93 }
94
95 public:
debug(UnicodeString & result) const96 virtual UnicodeString& debug(UnicodeString& result) const {
97 debugClass(result);
98 result.append(" val: ");
99 result.append(_val);
100 return result;
101 }
102
debugClass(UnicodeString & result) const103 virtual UnicodeString& debugClass(UnicodeString& result) const {
104 return result.append("Integer");
105 }
106
107 private:
108 static const char fgClassID;
109 };
110
111 const char Integer::fgClassID = '\0';
112
113 // use locale keys
114 class TestIntegerService : public ICUService {
115 public:
createKey(const UnicodeString * id,UErrorCode & status) const116 ICUServiceKey* createKey(const UnicodeString* id, UErrorCode& status) const {
117 return LocaleKey::createWithCanonicalFallback(id, NULL, status); // no fallback locale
118 }
119
createSimpleFactory(UObject * obj,const UnicodeString & id,UBool visible,UErrorCode & status)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
cloneInstance(UObject * instance) const129 virtual UObject* cloneInstance(UObject* instance) const {
130 return instance ? new Integer(*(Integer*)instance) : NULL;
131 }
132 };
133
134
ICUServiceTest()135 ICUServiceTest::ICUServiceTest() {
136 }
137
~ICUServiceTest()138 ICUServiceTest::~ICUServiceTest() {
139 }
140
141 void
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)142 ICUServiceTest::runIndexedTest(int32_t index, UBool exec, const char* &name,
143 char* /*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
append(UnicodeString & result,const UObject * obj)157 UnicodeString 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
181 UnicodeString&
lrmsg(UnicodeString & result,const UnicodeString & message,const UObject * lhs,const UObject * rhs) const182 ICUServiceTest::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
192 void
confirmBoolean(const UnicodeString & message,UBool val)193 ICUServiceTest::confirmBoolean(const UnicodeString& message, UBool val)
194 {
195 if (val) {
196 logln(message);
197 } else {
198 errln(message);
199 }
200 }
201
202 #if 0
203 void
204 ICUServiceTest::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
220 void
confirmEqual(const UnicodeString & message,const Integer * lhs,const Integer * rhs)221 ICUServiceTest::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
237 void
confirmEqual(const UnicodeString & message,const UnicodeString * lhs,const UnicodeString * rhs)238 ICUServiceTest::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
254 void
confirmEqual(const UnicodeString & message,const Locale * lhs,const Locale * rhs)255 ICUServiceTest::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
273 void
confirmStringsEqual(const UnicodeString & message,const UnicodeString & lhs,const UnicodeString & rhs)274 ICUServiceTest::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
292 void
confirmIdentical(const UnicodeString & message,const UObject * lhs,const UObject * rhs)293 ICUServiceTest::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
304 void
confirmIdentical(const UnicodeString & message,int32_t lhs,int32_t rhs)305 ICUServiceTest::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
314 void
msgstr(const UnicodeString & message,UObject * obj,UBool err)315 ICUServiceTest::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
326 void
testAPI_One()327 ICUServiceTest::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 */
478 class TestStringSimpleKeyService : public ICUService {
479 public:
480
createSimpleFactory(UObject * obj,const UnicodeString & id,UBool visible,UErrorCode & status)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
cloneInstance(UObject * instance) const493 virtual UObject* cloneInstance(UObject* instance) const {
494 return instance ? new UnicodeString(*(UnicodeString*)instance) : NULL;
495 }
496 };
497
498 class TestStringService : public ICUService {
499 public:
createKey(const UnicodeString * id,UErrorCode & status) const500 ICUServiceKey* createKey(const UnicodeString* id, UErrorCode& status) const {
501 return LocaleKey::createWithCanonicalFallback(id, NULL, status); // no fallback locale
502 }
503
createSimpleFactory(UObject * obj,const UnicodeString & id,UBool visible,UErrorCode &)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
cloneInstance(UObject * instance) const513 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
519 class AnonymousStringFactory : public ICUServiceFactory
520 {
521 public:
create(const ICUServiceKey & key,const ICUService *,UErrorCode &) const522 virtual UObject* create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& /* status */) const {
523 return new UnicodeString(key.getID());
524 }
525
updateVisibleIDs(Hashtable &,UErrorCode &) const526 virtual void updateVisibleIDs(Hashtable& /*result*/, UErrorCode& /*status*/) const {
527 // do nothing
528 }
529
getDisplayName(const UnicodeString &,const Locale &,UnicodeString & result) const530 virtual UnicodeString& getDisplayName(const UnicodeString& /*id*/, const Locale& /*locale*/, UnicodeString& result) const {
531 // do nothing
532 return result;
533 }
534
getStaticClassID()535 static UClassID getStaticClassID() {
536 return (UClassID)&fgClassID;
537 }
538
getDynamicClassID() const539 virtual UClassID getDynamicClassID() const {
540 return getStaticClassID();
541 }
542
543 private:
544 static const char fgClassID;
545 };
546
547 const char AnonymousStringFactory::fgClassID = '\0';
548
549 class TestMultipleKeyStringFactory : public ICUServiceFactory {
550 UErrorCode _status;
551 UVector _ids;
552 UnicodeString _factoryID;
553
554 public:
TestMultipleKeyStringFactory(const UnicodeString ids[],int32_t count,const UnicodeString & factoryID)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
~TestMultipleKeyStringFactory()565 ~TestMultipleKeyStringFactory() {
566 }
567
create(const ICUServiceKey & key,const ICUService *,UErrorCode & status) const568 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
updateVisibleIDs(Hashtable & result,UErrorCode & status) const584 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
getDisplayName(const UnicodeString & id,const Locale & locale,UnicodeString & result) const592 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
getStaticClassID()611 static UClassID getStaticClassID() {
612 return (UClassID)&fgClassID;
613 }
614
getDynamicClassID() const615 virtual UClassID getDynamicClassID() const {
616 return getStaticClassID();
617 }
618
619 private:
620 static const char fgClassID;
621 };
622
623 const char TestMultipleKeyStringFactory::fgClassID = '\0';
624
625 void
testAPI_Two()626 ICUServiceTest::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
822 class 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
cleanup(void)831 static void cleanup(void) {
832 delete supportedIDs;
833 supportedIDs = NULL;
834 }
835
getSupportedIDs(UErrorCode & status) const836 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
getDisplayName(const UnicodeString & id,const Locale & locale,UnicodeString & result) const851 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
886 const char* CalifornioLanguageFactory::californio = "en_US_CA";
887 const char* CalifornioLanguageFactory::valley = "en_US_CA_VALLEY";
888 const char* CalifornioLanguageFactory::surfer = "en_US_CA_SURFER";
889 const char* CalifornioLanguageFactory::geek = "en_US_CA_GEEK";
890 Hashtable* CalifornioLanguageFactory::supportedIDs = NULL;
891
892 void
testRBF()893 ICUServiceTest::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
954 class SimpleListener : public ServiceListener {
955 ICUServiceTest* _test;
956 UnicodeString _name;
957
958 public:
SimpleListener(ICUServiceTest * test,const UnicodeString & name)959 SimpleListener(ICUServiceTest* test, const UnicodeString& name) : _test(test), _name(name) {}
960
serviceChanged(const ICUService & service) const961 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
971 void
testNotification()972 ICUServiceTest::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() {
1014 private int n;
1015 public 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
1031 class TestStringLocaleService : public ICULocaleService {
1032 public:
cloneInstance(UObject * instance) const1033 virtual UObject* cloneInstance(UObject* instance) const {
1034 return instance ? new UnicodeString(*(UnicodeString*)instance) : NULL;
1035 }
1036 };
1037
testLocale()1038 void 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
1217 class WrapFactory : public ICUServiceFactory {
1218 public:
getGreetingID()1219 static const UnicodeString& getGreetingID() {
1220 if (greetingID == NULL) {
1221 greetingID = new UnicodeString("greeting");
1222 }
1223 return *greetingID;
1224 }
1225
cleanup()1226 static void cleanup() {
1227 delete greetingID;
1228 greetingID = NULL;
1229 }
1230
create(const ICUServiceKey & key,const ICUService * service,UErrorCode & status) const1231 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
updateVisibleIDs(Hashtable & result,UErrorCode & status) const1246 void updateVisibleIDs(Hashtable& result, UErrorCode& status) const {
1247 if (U_SUCCESS(status)) {
1248 result.put("greeting", (void*)this, status);
1249 }
1250 }
1251
getDisplayName(const UnicodeString & id,const Locale &,UnicodeString & result) const1252 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 */
getStaticClassID()1262 static UClassID getStaticClassID() {
1263 return (UClassID)&fgClassID;
1264 }
1265
getDynamicClassID() const1266 virtual UClassID getDynamicClassID() const {
1267 return getStaticClassID();
1268 }
1269
1270 private:
1271 static const char fgClassID;
1272 static UnicodeString* greetingID;
1273 };
1274
1275 UnicodeString* WrapFactory::greetingID = NULL;
1276 const char WrapFactory::fgClassID = '\0';
1277
1278 void
testWrapFactory()1279 ICUServiceTest::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
testCoverage()1309 void 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