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