• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /********************************************************************
2  * COPYRIGHT:
3  * Copyright (c) 1997-2006, International Business Machines Corporation and
4  * others. All Rights Reserved.
5  ********************************************************************/
6 
7 #include "unicode/utypes.h"
8 
9 #include "cstring.h"
10 #include "unicode/unistr.h"
11 #include "unicode/uniset.h"
12 #include "unicode/resbund.h"
13 #include "restest.h"
14 
15 #include <stdlib.h>
16 #include <time.h>
17 #include <string.h>
18 #include <limits.h>
19 
20 //***************************************************************************************
21 
22 static const UChar kErrorUChars[] = { 0x45, 0x52, 0x52, 0x4f, 0x52, 0 };
23 static const int32_t kErrorLength = 5;
24 static const int32_t kERROR_COUNT = -1234567;
25 
26 //***************************************************************************************
27 
28 enum E_Where
29 {
30     e_Root,
31     e_te,
32     e_te_IN,
33     e_Where_count
34 };
35 
36 //***************************************************************************************
37 
38 #define CONFIRM_EQ(actual, expected, myAction) if ((expected)==(actual)) { record_pass(myAction); } else { record_fail(myAction + (UnicodeString)" returned " + (actual) + (UnicodeString)" instead of " + (expected) + "\n");}
39 #define CONFIRM_GE(actual, expected, myAction) if ((actual)>=(expected)) { record_pass(myAction); } else { record_fail(myAction + (UnicodeString)" returned " + (actual) + (UnicodeString)" instead of x >= " + (expected) + "\n");}
40 #define CONFIRM_NE(actual, expected, myAction) if ((expected)!=(actual)) { record_pass(myAction); } else { record_fail(myAction + (UnicodeString)" returned " + (actual) + (UnicodeString)" instead of x != " + (expected) + "\n");}
41 
42 #define CONFIRM_UErrorCode(actual, expected, myAction) if ((expected)==(actual)) { record_pass(myAction); } else { record_fail(myAction + (UnicodeString)" returned " + u_errorName(actual) + " instead of " + u_errorName(expected) + "\n"); }
43 
44 //***************************************************************************************
45 
46 /**
47  * Convert an integer, positive or negative, to a character string radix 10.
48  */
49 char*
itoa(int32_t i,char * buf)50 itoa(int32_t i, char* buf)
51 {
52     char* result = buf;
53 
54     // Handle negative
55     if (i < 0)
56     {
57         *buf++ = '-';
58         i = -i;
59     }
60 
61     // Output digits in reverse order
62     char* p = buf;
63     do
64     {
65         *p++ = (char)('0' + (i % 10));
66         i /= 10;
67     }
68     while (i);
69     *p-- = 0;
70 
71     // Reverse the string
72     while (buf < p)
73     {
74         char c = *buf;
75         *buf++ = *p;
76         *p-- = c;
77     }
78 
79     return result;
80 }
81 
82 
83 
84 //***************************************************************************************
85 
86 // Array of our test objects
87 
88 static struct
89 {
90     const char* name;
91     Locale *locale;
92     UErrorCode expected_constructor_status;
93     E_Where where;
94     UBool like[e_Where_count];
95     UBool inherits[e_Where_count];
96 }
97 param[] =
98 {
99     // "te" means test
100     // "IN" means inherits
101     // "NE" or "ne" means "does not exist"
102 
103     { "root",       NULL,   U_ZERO_ERROR,             e_Root,      { TRUE, FALSE, FALSE }, { TRUE, FALSE, FALSE } },
104     { "te",         NULL,   U_ZERO_ERROR,             e_te,        { FALSE, TRUE, FALSE }, { TRUE, TRUE, FALSE } },
105     { "te_IN",      NULL,   U_ZERO_ERROR,             e_te_IN,     { FALSE, FALSE, TRUE }, { TRUE, TRUE, TRUE } },
106     { "te_NE",      NULL,   U_USING_FALLBACK_WARNING, e_te,        { FALSE, TRUE, FALSE }, { TRUE, TRUE, FALSE } },
107     { "te_IN_NE",   NULL,   U_USING_FALLBACK_WARNING, e_te_IN,     { FALSE, FALSE, TRUE }, { TRUE, TRUE, TRUE } },
108     { "ne",         NULL,   U_USING_DEFAULT_WARNING,  e_Root,      { TRUE, FALSE, FALSE }, { TRUE, FALSE, FALSE } }
109 };
110 
111 static const int32_t bundles_count = sizeof(param) / sizeof(param[0]);
112 
113 //***************************************************************************************
114 
115 /**
116  * Return a random unsigned long l where 0N <= l <= ULONG_MAX.
117  */
118 
119 uint32_t
randul()120 randul()
121 {
122     static UBool initialized = FALSE;
123     if (!initialized)
124     {
125         srand((unsigned)time(NULL));
126         initialized = TRUE;
127     }
128     // Assume rand has at least 12 bits of precision
129     uint32_t l = 0;
130     for (uint32_t i=0; i<sizeof(l); ++i)
131         ((char*)&l)[i] = (char)((rand() & 0x0FF0) >> 4);
132     return l;
133 }
134 
135 /**
136  * Return a random double x where 0.0 <= x < 1.0.
137  */
138 double
randd()139 randd()
140 {
141     return (double)(randul() / ULONG_MAX);
142 }
143 
144 /**
145  * Return a random integer i where 0 <= i < n.
146  */
randi(int32_t n)147 int32_t randi(int32_t n)
148 {
149     return (int32_t)(randd() * n);
150 }
151 
152 //***************************************************************************************
153 
154 /*
155  Don't use more than one of these at a time because of the Locale names
156 */
ResourceBundleTest()157 ResourceBundleTest::ResourceBundleTest()
158 : pass(0),
159   fail(0)
160 {
161     if (param[5].locale == NULL) {
162         param[0].locale = new Locale("root");
163         param[1].locale = new Locale("te");
164         param[2].locale = new Locale("te", "IN");
165         param[3].locale = new Locale("te", "NE");
166         param[4].locale = new Locale("te", "IN", "NE");
167         param[5].locale = new Locale("ne");
168     }
169 }
170 
~ResourceBundleTest()171 ResourceBundleTest::~ResourceBundleTest()
172 {
173     if (param[5].locale) {
174         int idx;
175         for (idx = 0; idx < (int)(sizeof(param)/sizeof(param[0])); idx++) {
176             delete param[idx].locale;
177             param[idx].locale = NULL;
178         }
179     }
180 }
181 
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)182 void ResourceBundleTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
183 {
184     if (exec) logln("TestSuite ResourceBundleTest: ");
185     switch (index) {
186     case 0: name = "TestResourceBundles"; if (exec) TestResourceBundles(); break;
187     case 1: name = "TestConstruction"; if (exec) TestConstruction(); break;
188     case 2: name = "TestExemplar"; if (exec) TestExemplar(); break;
189     case 3: name = "TestGetSize"; if (exec) TestGetSize(); break;
190     case 4: name = "TestGetLocaleByType"; if (exec) TestGetLocaleByType(); break;
191         default: name = ""; break; //needed to end loop
192     }
193 }
194 
195 //***************************************************************************************
196 
197 void
TestResourceBundles()198 ResourceBundleTest::TestResourceBundles()
199 {
200     UErrorCode status = U_ZERO_ERROR;
201 
202     loadTestData(status);
203     if(U_FAILURE(status))
204     {
205         errln("Could not load testdata.dat %s " + UnicodeString(u_errorName(status)));
206         return;
207     }
208 
209     /* Make sure that users using te_IN for the default locale don't get test failures. */
210     Locale originalDefault;
211     if (Locale::getDefault() == Locale("te_IN")) {
212         Locale::setDefault(Locale("en_US"), status);
213     }
214 
215     testTag("only_in_Root", TRUE, FALSE, FALSE);
216     testTag("only_in_te", FALSE, TRUE, FALSE);
217     testTag("only_in_te_IN", FALSE, FALSE, TRUE);
218     testTag("in_Root_te", TRUE, TRUE, FALSE);
219     testTag("in_Root_te_te_IN", TRUE, TRUE, TRUE);
220     testTag("in_Root_te_IN", TRUE, FALSE, TRUE);
221     testTag("in_te_te_IN", FALSE, TRUE, TRUE);
222     testTag("nonexistent", FALSE, FALSE, FALSE);
223     logln("Passed: %d\nFailed: %d", pass, fail);
224 
225     /* Restore the default locale for the other tests. */
226     Locale::setDefault(originalDefault, status);
227 }
228 
229 void
TestConstruction()230 ResourceBundleTest::TestConstruction()
231 {
232     UErrorCode   err = U_ZERO_ERROR;
233     Locale       locale("te", "IN");
234 
235     const char* testdatapath=loadTestData(err);
236     if(U_FAILURE(err))
237     {
238         errln("Could not load testdata.dat " + UnicodeString(testdatapath) +  ", " + UnicodeString(u_errorName(err)));
239         return;
240     }
241 
242     /* Make sure that users using te_IN for the default locale don't get test failures. */
243     Locale originalDefault;
244     if (Locale::getDefault() == Locale("te_IN")) {
245         Locale::setDefault(Locale("en_US"), err);
246     }
247 
248     ResourceBundle  test1((UnicodeString)testdatapath, err);
249     ResourceBundle  test2(testdatapath, locale, err);
250     //ResourceBundle  test1("c:\\icu\\icu\\source\\test\\testdata\\testdata", err);
251     //ResourceBundle  test2("c:\\icu\\icu\\source\\test\\testdata\\testdata", locale, err);
252 
253     UnicodeString   result1(test1.getStringEx("string_in_Root_te_te_IN", err));
254     UnicodeString   result2(test2.getStringEx("string_in_Root_te_te_IN", err));
255 
256     if (U_FAILURE(err)) {
257         errln("Something threw an error in TestConstruction()");
258         return;
259     }
260 
261     logln("for string_in_Root_te_te_IN, default.txt had " + result1);
262     logln("for string_in_Root_te_te_IN, te_IN.txt had " + result2);
263 
264     if (result1 != "ROOT" || result2 != "TE_IN")
265         errln("Construction test failed; run verbose for more information");
266 
267     const char* version1;
268     const char* version2;
269 
270     version1 = test1.getVersionNumber();
271     version2 = test2.getVersionNumber();
272 
273     char *versionID1 = new char[1+strlen(version1)]; // + 1 for zero byte
274     char *versionID2 = new char[1+ strlen(version2)]; // + 1 for zero byte
275 
276     strcpy(versionID1, "44.0");  // hardcoded, please change if the default.txt file or ResourceBundle::kVersionSeparater is changed.
277 
278     strcpy(versionID2, "55.0");  // hardcoded, please change if the te_IN.txt file or ResourceBundle::kVersionSeparater is changed.
279 
280     logln(UnicodeString("getVersionNumber on default.txt returned ") + version1);
281     logln(UnicodeString("getVersionNumber on te_IN.txt returned ") + version2);
282 
283     if (strcmp(version1, versionID1) != 0 || strcmp(version2, versionID2) != 0)
284         errln("getVersionNumber() failed");
285 
286     delete[] versionID1;
287     delete[] versionID2;
288 
289     /* Restore the default locale for the other tests. */
290     Locale::setDefault(originalDefault, err);
291 }
292 
293 //***************************************************************************************
294 
295 UBool
testTag(const char * frag,UBool in_Root,UBool in_te,UBool in_te_IN)296 ResourceBundleTest::testTag(const char* frag,
297                             UBool in_Root,
298                             UBool in_te,
299                             UBool in_te_IN)
300 {
301     int32_t failOrig = fail;
302 
303     // Make array from input params
304 
305     UBool is_in[] = { in_Root, in_te, in_te_IN };
306 
307     const char* NAME[] = { "ROOT", "TE", "TE_IN" };
308 
309     // Now try to load the desired items
310 
311     char tag[100];
312     UnicodeString action;
313 
314     int32_t i,j,actual_bundle;
315 //    int32_t row,col;
316     int32_t index;
317     UErrorCode status = U_ZERO_ERROR;
318     const char* testdatapath;
319     testdatapath=loadTestData(status);
320     if(U_FAILURE(status))
321     {
322         errln("Could not load testdata.dat %s " + UnicodeString(u_errorName(status)));
323         return FALSE;
324     }
325 
326     for (i=0; i<bundles_count; ++i)
327     {
328         action = "Constructor for ";
329         action += param[i].name;
330 
331         status = U_ZERO_ERROR;
332         ResourceBundle theBundle( testdatapath, *param[i].locale, status);
333         //ResourceBundle theBundle( "c:\\icu\\icu\\source\\test\\testdata\\testdata", *param[i].locale, status);
334         CONFIRM_UErrorCode(status, param[i].expected_constructor_status, action);
335 
336         if(i == 5)
337           actual_bundle = 0; /* ne -> default */
338         else if(i == 3)
339           actual_bundle = 1; /* te_NE -> te */
340         else if(i == 4)
341           actual_bundle = 2; /* te_IN_NE -> te_IN */
342         else
343           actual_bundle = i;
344 
345 
346         UErrorCode expected_resource_status = U_MISSING_RESOURCE_ERROR;
347         for (j=e_te_IN; j>=e_Root; --j)
348         {
349             if (is_in[j] && param[i].inherits[j])
350             {
351                 if(j == actual_bundle) /* it's in the same bundle OR it's a nonexistent=default bundle (5) */
352                   expected_resource_status = U_ZERO_ERROR;
353                 else if(j == 0)
354                   expected_resource_status = U_USING_DEFAULT_WARNING;
355                 else
356                   expected_resource_status = U_USING_FALLBACK_WARNING;
357 
358                 break;
359             }
360         }
361 
362         UErrorCode expected_status;
363 
364         UnicodeString base;
365         for (j=param[i].where; j>=0; --j)
366         {
367             if (is_in[j])
368             {
369                 base = NAME[j];
370                 break;
371             }
372         }
373 
374         //--------------------------------------------------------------------------
375         // string
376 
377         uprv_strcpy(tag, "string_");
378         uprv_strcat(tag, frag);
379 
380         action = param[i].name;
381         action += ".getString(";
382         action += tag;
383         action += ")";
384 
385 
386         status = U_ZERO_ERROR;
387 
388         UnicodeString string(theBundle.getStringEx(tag, status));
389 
390         if(U_FAILURE(status)) {
391             string.setTo(TRUE, kErrorUChars, kErrorLength);
392         }
393 
394         CONFIRM_UErrorCode(status, expected_resource_status, action);
395 
396         UnicodeString expected_string(kErrorUChars);
397         if (U_SUCCESS(status)) {
398             expected_string = base;
399         }
400 
401         CONFIRM_EQ(string, expected_string, action);
402 
403         //--------------------------------------------------------------------------
404         // array
405 
406         uprv_strcpy(tag, "array_");
407         uprv_strcat(tag, frag);
408 
409         action = param[i].name;
410         action += ".get(";
411         action += tag;
412         action += ")";
413 
414         status = U_ZERO_ERROR;
415         ResourceBundle arrayBundle(theBundle.get(tag, status));
416         CONFIRM_UErrorCode(status, expected_resource_status, action);
417         int32_t count = arrayBundle.getSize();
418 
419         if (U_SUCCESS(status))
420         {
421             CONFIRM_GE(count, 1, action);
422 
423             for (j=0; j < count; ++j)
424             {
425                 char buf[32];
426                 UnicodeString value(arrayBundle.getStringEx(j, status));
427                 expected_string = base;
428                 expected_string += itoa(j,buf);
429                 CONFIRM_EQ(value, expected_string, action);
430             }
431 
432             action = param[i].name;
433             action += ".getStringEx(";
434             action += tag;
435             action += ")";
436 
437             for (j=0; j<100; ++j)
438             {
439                 index = count ? (randi(count * 3) - count) : (randi(200) - 100);
440                 status = U_ZERO_ERROR;
441                 string = kErrorUChars;
442                 UnicodeString t(arrayBundle.getStringEx(index, status));
443                 expected_status = (index >= 0 && index < count) ? expected_resource_status : U_MISSING_RESOURCE_ERROR;
444                 CONFIRM_UErrorCode(status, expected_status, action);
445 
446                 if (U_SUCCESS(status))
447                 {
448                     char buf[32];
449                     expected_string = base;
450                     expected_string += itoa(index,buf);
451                 }
452                 else
453                 {
454                     expected_string = kErrorUChars;
455                 }
456                 CONFIRM_EQ(string, expected_string, action);
457             }
458         }
459         else if (status != expected_resource_status)
460         {
461             record_fail("Error getting " + (UnicodeString)tag);
462             return (UBool)(failOrig != fail);
463         }
464 
465     }
466 
467     return (UBool)(failOrig != fail);
468 }
469 
470 void
record_pass(UnicodeString passMessage)471 ResourceBundleTest::record_pass(UnicodeString passMessage)
472 {
473     logln(passMessage);
474     ++pass;
475 }
476 void
record_fail(UnicodeString errMessage)477 ResourceBundleTest::record_fail(UnicodeString errMessage)
478 {
479     err(errMessage);
480     ++fail;
481 }
482 
483 void
TestExemplar()484 ResourceBundleTest::TestExemplar(){
485 
486     int32_t locCount = uloc_countAvailable();
487     int32_t locIndex=0;
488     int num=0;
489     UErrorCode status = U_ZERO_ERROR;
490     for(;locIndex<locCount;locIndex++){
491         const char* locale = uloc_getAvailable(locIndex);
492         UResourceBundle *resb =ures_open(NULL,locale,&status);
493         if(U_SUCCESS(status) && status!=U_USING_FALLBACK_WARNING && status!=U_USING_DEFAULT_WARNING){
494             int32_t len=0;
495             const UChar* strSet = ures_getStringByKey(resb,"ExemplarCharacters",&len,&status);
496             UnicodeSet set(strSet,status);
497             if(U_FAILURE(status)){
498                 errln("Could not construct UnicodeSet from pattern for ExemplarCharacters in locale : %s. Error: %s",locale,u_errorName(status));
499                 status=U_ZERO_ERROR;
500             }
501             num++;
502         }
503         ures_close(resb);
504     }
505     logln("Number of installed locales with exemplar characters that could be tested: %d",num);
506 
507 }
508 
509 void
TestGetSize(void)510 ResourceBundleTest::TestGetSize(void)
511 {
512     const struct {
513         const char* key;
514         int32_t size;
515     } test[] = {
516         { "zerotest", 1},
517         { "one", 1},
518         { "importtest", 1},
519         { "integerarray", 1},
520         { "emptyarray", 0},
521         { "emptytable", 0},
522         { "emptystring", 1}, /* empty string is still a string */
523         { "emptyint", 1},
524         { "emptybin", 1},
525         { "testinclude", 1},
526         { "collations", 1}, /* not 2 - there is hidden %%CollationBin */
527     };
528 
529     UErrorCode status = U_ZERO_ERROR;
530 
531     const char* testdatapath = loadTestData(status);
532     int32_t i = 0, j = 0;
533     int32_t size = 0;
534 
535     if(U_FAILURE(status))
536     {
537         err("Could not load testdata.dat %s\n", u_errorName(status));
538         return;
539     }
540 
541     ResourceBundle rb(testdatapath, "testtypes", status);
542     if(U_FAILURE(status))
543     {
544         err("Could not testtypes resource bundle %s\n", u_errorName(status));
545         return;
546     }
547 
548     for(i = 0; i < (int32_t)(sizeof(test)/sizeof(test[0])); i++) {
549         ResourceBundle res = rb.get(test[i].key, status);
550         if(U_FAILURE(status))
551         {
552             err("Couldn't find the key %s. Error: %s\n", u_errorName(status));
553             return;
554         }
555         size = res.getSize();
556         if(size != test[i].size) {
557             err("Expected size %i, got size %i for key %s\n", test[i].size, size, test[i].key);
558             for(j = 0; j < size; j++) {
559                 ResourceBundle helper = res.get(j, status);
560                 err("%s\n", helper.getKey());
561             }
562         }
563     }
564 }
565 
566 void
TestGetLocaleByType(void)567 ResourceBundleTest::TestGetLocaleByType(void)
568 {
569     const struct {
570         const char *requestedLocale;
571         const char *resourceKey;
572         const char *validLocale;
573         const char *actualLocale;
574     } test[] = {
575         { "te_IN_BLAH", "string_only_in_te_IN", "te_IN", "te_IN" },
576         { "te_IN_BLAH", "string_only_in_te", "te_IN", "te" },
577         { "te_IN_BLAH", "string_only_in_Root", "te_IN", "root" },
578         { "te_IN_BLAH_01234567890_01234567890_01234567890_01234567890_01234567890_01234567890", "array_2d_only_in_Root", "te_IN", "root" },
579         { "te_IN_BLAH@currency=euro", "array_2d_only_in_te_IN", "te_IN", "te_IN" },
580         { "te_IN_BLAH@calendar=thai;collation=phonebook", "array_2d_only_in_te", "te_IN", "te" }
581     };
582 
583     UErrorCode status = U_ZERO_ERROR;
584 
585     const char* testdatapath = loadTestData(status);
586     int32_t i = 0;
587     Locale locale;
588 
589     if(U_FAILURE(status))
590     {
591         err("Could not load testdata.dat %s\n", u_errorName(status));
592         return;
593     }
594 
595     for(i = 0; i < (int32_t)(sizeof(test)/sizeof(test[0])); i++) {
596         ResourceBundle rb(testdatapath, test[i].requestedLocale, status);
597         if(U_FAILURE(status))
598         {
599             err("Could not open resource bundle %s (error %s)\n", test[i].requestedLocale, u_errorName(status));
600             status = U_ZERO_ERROR;
601             continue;
602         }
603 
604         ResourceBundle res = rb.get(test[i].resourceKey, status);
605         if(U_FAILURE(status))
606         {
607             err("Couldn't find the key %s. Error: %s\n", test[i].resourceKey, u_errorName(status));
608             status = U_ZERO_ERROR;
609             continue;
610         }
611 
612         locale = res.getLocale(ULOC_REQUESTED_LOCALE, status);
613         if(locale != Locale::getDefault()) {
614             err("Expected requested locale to be %s. Got %s\n", test[i].requestedLocale, locale.getName());
615         }
616         locale = res.getLocale(ULOC_VALID_LOCALE, status);
617         if(strcmp(locale.getName(), test[i].validLocale) != 0) {
618             err("Expected valid locale to be %s. Got %s\n", test[i].requestedLocale, locale.getName());
619         }
620         locale = res.getLocale(ULOC_ACTUAL_LOCALE, status);
621         if(strcmp(locale.getName(), test[i].actualLocale) != 0) {
622             err("Expected actual locale to be %s. Got %s\n", test[i].requestedLocale, locale.getName());
623         }
624     }
625 }
626 
627 //eof
628 
629