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 22static const UChar kErrorUChars[] = { 0x45, 0x52, 0x52, 0x4f, 0x52, 0 }; 23static const int32_t kErrorLength = 5; 24static const int32_t kERROR_COUNT = -1234567; 25 26//*************************************************************************************** 27 28enum 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 */ 49char* 50itoa(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 88static 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} 97param[] = 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 111static 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 119uint32_t 120randul() 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 */ 138double 139randd() 140{ 141 return (double)(randul() / ULONG_MAX); 142} 143 144/** 145 * Return a random integer i where 0 <= i < n. 146 */ 147int32_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*/ 157ResourceBundleTest::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 171ResourceBundleTest::~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 182void ResourceBundleTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) 183{ 184 if (exec) logln("TestSuite ResourceBundleTest: "); 185 switch (index) { 186#if !UCONFIG_NO_FILE_IO && !UCONFIG_NO_LEGACY_CONVERSION 187 case 0: name = "TestResourceBundles"; if (exec) TestResourceBundles(); break; 188 case 1: name = "TestConstruction"; if (exec) TestConstruction(); break; 189 case 2: name = "TestGetSize"; if (exec) TestGetSize(); break; 190 case 3: name = "TestGetLocaleByType"; if (exec) TestGetLocaleByType(); break; 191#else 192 case 0: case 1: case 2: case 3: name = "skip"; break; 193#endif 194 195 case 4: name = "TestExemplar"; if (exec) TestExemplar(); break; 196 default: name = ""; break; //needed to end loop 197 } 198} 199 200//*************************************************************************************** 201 202void 203ResourceBundleTest::TestResourceBundles() 204{ 205 UErrorCode status = U_ZERO_ERROR; 206 207 loadTestData(status); 208 if(U_FAILURE(status)) 209 { 210 dataerrln("Could not load testdata.dat %s " + UnicodeString(u_errorName(status))); 211 return; 212 } 213 214 /* Make sure that users using te_IN for the default locale don't get test failures. */ 215 Locale originalDefault; 216 if (Locale::getDefault() == Locale("te_IN")) { 217 Locale::setDefault(Locale("en_US"), status); 218 } 219 220 testTag("only_in_Root", TRUE, FALSE, FALSE); 221 testTag("only_in_te", FALSE, TRUE, FALSE); 222 testTag("only_in_te_IN", FALSE, FALSE, TRUE); 223 testTag("in_Root_te", TRUE, TRUE, FALSE); 224 testTag("in_Root_te_te_IN", TRUE, TRUE, TRUE); 225 testTag("in_Root_te_IN", TRUE, FALSE, TRUE); 226 testTag("in_te_te_IN", FALSE, TRUE, TRUE); 227 testTag("nonexistent", FALSE, FALSE, FALSE); 228 logln("Passed: %d\nFailed: %d", pass, fail); 229 230 /* Restore the default locale for the other tests. */ 231 Locale::setDefault(originalDefault, status); 232} 233 234void 235ResourceBundleTest::TestConstruction() 236{ 237 UErrorCode err = U_ZERO_ERROR; 238 Locale locale("te", "IN"); 239 240 const char* testdatapath=loadTestData(err); 241 if(U_FAILURE(err)) 242 { 243 dataerrln("Could not load testdata.dat " + UnicodeString(testdatapath) + ", " + UnicodeString(u_errorName(err))); 244 return; 245 } 246 247 /* Make sure that users using te_IN for the default locale don't get test failures. */ 248 Locale originalDefault; 249 if (Locale::getDefault() == Locale("te_IN")) { 250 Locale::setDefault(Locale("en_US"), err); 251 } 252 253 ResourceBundle test1((UnicodeString)testdatapath, err); 254 ResourceBundle test2(testdatapath, locale, err); 255 //ResourceBundle test1("c:\\icu\\icu\\source\\test\\testdata\\testdata", err); 256 //ResourceBundle test2("c:\\icu\\icu\\source\\test\\testdata\\testdata", locale, err); 257 258 UnicodeString result1(test1.getStringEx("string_in_Root_te_te_IN", err)); 259 UnicodeString result2(test2.getStringEx("string_in_Root_te_te_IN", err)); 260 261 if (U_FAILURE(err)) { 262 errln("Something threw an error in TestConstruction()"); 263 return; 264 } 265 266 logln("for string_in_Root_te_te_IN, default.txt had " + result1); 267 logln("for string_in_Root_te_te_IN, te_IN.txt had " + result2); 268 269 if (result1 != "ROOT" || result2 != "TE_IN") 270 errln("Construction test failed; run verbose for more information"); 271 272 const char* version1; 273 const char* version2; 274 275 version1 = test1.getVersionNumber(); 276 version2 = test2.getVersionNumber(); 277 278 char *versionID1 = new char[1+strlen(version1)]; // + 1 for zero byte 279 char *versionID2 = new char[1+ strlen(version2)]; // + 1 for zero byte 280 281 strcpy(versionID1, "44.0"); // hardcoded, please change if the default.txt file or ResourceBundle::kVersionSeparater is changed. 282 283 strcpy(versionID2, "55.0"); // hardcoded, please change if the te_IN.txt file or ResourceBundle::kVersionSeparater is changed. 284 285 logln(UnicodeString("getVersionNumber on default.txt returned ") + version1); 286 logln(UnicodeString("getVersionNumber on te_IN.txt returned ") + version2); 287 288 if (strcmp(version1, versionID1) != 0 || strcmp(version2, versionID2) != 0) 289 errln("getVersionNumber() failed"); 290 291 delete[] versionID1; 292 delete[] versionID2; 293 294 /* Restore the default locale for the other tests. */ 295 Locale::setDefault(originalDefault, err); 296} 297 298//*************************************************************************************** 299 300UBool 301ResourceBundleTest::testTag(const char* frag, 302 UBool in_Root, 303 UBool in_te, 304 UBool in_te_IN) 305{ 306 int32_t failOrig = fail; 307 308 // Make array from input params 309 310 UBool is_in[] = { in_Root, in_te, in_te_IN }; 311 312 const char* NAME[] = { "ROOT", "TE", "TE_IN" }; 313 314 // Now try to load the desired items 315 316 char tag[100]; 317 UnicodeString action; 318 319 int32_t i,j,actual_bundle; 320// int32_t row,col; 321 int32_t index; 322 UErrorCode status = U_ZERO_ERROR; 323 const char* testdatapath; 324 testdatapath=loadTestData(status); 325 if(U_FAILURE(status)) 326 { 327 dataerrln("Could not load testdata.dat %s " + UnicodeString(u_errorName(status))); 328 return FALSE; 329 } 330 331 for (i=0; i<bundles_count; ++i) 332 { 333 action = "Constructor for "; 334 action += param[i].name; 335 336 status = U_ZERO_ERROR; 337 ResourceBundle theBundle( testdatapath, *param[i].locale, status); 338 //ResourceBundle theBundle( "c:\\icu\\icu\\source\\test\\testdata\\testdata", *param[i].locale, status); 339 CONFIRM_UErrorCode(status, param[i].expected_constructor_status, action); 340 341 if(i == 5) 342 actual_bundle = 0; /* ne -> default */ 343 else if(i == 3) 344 actual_bundle = 1; /* te_NE -> te */ 345 else if(i == 4) 346 actual_bundle = 2; /* te_IN_NE -> te_IN */ 347 else 348 actual_bundle = i; 349 350 351 UErrorCode expected_resource_status = U_MISSING_RESOURCE_ERROR; 352 for (j=e_te_IN; j>=e_Root; --j) 353 { 354 if (is_in[j] && param[i].inherits[j]) 355 { 356 if(j == actual_bundle) /* it's in the same bundle OR it's a nonexistent=default bundle (5) */ 357 expected_resource_status = U_ZERO_ERROR; 358 else if(j == 0) 359 expected_resource_status = U_USING_DEFAULT_WARNING; 360 else 361 expected_resource_status = U_USING_FALLBACK_WARNING; 362 363 break; 364 } 365 } 366 367 UErrorCode expected_status; 368 369 UnicodeString base; 370 for (j=param[i].where; j>=0; --j) 371 { 372 if (is_in[j]) 373 { 374 base = NAME[j]; 375 break; 376 } 377 } 378 379 //-------------------------------------------------------------------------- 380 // string 381 382 uprv_strcpy(tag, "string_"); 383 uprv_strcat(tag, frag); 384 385 action = param[i].name; 386 action += ".getString("; 387 action += tag; 388 action += ")"; 389 390 391 status = U_ZERO_ERROR; 392 393 UnicodeString string(theBundle.getStringEx(tag, status)); 394 395 if(U_FAILURE(status)) { 396 string.setTo(TRUE, kErrorUChars, kErrorLength); 397 } 398 399 CONFIRM_UErrorCode(status, expected_resource_status, action); 400 401 UnicodeString expected_string(kErrorUChars); 402 if (U_SUCCESS(status)) { 403 expected_string = base; 404 } 405 406 CONFIRM_EQ(string, expected_string, action); 407 408 //-------------------------------------------------------------------------- 409 // array 410 411 uprv_strcpy(tag, "array_"); 412 uprv_strcat(tag, frag); 413 414 action = param[i].name; 415 action += ".get("; 416 action += tag; 417 action += ")"; 418 419 status = U_ZERO_ERROR; 420 ResourceBundle arrayBundle(theBundle.get(tag, status)); 421 CONFIRM_UErrorCode(status, expected_resource_status, action); 422 int32_t count = arrayBundle.getSize(); 423 424 if (U_SUCCESS(status)) 425 { 426 CONFIRM_GE(count, 1, action); 427 428 for (j=0; j < count; ++j) 429 { 430 char buf[32]; 431 UnicodeString value(arrayBundle.getStringEx(j, status)); 432 expected_string = base; 433 expected_string += itoa(j,buf); 434 CONFIRM_EQ(value, expected_string, action); 435 } 436 437 action = param[i].name; 438 action += ".getStringEx("; 439 action += tag; 440 action += ")"; 441 442 for (j=0; j<100; ++j) 443 { 444 index = count ? (randi(count * 3) - count) : (randi(200) - 100); 445 status = U_ZERO_ERROR; 446 string = kErrorUChars; 447 UnicodeString t(arrayBundle.getStringEx(index, status)); 448 expected_status = (index >= 0 && index < count) ? expected_resource_status : U_MISSING_RESOURCE_ERROR; 449 CONFIRM_UErrorCode(status, expected_status, action); 450 451 if (U_SUCCESS(status)) 452 { 453 char buf[32]; 454 expected_string = base; 455 expected_string += itoa(index,buf); 456 } 457 else 458 { 459 expected_string = kErrorUChars; 460 } 461 CONFIRM_EQ(string, expected_string, action); 462 } 463 } 464 else if (status != expected_resource_status) 465 { 466 record_fail("Error getting " + (UnicodeString)tag); 467 return (UBool)(failOrig != fail); 468 } 469 470 } 471 472 return (UBool)(failOrig != fail); 473} 474 475void 476ResourceBundleTest::record_pass(UnicodeString passMessage) 477{ 478 logln(passMessage); 479 ++pass; 480} 481void 482ResourceBundleTest::record_fail(UnicodeString errMessage) 483{ 484 err(errMessage); 485 ++fail; 486} 487 488void 489ResourceBundleTest::TestExemplar(){ 490 491 int32_t locCount = uloc_countAvailable(); 492 int32_t locIndex=0; 493 int num=0; 494 UErrorCode status = U_ZERO_ERROR; 495 for(;locIndex<locCount;locIndex++){ 496 const char* locale = uloc_getAvailable(locIndex); 497 UResourceBundle *resb =ures_open(NULL,locale,&status); 498 if(U_SUCCESS(status) && status!=U_USING_FALLBACK_WARNING && status!=U_USING_DEFAULT_WARNING){ 499 int32_t len=0; 500 const UChar* strSet = ures_getStringByKey(resb,"ExemplarCharacters",&len,&status); 501 UnicodeSet set(strSet,status); 502 if(U_FAILURE(status)){ 503 errln("Could not construct UnicodeSet from pattern for ExemplarCharacters in locale : %s. Error: %s",locale,u_errorName(status)); 504 status=U_ZERO_ERROR; 505 } 506 num++; 507 } 508 ures_close(resb); 509 } 510 logln("Number of installed locales with exemplar characters that could be tested: %d",num); 511 512} 513 514void 515ResourceBundleTest::TestGetSize(void) 516{ 517 const struct { 518 const char* key; 519 int32_t size; 520 } test[] = { 521 { "zerotest", 1}, 522 { "one", 1}, 523 { "importtest", 1}, 524 { "integerarray", 1}, 525 { "emptyarray", 0}, 526 { "emptytable", 0}, 527 { "emptystring", 1}, /* empty string is still a string */ 528 { "emptyint", 1}, 529 { "emptybin", 1}, 530 { "testinclude", 1}, 531 { "collations", 1}, /* not 2 - there is hidden %%CollationBin */ 532 }; 533 534 UErrorCode status = U_ZERO_ERROR; 535 536 const char* testdatapath = loadTestData(status); 537 int32_t i = 0, j = 0; 538 int32_t size = 0; 539 540 if(U_FAILURE(status)) 541 { 542 dataerrln("Could not load testdata.dat %s\n", u_errorName(status)); 543 return; 544 } 545 546 ResourceBundle rb(testdatapath, "testtypes", status); 547 if(U_FAILURE(status)) 548 { 549 err("Could not testtypes resource bundle %s\n", u_errorName(status)); 550 return; 551 } 552 553 for(i = 0; i < (int32_t)(sizeof(test)/sizeof(test[0])); i++) { 554 ResourceBundle res = rb.get(test[i].key, status); 555 if(U_FAILURE(status)) 556 { 557 err("Couldn't find the key %s. Error: %s\n", u_errorName(status)); 558 return; 559 } 560 size = res.getSize(); 561 if(size != test[i].size) { 562 err("Expected size %i, got size %i for key %s\n", test[i].size, size, test[i].key); 563 for(j = 0; j < size; j++) { 564 ResourceBundle helper = res.get(j, status); 565 err("%s\n", helper.getKey()); 566 } 567 } 568 } 569} 570 571void 572ResourceBundleTest::TestGetLocaleByType(void) 573{ 574 const struct { 575 const char *requestedLocale; 576 const char *resourceKey; 577 const char *validLocale; 578 const char *actualLocale; 579 } test[] = { 580 { "te_IN_BLAH", "string_only_in_te_IN", "te_IN", "te_IN" }, 581 { "te_IN_BLAH", "string_only_in_te", "te_IN", "te" }, 582 { "te_IN_BLAH", "string_only_in_Root", "te_IN", "root" }, 583 { "te_IN_BLAH_01234567890_01234567890_01234567890_01234567890_01234567890_01234567890", "array_2d_only_in_Root", "te_IN", "root" }, 584 { "te_IN_BLAH@currency=euro", "array_2d_only_in_te_IN", "te_IN", "te_IN" }, 585 { "te_IN_BLAH@calendar=thai;collation=phonebook", "array_2d_only_in_te", "te_IN", "te" } 586 }; 587 588 UErrorCode status = U_ZERO_ERROR; 589 590 const char* testdatapath = loadTestData(status); 591 int32_t i = 0; 592 Locale locale; 593 594 if(U_FAILURE(status)) 595 { 596 dataerrln("Could not load testdata.dat %s\n", u_errorName(status)); 597 return; 598 } 599 600 for(i = 0; i < (int32_t)(sizeof(test)/sizeof(test[0])); i++) { 601 ResourceBundle rb(testdatapath, test[i].requestedLocale, status); 602 if(U_FAILURE(status)) 603 { 604 err("Could not open resource bundle %s (error %s)\n", test[i].requestedLocale, u_errorName(status)); 605 status = U_ZERO_ERROR; 606 continue; 607 } 608 609 ResourceBundle res = rb.get(test[i].resourceKey, status); 610 if(U_FAILURE(status)) 611 { 612 err("Couldn't find the key %s. Error: %s\n", test[i].resourceKey, u_errorName(status)); 613 status = U_ZERO_ERROR; 614 continue; 615 } 616 617 locale = res.getLocale(ULOC_REQUESTED_LOCALE, status); 618 if(locale != Locale::getDefault()) { 619 err("Expected requested locale to be %s. Got %s\n", test[i].requestedLocale, locale.getName()); 620 } 621 locale = res.getLocale(ULOC_VALID_LOCALE, status); 622 if(strcmp(locale.getName(), test[i].validLocale) != 0) { 623 err("Expected valid locale to be %s. Got %s\n", test[i].requestedLocale, locale.getName()); 624 } 625 locale = res.getLocale(ULOC_ACTUAL_LOCALE, status); 626 if(strcmp(locale.getName(), test[i].actualLocale) != 0) { 627 err("Expected actual locale to be %s. Got %s\n", test[i].requestedLocale, locale.getName()); 628 } 629 } 630} 631 632//eof 633 634