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