1 /******************************************************************** 2 * COPYRIGHT: 3 * Copyright (c) 1997-2009, 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* 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 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 139 randd() 140 { 141 return (double)(randul() / ULONG_MAX); 142 } 143 144 /** 145 * Return a random integer i where 0 <= i < n. 146 */ 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 */ 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 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 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 198 ResourceBundleTest::TestResourceBundles() 199 { 200 UErrorCode status = U_ZERO_ERROR; 201 202 loadTestData(status); 203 if(U_FAILURE(status)) 204 { 205 dataerrln("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 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 dataerrln("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 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 dataerrln("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 471 ResourceBundleTest::record_pass(UnicodeString passMessage) 472 { 473 logln(passMessage); 474 ++pass; 475 } 476 void 477 ResourceBundleTest::record_fail(UnicodeString errMessage) 478 { 479 err(errMessage); 480 ++fail; 481 } 482 483 void 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 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 dataerrln("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 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 dataerrln("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