1 // 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 /******************************************************************** 4 * COPYRIGHT: 5 * Copyright (c) 1997-2016, International Business Machines Corporation and 6 * others. All Rights Reserved. 7 ********************************************************************/ 8 9 10 #include "unicode/utypes.h" 11 12 /** 13 * IntlTest is a base class for tests. 14 */ 15 16 #include <assert.h> 17 #include <stdarg.h> 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <string.h> 21 22 #include "unicode/ctest.h" // for str_timeDelta 23 #include "unicode/curramt.h" 24 #include "unicode/locid.h" 25 #include "unicode/putil.h" 26 #include "unicode/smpdtfmt.h" 27 #include "unicode/timezone.h" 28 #include "unicode/uclean.h" 29 #include "unicode/ucnv.h" 30 #include "unicode/unistr.h" 31 #include "unicode/ures.h" 32 #include "unicode/utf16.h" 33 34 #include "intltest.h" 35 36 #include "caltztst.h" 37 #include "cmemory.h" 38 #include "cstring.h" 39 #include "itmajor.h" 40 #include "mutex.h" 41 #include "putilimp.h" // for uprv_getRawUTCtime() 42 #include "uassert.h" 43 #include "udbgutil.h" 44 #include "umutex.h" 45 #include "uoptions.h" 46 47 #ifdef XP_MAC_CONSOLE 48 #include <console.h> 49 #include "Files.h" 50 #endif 51 52 53 static char* _testDataPath=NULL; 54 55 // Static list of errors found 56 static UnicodeString errorList; 57 static void *knownList = NULL; // known issues 58 static UBool noKnownIssues = FALSE; // if TRUE, don't emit known issues 59 60 //----------------------------------------------------------------------------- 61 //convenience classes to ease porting code that uses the Java 62 //string-concatenation operator (moved from findword test by rtg) 63 64 // [LIU] Just to get things working 65 UnicodeString 66 UCharToUnicodeString(UChar c) 67 { return UnicodeString(c); } 68 69 // [rtg] Just to get things working 70 UnicodeString 71 operator+(const UnicodeString& left, 72 long num) 73 { 74 char buffer[64]; // nos changed from 10 to 64 75 char danger = 'p'; // guard against overrunning the buffer (rtg) 76 77 sprintf(buffer, "%ld", num); 78 assert(danger == 'p'); 79 80 return left + buffer; 81 } 82 83 UnicodeString 84 operator+(const UnicodeString& left, 85 unsigned long num) 86 { 87 char buffer[64]; // nos changed from 10 to 64 88 char danger = 'p'; // guard against overrunning the buffer (rtg) 89 90 sprintf(buffer, "%lu", num); 91 assert(danger == 'p'); 92 93 return left + buffer; 94 } 95 96 UnicodeString 97 Int64ToUnicodeString(int64_t num) 98 { 99 char buffer[64]; // nos changed from 10 to 64 100 char danger = 'p'; // guard against overrunning the buffer (rtg) 101 102 #if defined(_MSC_VER) 103 sprintf(buffer, "%I64d", num); 104 #else 105 sprintf(buffer, "%lld", (long long)num); 106 #endif 107 assert(danger == 'p'); 108 109 return buffer; 110 } 111 112 UnicodeString 113 DoubleToUnicodeString(double num) 114 { 115 char buffer[64]; // nos changed from 10 to 64 116 char danger = 'p'; // guard against overrunning the buffer (rtg) 117 118 sprintf(buffer, "%1.14e", num); 119 assert(danger == 'p'); 120 121 return buffer; 122 } 123 124 // [LIU] Just to get things working 125 UnicodeString 126 operator+(const UnicodeString& left, 127 double num) 128 { 129 char buffer[64]; // was 32, made it arbitrarily bigger (rtg) 130 char danger = 'p'; // guard against overrunning the buffer (rtg) 131 132 // IEEE floating point has 52 bits of mantissa, plus one assumed bit 133 // 53*log(2)/log(10) = 15.95 134 // so there is no need to show more than 16 digits. [alan] 135 136 sprintf(buffer, "%.17g", num); 137 assert(danger == 'p'); 138 139 return left + buffer; 140 } 141 142 #if 0 143 UnicodeString 144 operator+(const UnicodeString& left, 145 int64_t num) { 146 return left + Int64ToUnicodeString(num); 147 } 148 #endif 149 150 #if !UCONFIG_NO_FORMATTING 151 152 /** 153 * Return a string display for this, without surrounding braces. 154 */ 155 UnicodeString _toString(const Formattable& f) { 156 UnicodeString s; 157 switch (f.getType()) { 158 case Formattable::kDate: 159 { 160 UErrorCode status = U_ZERO_ERROR; 161 SimpleDateFormat fmt(status); 162 if (U_SUCCESS(status)) { 163 FieldPosition pos; 164 fmt.format(f.getDate(), s, pos); 165 s.insert(0, "Date:"); 166 } else { 167 s = UnicodeString("Error creating date format]"); 168 } 169 } 170 break; 171 case Formattable::kDouble: 172 s = UnicodeString("double:") + f.getDouble(); 173 break; 174 case Formattable::kLong: 175 s = UnicodeString("long:") + f.getLong(); 176 break; 177 178 case Formattable::kInt64: 179 s = UnicodeString("int64:") + Int64ToUnicodeString(f.getInt64()); 180 break; 181 182 case Formattable::kString: 183 f.getString(s); 184 s.insert(0, "String:"); 185 break; 186 case Formattable::kArray: 187 { 188 int32_t i, n; 189 const Formattable* array = f.getArray(n); 190 s.insert(0, UnicodeString("Array:")); 191 UnicodeString delim(", "); 192 for (i=0; i<n; ++i) { 193 if (i > 0) { 194 s.append(delim); 195 } 196 s = s + _toString(array[i]); 197 } 198 } 199 break; 200 case Formattable::kObject: { 201 const CurrencyAmount* c = dynamic_cast<const CurrencyAmount*>(f.getObject()); 202 if (c != NULL) { 203 s = _toString(c->getNumber()) + " " + UnicodeString(c->getISOCurrency()); 204 } else { 205 s = UnicodeString("Unknown UObject"); 206 } 207 break; 208 } 209 default: 210 s = UnicodeString("Unknown Formattable type=") + (int32_t)f.getType(); 211 break; 212 } 213 return s; 214 } 215 216 /** 217 * Originally coded this as operator+, but that makes the expression 218 * + char* ambiguous. - liu 219 */ 220 UnicodeString toString(const Formattable& f) { 221 UnicodeString s((UChar)91/*[*/); 222 s.append(_toString(f)); 223 s.append((UChar)0x5d/*]*/); 224 return s; 225 } 226 227 #endif 228 229 // useful when operator+ won't cooperate 230 UnicodeString toString(int32_t n) { 231 return UnicodeString() + (long)n; 232 } 233 234 235 236 UnicodeString toString(UBool b) { 237 return b ? UnicodeString("TRUE"):UnicodeString("FALSE"); 238 } 239 240 // stephen - cleaned up 05/05/99 241 UnicodeString operator+(const UnicodeString& left, char num) 242 { return left + (long)num; } 243 UnicodeString operator+(const UnicodeString& left, short num) 244 { return left + (long)num; } 245 UnicodeString operator+(const UnicodeString& left, int num) 246 { return left + (long)num; } 247 UnicodeString operator+(const UnicodeString& left, unsigned char num) 248 { return left + (unsigned long)num; } 249 UnicodeString operator+(const UnicodeString& left, unsigned short num) 250 { return left + (unsigned long)num; } 251 UnicodeString operator+(const UnicodeString& left, unsigned int num) 252 { return left + (unsigned long)num; } 253 UnicodeString operator+(const UnicodeString& left, float num) 254 { return left + (double)num; } 255 256 //------------------ 257 258 // Append a hex string to the target 259 UnicodeString& 260 IntlTest::appendHex(uint32_t number, 261 int32_t digits, 262 UnicodeString& target) 263 { 264 static const UChar digitString[] = { 265 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 266 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0 267 }; /* "0123456789ABCDEF" */ 268 269 if (digits < 0) { // auto-digits 270 digits = 2; 271 uint32_t max = 0xff; 272 while (number > max) { 273 digits += 2; 274 max = (max << 8) | 0xff; 275 } 276 } 277 switch (digits) 278 { 279 case 8: 280 target += digitString[(number >> 28) & 0xF]; 281 U_FALLTHROUGH; 282 case 7: 283 target += digitString[(number >> 24) & 0xF]; 284 U_FALLTHROUGH; 285 case 6: 286 target += digitString[(number >> 20) & 0xF]; 287 U_FALLTHROUGH; 288 case 5: 289 target += digitString[(number >> 16) & 0xF]; 290 U_FALLTHROUGH; 291 case 4: 292 target += digitString[(number >> 12) & 0xF]; 293 U_FALLTHROUGH; 294 case 3: 295 target += digitString[(number >> 8) & 0xF]; 296 U_FALLTHROUGH; 297 case 2: 298 target += digitString[(number >> 4) & 0xF]; 299 U_FALLTHROUGH; 300 case 1: 301 target += digitString[(number >> 0) & 0xF]; 302 break; 303 default: 304 target += "**"; 305 } 306 return target; 307 } 308 309 UnicodeString 310 IntlTest::toHex(uint32_t number, int32_t digits) { 311 UnicodeString result; 312 appendHex(number, digits, result); 313 return result; 314 } 315 316 static inline UBool isPrintable(UChar32 c) { 317 return c <= 0x7E && (c >= 0x20 || c == 9 || c == 0xA || c == 0xD); 318 } 319 320 // Replace nonprintable characters with unicode escapes 321 UnicodeString& 322 IntlTest::prettify(const UnicodeString &source, 323 UnicodeString &target) 324 { 325 int32_t i; 326 327 target.remove(); 328 target += "\""; 329 330 for (i = 0; i < source.length(); ) 331 { 332 UChar32 ch = source.char32At(i); 333 i += U16_LENGTH(ch); 334 335 if (!isPrintable(ch)) 336 { 337 if (ch <= 0xFFFF) { 338 target += "\\u"; 339 appendHex(ch, 4, target); 340 } else { 341 target += "\\U"; 342 appendHex(ch, 8, target); 343 } 344 } 345 else 346 { 347 target += ch; 348 } 349 } 350 351 target += "\""; 352 353 return target; 354 } 355 356 // Replace nonprintable characters with unicode escapes 357 UnicodeString 358 IntlTest::prettify(const UnicodeString &source, UBool parseBackslash) 359 { 360 int32_t i; 361 UnicodeString target; 362 target.remove(); 363 target += "\""; 364 365 for (i = 0; i < source.length();) 366 { 367 UChar32 ch = source.char32At(i); 368 i += U16_LENGTH(ch); 369 370 if (!isPrintable(ch)) 371 { 372 if (parseBackslash) { 373 // If we are preceded by an odd number of backslashes, 374 // then this character has already been backslash escaped. 375 // Delete a backslash. 376 int32_t backslashCount = 0; 377 for (int32_t j=target.length()-1; j>=0; --j) { 378 if (target.charAt(j) == (UChar)92) { 379 ++backslashCount; 380 } else { 381 break; 382 } 383 } 384 if ((backslashCount % 2) == 1) { 385 target.truncate(target.length() - 1); 386 } 387 } 388 if (ch <= 0xFFFF) { 389 target += "\\u"; 390 appendHex(ch, 4, target); 391 } else { 392 target += "\\U"; 393 appendHex(ch, 8, target); 394 } 395 } 396 else 397 { 398 target += ch; 399 } 400 } 401 402 target += "\""; 403 404 return target; 405 } 406 407 /* IntlTest::setICU_DATA - if the ICU_DATA environment variable is not already 408 * set, try to deduce the directory in which ICU was built, 409 * and set ICU_DATA to "icu/source/data" in that location. 410 * The intent is to allow the tests to have a good chance 411 * of running without requiring that the user manually set 412 * ICU_DATA. Common data isn't a problem, since it is 413 * picked up via a static (build time) reference, but the 414 * tests dynamically load some data. 415 */ 416 void IntlTest::setICU_DATA() { 417 const char *original_ICU_DATA = getenv("ICU_DATA"); 418 419 if (original_ICU_DATA != NULL && *original_ICU_DATA != 0) { 420 /* If the user set ICU_DATA, don't second-guess the person. */ 421 return; 422 } 423 424 // U_TOPBUILDDIR is set by the makefiles on UNIXes when building cintltst and intltst 425 // to point to the top of the build hierarchy, which may or 426 // may not be the same as the source directory, depending on 427 // the configure options used. At any rate, 428 // set the data path to the built data from this directory. 429 // The value is complete with quotes, so it can be used 430 // as-is as a string constant. 431 432 #if defined (U_TOPBUILDDIR) 433 { 434 static char env_string[] = U_TOPBUILDDIR "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING; 435 u_setDataDirectory(env_string); 436 return; 437 } 438 439 #else 440 // Use #else so we don't get compiler warnings due to the return above. 441 442 /* On Windows, the file name obtained from __FILE__ includes a full path. 443 * This file is "wherever\icu\source\test\cintltst\cintltst.c" 444 * Change to "wherever\icu\source\data" 445 */ 446 { 447 char p[sizeof(__FILE__) + 10]; 448 char *pBackSlash; 449 int i; 450 451 strcpy(p, __FILE__); 452 /* We want to back over three '\' chars. */ 453 /* Only Windows should end up here, so looking for '\' is safe. */ 454 for (i=1; i<=3; i++) { 455 pBackSlash = strrchr(p, U_FILE_SEP_CHAR); 456 if (pBackSlash != NULL) { 457 *pBackSlash = 0; /* Truncate the string at the '\' */ 458 } 459 } 460 461 if (pBackSlash != NULL) { 462 /* We found and truncated three names from the path. 463 * Now append "source\data" and set the environment 464 */ 465 strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING); 466 u_setDataDirectory(p); /* p is "ICU_DATA=wherever\icu\source\data" */ 467 return; 468 } 469 else { 470 /* __FILE__ on MSVC7 does not contain the directory */ 471 u_setDataDirectory(".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING); 472 return; 473 } 474 } 475 #endif 476 477 /* No location for the data dir was identifiable. 478 * Add other fallbacks for the test data location here if the need arises 479 */ 480 } 481 482 483 //-------------------------------------------------------------------------------------- 484 485 static const int32_t indentLevel_offset = 3; 486 static const char delim = '/'; 487 488 IntlTest* IntlTest::gTest = NULL; 489 490 static int32_t execCount = 0; 491 492 void it_log( UnicodeString message ) 493 { 494 if (IntlTest::gTest) 495 IntlTest::gTest->log( message ); 496 } 497 498 void it_logln( UnicodeString message ) 499 { 500 if (IntlTest::gTest) 501 IntlTest::gTest->logln( message ); 502 } 503 504 void it_logln( void ) 505 { 506 if (IntlTest::gTest) 507 IntlTest::gTest->logln(); 508 } 509 510 void it_info( UnicodeString message ) 511 { 512 if (IntlTest::gTest) 513 IntlTest::gTest->info( message ); 514 } 515 516 void it_infoln( UnicodeString message ) 517 { 518 if (IntlTest::gTest) 519 IntlTest::gTest->infoln( message ); 520 } 521 522 void it_infoln( void ) 523 { 524 if (IntlTest::gTest) 525 IntlTest::gTest->infoln(); 526 } 527 528 void it_err() 529 { 530 if (IntlTest::gTest) 531 IntlTest::gTest->err(); 532 } 533 534 void it_err( UnicodeString message ) 535 { 536 if (IntlTest::gTest) 537 IntlTest::gTest->err( message ); 538 } 539 540 void it_errln( UnicodeString message ) 541 { 542 if (IntlTest::gTest) 543 IntlTest::gTest->errln( message ); 544 } 545 546 void it_dataerr( UnicodeString message ) 547 { 548 if (IntlTest::gTest) 549 IntlTest::gTest->dataerr( message ); 550 } 551 552 void it_dataerrln( UnicodeString message ) 553 { 554 if (IntlTest::gTest) 555 IntlTest::gTest->dataerrln( message ); 556 } 557 558 IntlTest::IntlTest() 559 { 560 caller = NULL; 561 testPath = NULL; 562 LL_linestart = TRUE; 563 errorCount = 0; 564 dataErrorCount = 0; 565 verbose = FALSE; 566 no_time = FALSE; 567 no_err_msg = FALSE; 568 warn_on_missing_data = FALSE; 569 quick = FALSE; 570 leaks = FALSE; 571 threadCount = 12; 572 testoutfp = stdout; 573 LL_indentlevel = indentLevel_offset; 574 numProps = 0; 575 strcpy(basePath, "/"); 576 currName[0]=0; 577 } 578 579 void IntlTest::setCaller( IntlTest* callingTest ) 580 { 581 caller = callingTest; 582 if (caller) { 583 warn_on_missing_data = caller->warn_on_missing_data; 584 verbose = caller->verbose; 585 no_err_msg = caller->no_err_msg; 586 quick = caller->quick; 587 threadCount = caller->threadCount; 588 testoutfp = caller->testoutfp; 589 LL_indentlevel = caller->LL_indentlevel + indentLevel_offset; 590 numProps = caller->numProps; 591 for (int32_t i = 0; i < numProps; i++) { 592 proplines[i] = caller->proplines[i]; 593 } 594 } 595 } 596 597 UBool IntlTest::callTest( IntlTest& testToBeCalled, char* par ) 598 { 599 execCount--; // correct a previously assumed test-exec, as this only calls a subtest 600 testToBeCalled.setCaller( this ); 601 strcpy(testToBeCalled.basePath, this->basePath ); 602 UBool result = testToBeCalled.runTest( testPath, par, testToBeCalled.basePath ); 603 strcpy(testToBeCalled.basePath, this->basePath ); // reset it. 604 return result; 605 } 606 607 void IntlTest::setPath( char* pathVal ) 608 { 609 this->testPath = pathVal; 610 } 611 612 UBool IntlTest::setVerbose( UBool verboseVal ) 613 { 614 UBool rval = this->verbose; 615 this->verbose = verboseVal; 616 return rval; 617 } 618 619 UBool IntlTest::setNotime( UBool no_time ) 620 { 621 UBool rval = this->no_time; 622 this->no_time = no_time; 623 return rval; 624 } 625 626 UBool IntlTest::setWarnOnMissingData( UBool warn_on_missing_dataVal ) 627 { 628 UBool rval = this->warn_on_missing_data; 629 this->warn_on_missing_data = warn_on_missing_dataVal; 630 return rval; 631 } 632 633 UBool IntlTest::setNoErrMsg( UBool no_err_msgVal ) 634 { 635 UBool rval = this->no_err_msg; 636 this->no_err_msg = no_err_msgVal; 637 return rval; 638 } 639 640 UBool IntlTest::setQuick( UBool quickVal ) 641 { 642 UBool rval = this->quick; 643 this->quick = quickVal; 644 return rval; 645 } 646 647 UBool IntlTest::setLeaks( UBool leaksVal ) 648 { 649 UBool rval = this->leaks; 650 this->leaks = leaksVal; 651 return rval; 652 } 653 654 int32_t IntlTest::setThreadCount( int32_t count ) 655 { 656 int32_t rval = this->threadCount; 657 this->threadCount = count; 658 return rval; 659 } 660 661 int32_t IntlTest::getErrors( void ) 662 { 663 return errorCount; 664 } 665 666 int32_t IntlTest::getDataErrors( void ) 667 { 668 return dataErrorCount; 669 } 670 671 UBool IntlTest::runTest( char* name, char* par, char *baseName ) 672 { 673 UBool rval; 674 char* pos = NULL; 675 676 char* baseNameBuffer = NULL; 677 678 if(baseName == NULL) { 679 baseNameBuffer = (char*)malloc(1024); 680 baseName=baseNameBuffer; 681 strcpy(baseName, "/"); 682 } 683 684 if (name) 685 pos = strchr( name, delim ); // check if name contains path (by looking for '/') 686 if (pos) { 687 testPath = pos+1; // store subpath for calling subtest 688 *pos = 0; // split into two strings 689 }else{ 690 testPath = NULL; 691 } 692 693 if (!name || (name[0] == 0) || (strcmp(name, "*") == 0)) { 694 rval = runTestLoop( NULL, par, baseName ); 695 696 }else if (strcmp( name, "LIST" ) == 0) { 697 this->usage(); 698 rval = TRUE; 699 700 }else{ 701 rval = runTestLoop( name, par, baseName ); 702 } 703 704 if (pos) 705 *pos = delim; // restore original value at pos 706 if(baseNameBuffer!=NULL) { 707 free(baseNameBuffer); 708 } 709 return rval; 710 } 711 712 // call individual tests, to be overridden to call implementations 713 void IntlTest::runIndexedTest( int32_t /*index*/, UBool /*exec*/, const char* & /*name*/, char* /*par*/ ) 714 { 715 // to be overridden by a method like: 716 /* 717 switch (index) { 718 case 0: name = "First Test"; if (exec) FirstTest( par ); break; 719 case 1: name = "Second Test"; if (exec) SecondTest( par ); break; 720 default: name = ""; break; 721 } 722 */ 723 this->errln("*** runIndexedTest needs to be overridden! ***"); 724 } 725 726 727 UBool IntlTest::runTestLoop( char* testname, char* par, char *baseName ) 728 { 729 int32_t index = 0; 730 const char* name; 731 UBool run_this_test; 732 int32_t lastErrorCount; 733 UBool rval = FALSE; 734 UBool lastTestFailed; 735 736 if(baseName == NULL) { 737 printf("ERROR: baseName can't be null.\n"); 738 return FALSE; 739 } else { 740 if ((char *)this->basePath != baseName) { 741 strcpy(this->basePath, baseName); 742 } 743 } 744 745 char * saveBaseLoc = baseName+strlen(baseName); 746 747 IntlTest* saveTest = gTest; 748 gTest = this; 749 do { 750 this->runIndexedTest( index, FALSE, name, par ); 751 if (strcmp(name,"skip") == 0) { 752 run_this_test = FALSE; 753 } else { 754 if (!name || (name[0] == 0)) 755 break; 756 if (!testname) { 757 run_this_test = TRUE; 758 }else{ 759 run_this_test = (UBool) (strcmp( name, testname ) == 0); 760 } 761 } 762 if (run_this_test) { 763 lastErrorCount = errorCount; 764 execCount++; 765 char msg[256]; 766 sprintf(msg, "%s {", name); 767 LL_message(msg, TRUE); 768 UDate timeStart = uprv_getRawUTCtime(); 769 strcpy(saveBaseLoc,name); 770 strcat(saveBaseLoc,"/"); 771 772 strcpy(currName, name); // set 773 this->runIndexedTest( index, TRUE, name, par ); 774 currName[0]=0; // reset 775 776 UDate timeStop = uprv_getRawUTCtime(); 777 rval = TRUE; // at least one test has been called 778 char secs[256]; 779 if(!no_time) { 780 sprintf(secs, "%f", (timeStop-timeStart)/1000.0); 781 } else { 782 secs[0]=0; 783 } 784 785 786 strcpy(saveBaseLoc,name); 787 788 789 ctest_xml_testcase(baseName, name, secs, (lastErrorCount!=errorCount)?"err":NULL); 790 791 792 saveBaseLoc[0]=0; /* reset path */ 793 794 if (lastErrorCount == errorCount) { 795 sprintf( msg, " } OK: %s ", name ); 796 if(!no_time) str_timeDelta(msg+strlen(msg),timeStop-timeStart); 797 lastTestFailed = FALSE; 798 }else{ 799 sprintf(msg, " } ERRORS (%li) in %s", (long)(errorCount-lastErrorCount), name); 800 if(!no_time) str_timeDelta(msg+strlen(msg),timeStop-timeStart); 801 802 for(int i=0;i<LL_indentlevel;i++) { 803 errorList += " "; 804 } 805 errorList += name; 806 errorList += "\n"; 807 lastTestFailed = TRUE; 808 } 809 LL_indentlevel -= 3; 810 if (lastTestFailed) { 811 LL_message( "", TRUE); 812 } 813 LL_message( msg, TRUE); 814 if (lastTestFailed) { 815 LL_message( "", TRUE); 816 } 817 LL_indentlevel += 3; 818 } 819 index++; 820 }while(name); 821 822 *saveBaseLoc = 0; 823 824 gTest = saveTest; 825 return rval; 826 } 827 828 829 /** 830 * Adds given string to the log if we are in verbose mode. 831 */ 832 void IntlTest::log( const UnicodeString &message ) 833 { 834 if( verbose ) { 835 LL_message( message, FALSE ); 836 } 837 } 838 839 /** 840 * Adds given string to the log if we are in verbose mode. Adds a new line to 841 * the given message. 842 */ 843 void IntlTest::logln( const UnicodeString &message ) 844 { 845 if( verbose ) { 846 LL_message( message, TRUE ); 847 } 848 } 849 850 void IntlTest::logln( void ) 851 { 852 if( verbose ) { 853 LL_message( "", TRUE ); 854 } 855 } 856 857 /** 858 * Unconditionally adds given string to the log. 859 */ 860 void IntlTest::info( const UnicodeString &message ) 861 { 862 LL_message( message, FALSE ); 863 } 864 865 /** 866 * Unconditionally adds given string to the log. Adds a new line to 867 * the given message. 868 */ 869 void IntlTest::infoln( const UnicodeString &message ) 870 { 871 LL_message( message, TRUE ); 872 } 873 874 void IntlTest::infoln( void ) 875 { 876 LL_message( "", TRUE ); 877 } 878 879 int32_t IntlTest::IncErrorCount( void ) 880 { 881 errorCount++; 882 if (caller) caller->IncErrorCount(); 883 return errorCount; 884 } 885 886 int32_t IntlTest::IncDataErrorCount( void ) 887 { 888 dataErrorCount++; 889 if (caller) caller->IncDataErrorCount(); 890 return dataErrorCount; 891 } 892 893 void IntlTest::err() 894 { 895 IncErrorCount(); 896 } 897 898 void IntlTest::err( const UnicodeString &message ) 899 { 900 IncErrorCount(); 901 if (!no_err_msg) LL_message( message, FALSE ); 902 } 903 904 void IntlTest::errln( const UnicodeString &message ) 905 { 906 IncErrorCount(); 907 if (!no_err_msg) LL_message( message, TRUE ); 908 } 909 910 void IntlTest::dataerr( const UnicodeString &message ) 911 { 912 IncDataErrorCount(); 913 914 if (!warn_on_missing_data) { 915 IncErrorCount(); 916 } 917 918 if (!no_err_msg) LL_message( message, FALSE ); 919 } 920 921 void IntlTest::dataerrln( const UnicodeString &message ) 922 { 923 int32_t errCount = IncDataErrorCount(); 924 UnicodeString msg; 925 if (!warn_on_missing_data) { 926 IncErrorCount(); 927 msg = message; 928 } else { 929 msg = UnicodeString("[DATA] " + message); 930 } 931 932 if (!no_err_msg) { 933 if ( errCount == 1) { 934 LL_message( msg + " - (Are you missing data?)", TRUE ); // only show this message the first time 935 } else { 936 LL_message( msg , TRUE ); 937 } 938 } 939 } 940 941 void IntlTest::errcheckln(UErrorCode status, const UnicodeString &message ) { 942 if (status == U_FILE_ACCESS_ERROR || status == U_MISSING_RESOURCE_ERROR) { 943 dataerrln(message); 944 } else { 945 errln(message); 946 } 947 } 948 949 /* convenience functions that include sprintf formatting */ 950 void IntlTest::log(const char *fmt, ...) 951 { 952 char buffer[4000]; 953 va_list ap; 954 955 va_start(ap, fmt); 956 /* sprintf it just to make sure that the information is valid */ 957 vsprintf(buffer, fmt, ap); 958 va_end(ap); 959 if( verbose ) { 960 log(UnicodeString(buffer, (const char *)NULL)); 961 } 962 } 963 964 void IntlTest::logln(const char *fmt, ...) 965 { 966 char buffer[4000]; 967 va_list ap; 968 969 va_start(ap, fmt); 970 /* sprintf it just to make sure that the information is valid */ 971 vsprintf(buffer, fmt, ap); 972 va_end(ap); 973 if( verbose ) { 974 logln(UnicodeString(buffer, (const char *)NULL)); 975 } 976 } 977 978 UBool IntlTest::logKnownIssue(const char *ticket, const char *fmt, ...) 979 { 980 char buffer[4000]; 981 va_list ap; 982 983 va_start(ap, fmt); 984 /* sprintf it just to make sure that the information is valid */ 985 vsprintf(buffer, fmt, ap); 986 va_end(ap); 987 return logKnownIssue(ticket, UnicodeString(buffer, (const char *)NULL)); 988 } 989 990 UBool IntlTest::logKnownIssue(const char *ticket) { 991 return logKnownIssue(ticket, UnicodeString()); 992 } 993 994 UBool IntlTest::logKnownIssue(const char *ticket, const UnicodeString &msg) { 995 if(noKnownIssues) return FALSE; 996 997 char fullpath[2048]; 998 strcpy(fullpath, basePath); 999 strcat(fullpath, currName); 1000 UnicodeString msg2 = msg; 1001 UBool firstForTicket = TRUE, firstForWhere = TRUE; 1002 knownList = udbg_knownIssue_openU(knownList, ticket, fullpath, msg2.getTerminatedBuffer(), &firstForTicket, &firstForWhere); 1003 1004 msg2 = UNICODE_STRING_SIMPLE("(Known issue #") + 1005 UnicodeString(ticket, -1, US_INV) + UNICODE_STRING_SIMPLE(") ") + msg; 1006 if(firstForTicket || firstForWhere) { 1007 infoln(msg2); 1008 } else { 1009 logln(msg2); 1010 } 1011 1012 return TRUE; 1013 } 1014 1015 /* convenience functions that include sprintf formatting */ 1016 void IntlTest::info(const char *fmt, ...) 1017 { 1018 char buffer[4000]; 1019 va_list ap; 1020 1021 va_start(ap, fmt); 1022 /* sprintf it just to make sure that the information is valid */ 1023 vsprintf(buffer, fmt, ap); 1024 va_end(ap); 1025 info(UnicodeString(buffer, (const char *)NULL)); 1026 } 1027 1028 void IntlTest::infoln(const char *fmt, ...) 1029 { 1030 char buffer[4000]; 1031 va_list ap; 1032 1033 va_start(ap, fmt); 1034 /* sprintf it just to make sure that the information is valid */ 1035 vsprintf(buffer, fmt, ap); 1036 va_end(ap); 1037 infoln(UnicodeString(buffer, (const char *)NULL)); 1038 } 1039 1040 void IntlTest::err(const char *fmt, ...) 1041 { 1042 char buffer[4000]; 1043 va_list ap; 1044 1045 va_start(ap, fmt); 1046 vsprintf(buffer, fmt, ap); 1047 va_end(ap); 1048 err(UnicodeString(buffer, (const char *)NULL)); 1049 } 1050 1051 void IntlTest::errln(const char *fmt, ...) 1052 { 1053 char buffer[4000]; 1054 va_list ap; 1055 1056 va_start(ap, fmt); 1057 vsprintf(buffer, fmt, ap); 1058 va_end(ap); 1059 errln(UnicodeString(buffer, (const char *)NULL)); 1060 } 1061 1062 void IntlTest::dataerrln(const char *fmt, ...) 1063 { 1064 char buffer[4000]; 1065 va_list ap; 1066 1067 va_start(ap, fmt); 1068 vsprintf(buffer, fmt, ap); 1069 va_end(ap); 1070 dataerrln(UnicodeString(buffer, (const char *)NULL)); 1071 } 1072 1073 void IntlTest::errcheckln(UErrorCode status, const char *fmt, ...) 1074 { 1075 char buffer[4000]; 1076 va_list ap; 1077 1078 va_start(ap, fmt); 1079 vsprintf(buffer, fmt, ap); 1080 va_end(ap); 1081 1082 if (status == U_FILE_ACCESS_ERROR || status == U_MISSING_RESOURCE_ERROR) { 1083 dataerrln(UnicodeString(buffer, (const char *)NULL)); 1084 } else { 1085 errln(UnicodeString(buffer, (const char *)NULL)); 1086 } 1087 } 1088 1089 void IntlTest::printErrors() 1090 { 1091 IntlTest::LL_message(errorList, TRUE); 1092 } 1093 1094 UBool IntlTest::printKnownIssues() 1095 { 1096 if(knownList != NULL) { 1097 udbg_knownIssue_print(knownList); 1098 udbg_knownIssue_close(knownList); 1099 return TRUE; 1100 } else { 1101 return FALSE; 1102 } 1103 } 1104 1105 static UMutex messageMutex = U_MUTEX_INITIALIZER; 1106 1107 void IntlTest::LL_message( UnicodeString message, UBool newline ) 1108 { 1109 // Synchronize this function. 1110 // All error messages generated by tests funnel through here. 1111 // Multithreaded tests can concurrently generate errors, requiring synchronization 1112 // to keep each message together. 1113 Mutex lock(&messageMutex); 1114 1115 // string that starts with a LineFeed character and continues 1116 // with spaces according to the current indentation 1117 static const UChar indentUChars[] = { 1118 '\n', 1119 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1120 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1121 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1122 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1123 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1124 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1125 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1126 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1127 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 1128 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 1129 }; 1130 U_ASSERT(1 + LL_indentlevel <= UPRV_LENGTHOF(indentUChars)); 1131 UnicodeString indent(FALSE, indentUChars, 1 + LL_indentlevel); 1132 1133 char buffer[30000]; 1134 int32_t length; 1135 1136 // stream out the indentation string first if necessary 1137 length = indent.extract(1, indent.length(), buffer, sizeof(buffer)); 1138 if (length > 0) { 1139 fwrite(buffer, sizeof(*buffer), length, (FILE *)testoutfp); 1140 } 1141 1142 // replace each LineFeed by the indentation string 1143 message.findAndReplace(UnicodeString((UChar)'\n'), indent); 1144 1145 // stream out the message 1146 length = message.extract(0, message.length(), buffer, sizeof(buffer)); 1147 if (length > 0) { 1148 length = length > 30000 ? 30000 : length; 1149 fwrite(buffer, sizeof(*buffer), length, (FILE *)testoutfp); 1150 } 1151 1152 if (newline) { 1153 char newLine = '\n'; 1154 fwrite(&newLine, sizeof(newLine), 1, (FILE *)testoutfp); 1155 } 1156 1157 // A newline usually flushes the buffer, but 1158 // flush the message just in case of a core dump. 1159 fflush((FILE *)testoutfp); 1160 } 1161 1162 /** 1163 * Print a usage message for this test class. 1164 */ 1165 void IntlTest::usage( void ) 1166 { 1167 UBool save_verbose = setVerbose( TRUE ); 1168 logln("Test names:"); 1169 logln("-----------"); 1170 1171 int32_t index = 0; 1172 const char* name = NULL; 1173 do{ 1174 this->runIndexedTest( index, FALSE, name ); 1175 if (!name) break; 1176 logln(name); 1177 index++; 1178 }while (name && (name[0] != 0)); 1179 setVerbose( save_verbose ); 1180 } 1181 1182 1183 // memory leak reporting software will be able to take advantage of the testsuite 1184 // being run a second time local to a specific method in order to report only actual leaks 1185 UBool 1186 IntlTest::run_phase2( char* name, char* par ) // supports reporting memory leaks 1187 { 1188 UnicodeString* strLeak = new UnicodeString("forced leak"); // for verifying purify filter 1189 strLeak->append(" for verifying purify filter"); 1190 return this->runTest( name, par ); 1191 } 1192 1193 1194 #if UCONFIG_NO_LEGACY_CONVERSION 1195 # define TRY_CNV_1 "iso-8859-1" 1196 # define TRY_CNV_2 "ibm-1208" 1197 #else 1198 # define TRY_CNV_1 "iso-8859-7" 1199 # define TRY_CNV_2 "sjis" 1200 #endif 1201 1202 #ifdef UNISTR_COUNT_FINAL_STRING_LENGTHS 1203 U_CAPI void unistr_printLengths(); 1204 #endif 1205 1206 int 1207 main(int argc, char* argv[]) 1208 { 1209 UBool syntax = FALSE; 1210 UBool all = FALSE; 1211 UBool verbose = FALSE; 1212 UBool no_err_msg = FALSE; 1213 UBool no_time = FALSE; 1214 UBool quick = TRUE; 1215 UBool name = FALSE; 1216 UBool leaks = FALSE; 1217 UBool utf8 = FALSE; 1218 const char *summary_file = NULL; 1219 UBool warnOnMissingData = FALSE; 1220 UBool defaultDataFound = FALSE; 1221 int32_t threadCount = 12; 1222 UErrorCode errorCode = U_ZERO_ERROR; 1223 UConverter *cnv = NULL; 1224 const char *warnOrErr = "Failure"; 1225 UDate startTime, endTime; 1226 int32_t diffTime; 1227 const char *props[IntlTest::kMaxProps]; 1228 int32_t nProps = 0; 1229 1230 U_MAIN_INIT_ARGS(argc, argv); 1231 1232 startTime = uprv_getRawUTCtime(); 1233 1234 for (int i = 1; i < argc; ++i) { 1235 if (argv[i][0] == '-') { 1236 const char* str = argv[i] + 1; 1237 if (strcmp("verbose", str) == 0 || 1238 strcmp("v", str) == 0) 1239 verbose = TRUE; 1240 else if (strcmp("noerrormsg", str) == 0 || 1241 strcmp("n", str) == 0) 1242 no_err_msg = TRUE; 1243 else if (strcmp("exhaustive", str) == 0 || 1244 strcmp("e", str) == 0) 1245 quick = FALSE; 1246 else if (strcmp("all", str) == 0 || 1247 strcmp("a", str) == 0) 1248 all = TRUE; 1249 else if (strcmp("utf-8", str) == 0 || 1250 strcmp("u", str) == 0) 1251 utf8 = TRUE; 1252 else if (strcmp("noknownissues", str) == 0 || 1253 strcmp("K", str) == 0) 1254 noKnownIssues = TRUE; 1255 else if (strcmp("leaks", str) == 0 || 1256 strcmp("l", str) == 0) 1257 leaks = TRUE; 1258 else if (strcmp("notime", str) == 0 || 1259 strcmp("T", str) == 0) 1260 no_time = TRUE; 1261 else if (strncmp("E", str, 1) == 0) 1262 summary_file = str+1; 1263 else if (strcmp("x", str)==0) { 1264 if(++i>=argc) { 1265 printf("* Error: '-x' option requires an argument. usage: '-x outfile.xml'.\n"); 1266 syntax = TRUE; 1267 } 1268 if(ctest_xml_setFileName(argv[i])) { /* set the name */ 1269 return 1; /* error */ 1270 } 1271 } else if (strcmp("w", str) == 0) { 1272 warnOnMissingData = TRUE; 1273 warnOrErr = "WARNING"; 1274 } 1275 else if (strncmp("threads:", str, 8) == 0) { 1276 threadCount = atoi(str + 8); 1277 } 1278 else if (strncmp("prop:", str, 5) == 0) { 1279 if (nProps < IntlTest::kMaxProps) { 1280 props[nProps] = str + 5; 1281 } 1282 nProps++; 1283 } 1284 else { 1285 syntax = TRUE; 1286 } 1287 }else{ 1288 name = TRUE; 1289 } 1290 } 1291 1292 if (!all && !name) { 1293 all = TRUE; 1294 } else if (all && name) { 1295 syntax = TRUE; 1296 } 1297 1298 if (syntax) { 1299 fprintf(stdout, 1300 "### Syntax:\n" 1301 "### IntlTest [-option1 -option2 ...] [testname1 testname2 ...] \n" 1302 "### \n" 1303 "### Options are: verbose (v), all (a), noerrormsg (n), \n" 1304 "### exhaustive (e), leaks (l), -x xmlfile.xml, prop:<propery>=<value>, \n" 1305 "### notime (T), \n" 1306 "### threads:<threadCount>\n" 1307 "### (The default thread count is 12.),\n" 1308 "### (Specify either -all (shortcut -a) or a test name). \n" 1309 "### -all will run all of the tests.\n" 1310 "### \n" 1311 "### To get a list of the test names type: intltest LIST \n" 1312 "### To run just the utility tests type: intltest utility \n" 1313 "### \n" 1314 "### Test names can be nested using slashes (\"testA/subtest1\") \n" 1315 "### For example to list the utility tests type: intltest utility/LIST \n" 1316 "### To run just the Locale test type: intltest utility/LocaleTest \n" 1317 "### \n" 1318 "### A parameter can be specified for a test by appending '@' and the value \n" 1319 "### to the testname. \n\n"); 1320 return 1; 1321 } 1322 1323 if (nProps > IntlTest::kMaxProps) { 1324 fprintf(stdout, "### Too many properties. Exiting.\n"); 1325 } 1326 1327 MajorTestLevel major; 1328 major.setVerbose( verbose ); 1329 major.setNoErrMsg( no_err_msg ); 1330 major.setQuick( quick ); 1331 major.setLeaks( leaks ); 1332 major.setThreadCount( threadCount ); 1333 major.setWarnOnMissingData( warnOnMissingData ); 1334 major.setNotime (no_time); 1335 for (int32_t i = 0; i < nProps; i++) { 1336 major.setProperty(props[i]); 1337 } 1338 1339 1340 fprintf(stdout, "-----------------------------------------------\n"); 1341 fprintf(stdout, " IntlTest (C++) Test Suite for \n"); 1342 fprintf(stdout, " International Components for Unicode %s\n", U_ICU_VERSION); 1343 1344 1345 { 1346 const char *charsetFamily = "Unknown"; 1347 int32_t voidSize = (int32_t)sizeof(void*); 1348 int32_t bits = voidSize * 8; 1349 if(U_CHARSET_FAMILY==U_ASCII_FAMILY) { 1350 charsetFamily="ASCII"; 1351 } else if(U_CHARSET_FAMILY==U_EBCDIC_FAMILY) { 1352 charsetFamily="EBCDIC"; 1353 } 1354 fprintf(stdout, 1355 " Bits: %d, Byte order: %s, Chars: %s\n", 1356 bits, U_IS_BIG_ENDIAN?"Big endian":"Little endian", 1357 charsetFamily); 1358 } 1359 fprintf(stdout, "-----------------------------------------------\n"); 1360 fprintf(stdout, " Options: \n"); 1361 fprintf(stdout, " all (a) : %s\n", (all? "On" : "Off")); 1362 fprintf(stdout, " Verbose (v) : %s\n", (verbose? "On" : "Off")); 1363 fprintf(stdout, " No error messages (n) : %s\n", (no_err_msg? "On" : "Off")); 1364 fprintf(stdout, " Exhaustive (e) : %s\n", (!quick? "On" : "Off")); 1365 fprintf(stdout, " Leaks (l) : %s\n", (leaks? "On" : "Off")); 1366 fprintf(stdout, " utf-8 (u) : %s\n", (utf8? "On" : "Off")); 1367 fprintf(stdout, " notime (T) : %s\n", (no_time? "On" : "Off")); 1368 fprintf(stdout, " noknownissues (K) : %s\n", (noKnownIssues? "On" : "Off")); 1369 fprintf(stdout, " Warn on missing data (w) : %s\n", (warnOnMissingData? "On" : "Off")); 1370 fprintf(stdout, " Threads : %d\n", threadCount); 1371 for (int32_t i = 0; i < nProps; i++) { 1372 fprintf(stdout, " Custom property (prop:) : %s\n", props[i]); 1373 } 1374 fprintf(stdout, "-----------------------------------------------\n"); 1375 1376 if(utf8) { 1377 ucnv_setDefaultName("utf-8"); 1378 } 1379 /* Check whether ICU will initialize without forcing the build data directory into 1380 * the ICU_DATA path. Success here means either the data dll contains data, or that 1381 * this test program was run with ICU_DATA set externally. Failure of this check 1382 * is normal when ICU data is not packaged into a shared library. 1383 * 1384 * Whether or not this test succeeds, we want to cleanup and reinitialize 1385 * with a data path so that data loading from individual files can be tested. 1386 */ 1387 u_init(&errorCode); 1388 if (U_FAILURE(errorCode)) { 1389 fprintf(stderr, 1390 "#### Note: ICU Init without build-specific setDataDirectory() failed.\n"); 1391 defaultDataFound = FALSE; 1392 } 1393 else { 1394 defaultDataFound = TRUE; 1395 } 1396 u_cleanup(); 1397 if(utf8) { 1398 ucnv_setDefaultName("utf-8"); 1399 } 1400 errorCode = U_ZERO_ERROR; 1401 1402 /* Initialize ICU */ 1403 if (!defaultDataFound) { 1404 IntlTest::setICU_DATA(); // Must set data directory before u_init() is called. 1405 } 1406 u_init(&errorCode); 1407 if (U_FAILURE(errorCode)) { 1408 fprintf(stderr, 1409 "#### ERROR! %s: u_init() failed with status = \"%s\".\n" 1410 "*** Check the ICU_DATA environment variable and \n" 1411 "*** check that the data files are present.\n", argv[0], u_errorName(errorCode)); 1412 if(warnOnMissingData == 0) { 1413 fprintf(stderr, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n"); 1414 u_cleanup(); 1415 return 1; 1416 } 1417 } 1418 1419 // initial check for the default converter 1420 errorCode = U_ZERO_ERROR; 1421 cnv = ucnv_open(0, &errorCode); 1422 if(cnv != 0) { 1423 // ok 1424 ucnv_close(cnv); 1425 } else { 1426 fprintf(stdout, 1427 "*** %s! The default converter [%s] cannot be opened.\n" 1428 "*** Check the ICU_DATA environment variable and\n" 1429 "*** check that the data files are present.\n", 1430 warnOrErr, ucnv_getDefaultName()); 1431 if(!warnOnMissingData) { 1432 fprintf(stdout, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n"); 1433 return 1; 1434 } 1435 } 1436 1437 // try more data 1438 cnv = ucnv_open(TRY_CNV_2, &errorCode); 1439 if(cnv != 0) { 1440 // ok 1441 ucnv_close(cnv); 1442 } else { 1443 fprintf(stdout, 1444 "*** %s! The converter for " TRY_CNV_2 " cannot be opened.\n" 1445 "*** Check the ICU_DATA environment variable and \n" 1446 "*** check that the data files are present.\n", warnOrErr); 1447 if(!warnOnMissingData) { 1448 fprintf(stdout, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n"); 1449 return 1; 1450 } 1451 } 1452 1453 UResourceBundle *rb = ures_open(0, "en", &errorCode); 1454 ures_close(rb); 1455 if(U_FAILURE(errorCode)) { 1456 fprintf(stdout, 1457 "*** %s! The \"en\" locale resource bundle cannot be opened.\n" 1458 "*** Check the ICU_DATA environment variable and \n" 1459 "*** check that the data files are present.\n", warnOrErr); 1460 if(!warnOnMissingData) { 1461 fprintf(stdout, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n"); 1462 return 1; 1463 } 1464 } 1465 1466 Locale originalLocale; // Save the default locale for comparison later on. 1467 1468 if(ctest_xml_init("intltest")) 1469 return 1; 1470 1471 1472 /* TODO: Add option to call u_cleanup and rerun tests. */ 1473 if (all) { 1474 major.runTest(); 1475 if (leaks) { 1476 major.run_phase2( NULL, NULL ); 1477 } 1478 }else{ 1479 for (int i = 1; i < argc; ++i) { 1480 if (argv[i][0] != '-') { 1481 char* name = argv[i]; 1482 fprintf(stdout, "\n=== Handling test: %s: ===\n", name); 1483 1484 char baseName[1024]; 1485 sprintf(baseName, "/%s/", name); 1486 1487 char* parameter = strchr( name, '@' ); 1488 if (parameter) { 1489 *parameter = 0; 1490 parameter += 1; 1491 } 1492 execCount = 0; 1493 UBool res = major.runTest( name, parameter, baseName ); 1494 if (leaks && res) { 1495 major.run_phase2( name, parameter ); 1496 } 1497 if (!res || (execCount <= 0)) { 1498 fprintf(stdout, "\n---ERROR: Test doesn't exist: %s!\n", name); 1499 } 1500 } else if(!strcmp(argv[i],"-x")) { 1501 i++; 1502 } 1503 } 1504 } 1505 1506 1507 #if !UCONFIG_NO_FORMATTING 1508 CalendarTimeZoneTest::cleanup(); 1509 #endif 1510 1511 free(_testDataPath); 1512 _testDataPath = 0; 1513 1514 Locale lastDefaultLocale; 1515 if (originalLocale != lastDefaultLocale) { 1516 major.errln("FAILURE: A test changed the default locale without resetting it."); 1517 } 1518 1519 fprintf(stdout, "\n--------------------------------------\n"); 1520 if( major.printKnownIssues() ) { 1521 fprintf(stdout, " To run suppressed tests, use the -K option. \n"); 1522 } 1523 if (major.getErrors() == 0) { 1524 /* Call it twice to make sure that the defaults were reset. */ 1525 /* Call it before the OK message to verify proper cleanup. */ 1526 u_cleanup(); 1527 u_cleanup(); 1528 1529 fprintf(stdout, "OK: All tests passed without error.\n"); 1530 1531 if (major.getDataErrors() != 0) { 1532 fprintf(stdout, "\t*WARNING* some data-loading errors were ignored by the -w option.\n"); 1533 } 1534 }else{ 1535 fprintf(stdout, "Errors in total: %ld.\n", (long)major.getErrors()); 1536 major.printErrors(); 1537 1538 if(summary_file != NULL) { 1539 FILE *summf = fopen(summary_file, "w"); 1540 if( summf != NULL) { 1541 char buf[10000]; 1542 int32_t length = errorList.extract(0, errorList.length(), buf, sizeof(buf)); 1543 fwrite(buf, sizeof(*buf), length, (FILE*)summf); 1544 fclose(summf); 1545 } 1546 } 1547 1548 1549 if (major.getDataErrors() != 0) { 1550 fprintf(stdout, "\t*Note* some errors are data-loading related. If the data used is not the \n" 1551 "\tstock ICU data (i.e some have been added or removed), consider using\n" 1552 "\tthe '-w' option to turn these errors into warnings.\n"); 1553 } 1554 1555 /* Call afterwards to display errors. */ 1556 u_cleanup(); 1557 } 1558 1559 #ifdef UNISTR_COUNT_FINAL_STRING_LENGTHS 1560 unistr_printLengths(); 1561 #endif 1562 1563 fprintf(stdout, "--------------------------------------\n"); 1564 1565 if (execCount <= 0) { 1566 fprintf(stdout, "***** Not all called tests actually exist! *****\n"); 1567 } 1568 if(!no_time) { 1569 endTime = uprv_getRawUTCtime(); 1570 diffTime = (int32_t)(endTime - startTime); 1571 printf("Elapsed Time: %02d:%02d:%02d.%03d\n", 1572 (int)((diffTime%U_MILLIS_PER_DAY)/U_MILLIS_PER_HOUR), 1573 (int)((diffTime%U_MILLIS_PER_HOUR)/U_MILLIS_PER_MINUTE), 1574 (int)((diffTime%U_MILLIS_PER_MINUTE)/U_MILLIS_PER_SECOND), 1575 (int)(diffTime%U_MILLIS_PER_SECOND)); 1576 } 1577 1578 if(ctest_xml_fini()) 1579 return 1; 1580 1581 return major.getErrors(); 1582 } 1583 1584 const char* IntlTest::loadTestData(UErrorCode& err){ 1585 if( _testDataPath == NULL){ 1586 const char* directory=NULL; 1587 UResourceBundle* test =NULL; 1588 char* tdpath=NULL; 1589 const char* tdrelativepath; 1590 1591 #if defined (U_TOPBUILDDIR) 1592 tdrelativepath = "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING; 1593 directory = U_TOPBUILDDIR; 1594 #else 1595 tdrelativepath = ".." U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING; 1596 directory = pathToDataDirectory(); 1597 #endif 1598 1599 tdpath = (char*) malloc(sizeof(char) *(( strlen(directory) * strlen(tdrelativepath)) + 100)); 1600 1601 1602 /* u_getDataDirectory shoul return \source\data ... set the 1603 * directory to ..\source\data\..\test\testdata\out\testdata 1604 */ 1605 strcpy(tdpath, directory); 1606 strcat(tdpath, tdrelativepath); 1607 strcat(tdpath,"testdata"); 1608 1609 test=ures_open(tdpath, "testtypes", &err); 1610 1611 if(U_FAILURE(err)){ 1612 err = U_FILE_ACCESS_ERROR; 1613 it_dataerrln((UnicodeString)"Could not load testtypes.res in testdata bundle with path " + tdpath + (UnicodeString)" - " + u_errorName(err)); 1614 return ""; 1615 } 1616 ures_close(test); 1617 _testDataPath = tdpath; 1618 return _testDataPath; 1619 } 1620 return _testDataPath; 1621 } 1622 1623 const char* IntlTest::getTestDataPath(UErrorCode& err) { 1624 return loadTestData(err); 1625 } 1626 1627 /* Returns the path to icu/source/test/testdata/ */ 1628 const char *IntlTest::getSourceTestData(UErrorCode& /*err*/) { 1629 const char *srcDataDir = NULL; 1630 #ifdef U_TOPSRCDIR 1631 srcDataDir = U_TOPSRCDIR U_FILE_SEP_STRING"test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING; 1632 #else 1633 srcDataDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING; 1634 FILE *f = fopen(".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING "rbbitst.txt", "r"); 1635 if (f) { 1636 /* We're in icu/source/test/intltest/ */ 1637 fclose(f); 1638 } 1639 else { 1640 /* We're in icu/source/test/intltest/Platform/(Debug|Release) */ 1641 srcDataDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING 1642 "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING; 1643 } 1644 #endif 1645 return srcDataDir; 1646 } 1647 1648 char *IntlTest::getUnidataPath(char path[]) { 1649 const int kUnicodeDataTxtLength = 15; // strlen("UnicodeData.txt") 1650 1651 // Look inside ICU_DATA first. 1652 strcpy(path, pathToDataDirectory()); 1653 strcat(path, "unidata" U_FILE_SEP_STRING "UnicodeData.txt"); 1654 FILE *f = fopen(path, "r"); 1655 if(f != NULL) { 1656 fclose(f); 1657 *(strchr(path, 0) - kUnicodeDataTxtLength) = 0; // Remove the basename. 1658 return path; 1659 } 1660 1661 // As a fallback, try to guess where the source data was located 1662 // at the time ICU was built, and look there. 1663 # ifdef U_TOPSRCDIR 1664 strcpy(path, U_TOPSRCDIR U_FILE_SEP_STRING "data"); 1665 # else 1666 UErrorCode errorCode = U_ZERO_ERROR; 1667 const char *testDataPath = loadTestData(errorCode); 1668 if(U_FAILURE(errorCode)) { 1669 it_errln(UnicodeString( 1670 "unable to find path to source/data/unidata/ and loadTestData() failed: ") + 1671 u_errorName(errorCode)); 1672 return NULL; 1673 } 1674 strcpy(path, testDataPath); 1675 strcat(path, U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." 1676 U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." 1677 U_FILE_SEP_STRING "data"); 1678 # endif 1679 strcat(path, U_FILE_SEP_STRING); 1680 strcat(path, "unidata" U_FILE_SEP_STRING "UnicodeData.txt"); 1681 f = fopen(path, "r"); 1682 if(f != NULL) { 1683 fclose(f); 1684 *(strchr(path, 0) - kUnicodeDataTxtLength) = 0; // Remove the basename. 1685 return path; 1686 } 1687 return NULL; 1688 } 1689 1690 const char* IntlTest::fgDataDir = NULL; 1691 1692 /* returns the path to icu/source/data */ 1693 const char * IntlTest::pathToDataDirectory() 1694 { 1695 1696 if(fgDataDir != NULL) { 1697 return fgDataDir; 1698 } 1699 1700 /* U_TOPSRCDIR is set by the makefiles on UNIXes when building cintltst and intltst 1701 // to point to the top of the build hierarchy, which may or 1702 // may not be the same as the source directory, depending on 1703 // the configure options used. At any rate, 1704 // set the data path to the built data from this directory. 1705 // The value is complete with quotes, so it can be used 1706 // as-is as a string constant. 1707 */ 1708 #if defined (U_TOPSRCDIR) 1709 { 1710 fgDataDir = U_TOPSRCDIR U_FILE_SEP_STRING "data" U_FILE_SEP_STRING; 1711 } 1712 #else 1713 1714 /* On Windows, the file name obtained from __FILE__ includes a full path. 1715 * This file is "wherever\icu\source\test\cintltst\cintltst.c" 1716 * Change to "wherever\icu\source\data" 1717 */ 1718 { 1719 static char p[sizeof(__FILE__) + 10]; 1720 char *pBackSlash; 1721 int i; 1722 1723 strcpy(p, __FILE__); 1724 /* We want to back over three '\' chars. */ 1725 /* Only Windows should end up here, so looking for '\' is safe. */ 1726 for (i=1; i<=3; i++) { 1727 pBackSlash = strrchr(p, U_FILE_SEP_CHAR); 1728 if (pBackSlash != NULL) { 1729 *pBackSlash = 0; /* Truncate the string at the '\' */ 1730 } 1731 } 1732 1733 if (pBackSlash != NULL) { 1734 /* We found and truncated three names from the path. 1735 * Now append "source\data" and set the environment 1736 */ 1737 strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING ); 1738 fgDataDir = p; 1739 } 1740 else { 1741 /* __FILE__ on MSVC7 does not contain the directory */ 1742 FILE *file = fopen(".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "Makefile.in", "r"); 1743 if (file) { 1744 fclose(file); 1745 fgDataDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING; 1746 } 1747 else { 1748 fgDataDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING; 1749 } 1750 } 1751 } 1752 #endif 1753 1754 return fgDataDir; 1755 1756 } 1757 1758 /* 1759 * This is a variant of cintltst/ccolltst.c:CharsToUChars(). 1760 * It converts an invariant-character string into a UnicodeString, with 1761 * unescaping \u sequences. 1762 */ 1763 UnicodeString CharsToUnicodeString(const char* chars){ 1764 return UnicodeString(chars, -1, US_INV).unescape(); 1765 } 1766 1767 UnicodeString ctou(const char* chars) { 1768 return CharsToUnicodeString(chars); 1769 } 1770 1771 #define RAND_M (714025) 1772 #define RAND_IA (1366) 1773 #define RAND_IC (150889) 1774 1775 static int32_t RAND_SEED; 1776 1777 /** 1778 * Returns a uniform random value x, with 0.0 <= x < 1.0. Use 1779 * with care: Does not return all possible values; returns one of 1780 * 714,025 values, uniformly spaced. However, the period is 1781 * effectively infinite. See: Numerical Recipes, section 7.1. 1782 * 1783 * @param seedp pointer to seed. Set *seedp to any negative value 1784 * to restart the sequence. 1785 */ 1786 float IntlTest::random(int32_t* seedp) { 1787 static int32_t iy, ir[98]; 1788 static UBool first=TRUE; 1789 int32_t j; 1790 if (*seedp < 0 || first) { 1791 first = FALSE; 1792 if ((*seedp=(RAND_IC-(*seedp)) % RAND_M) < 0) *seedp = -(*seedp); 1793 for (j=1;j<=97;++j) { 1794 *seedp=(RAND_IA*(*seedp)+RAND_IC) % RAND_M; 1795 ir[j]=(*seedp); 1796 } 1797 *seedp=(RAND_IA*(*seedp)+RAND_IC) % RAND_M; 1798 iy=(*seedp); 1799 } 1800 j=(int32_t)(1 + 97.0*iy/RAND_M); 1801 U_ASSERT(j>=1 && j<=97); 1802 iy=ir[j]; 1803 *seedp=(RAND_IA*(*seedp)+RAND_IC) % RAND_M; 1804 ir[j]=(*seedp); 1805 return (float) iy/RAND_M; 1806 } 1807 1808 /** 1809 * Convenience method using a global seed. 1810 */ 1811 float IntlTest::random() { 1812 return random(&RAND_SEED); 1813 } 1814 1815 1816 /* 1817 * Integer random number class implementation. 1818 * Similar to C++ std::minstd_rand, with the same algorithm & constants. 1819 */ 1820 IntlTest::icu_rand::icu_rand(uint32_t seed) { 1821 seed = seed % 2147483647UL; 1822 if (seed == 0) { 1823 seed = 1; 1824 } 1825 fLast = seed; 1826 } 1827 1828 IntlTest::icu_rand::~icu_rand() {} 1829 1830 void IntlTest::icu_rand::seed(uint32_t seed) { 1831 if (seed == 0) { 1832 seed = 1; 1833 } 1834 fLast = seed; 1835 } 1836 1837 uint32_t IntlTest::icu_rand::operator() () { 1838 fLast = ((uint64_t)fLast * 48271UL) % 2147483647UL; 1839 return fLast; 1840 } 1841 1842 uint32_t IntlTest::icu_rand::getSeed() { 1843 return (uint32_t) fLast; 1844 } 1845 1846 1847 1848 static inline UChar toHex(int32_t i) { 1849 return (UChar)(i + (i < 10 ? 0x30 : (0x41 - 10))); 1850 } 1851 1852 static UnicodeString& escape(const UnicodeString& s, UnicodeString& result) { 1853 for (int32_t i=0; i<s.length(); ++i) { 1854 UChar c = s[i]; 1855 if (c <= (UChar)0x7F) { 1856 result += c; 1857 } else { 1858 result += (UChar)0x5c; 1859 result += (UChar)0x75; 1860 result += toHex((c >> 12) & 0xF); 1861 result += toHex((c >> 8) & 0xF); 1862 result += toHex((c >> 4) & 0xF); 1863 result += toHex( c & 0xF); 1864 } 1865 } 1866 return result; 1867 } 1868 1869 #define VERBOSE_ASSERTIONS 1870 1871 UBool IntlTest::assertTrue(const char* message, UBool condition, UBool quiet, UBool possibleDataError, const char *file, int line) { 1872 if (file != NULL) { 1873 if (!condition) { 1874 if (possibleDataError) { 1875 dataerrln("%s:%d: FAIL: assertTrue() failed: %s", file, line, message); 1876 } else { 1877 errln("%s:%d: FAIL: assertTrue() failed: %s", file, line, message); 1878 } 1879 } else if (!quiet) { 1880 logln("%s:%d: Ok: %s", file, line, message); 1881 } 1882 } else { 1883 if (!condition) { 1884 if (possibleDataError) { 1885 dataerrln("FAIL: assertTrue() failed: %s", message); 1886 } else { 1887 errln("FAIL: assertTrue() failed: %s", message); 1888 } 1889 } else if (!quiet) { 1890 logln("Ok: %s", message); 1891 } 1892 1893 } 1894 return condition; 1895 } 1896 1897 UBool IntlTest::assertFalse(const char* message, UBool condition, UBool quiet) { 1898 if (condition) { 1899 errln("FAIL: assertFalse() failed: %s", message); 1900 } else if (!quiet) { 1901 logln("Ok: %s", message); 1902 } 1903 return !condition; 1904 } 1905 1906 UBool IntlTest::assertSuccess(const char* message, UErrorCode ec, UBool possibleDataError, const char *file, int line) { 1907 if( file==NULL ) { 1908 file = ""; // prevent failure if no file given 1909 } 1910 if (U_FAILURE(ec)) { 1911 if (possibleDataError) { 1912 dataerrln("FAIL: %s:%d: %s (%s)", file, line, message, u_errorName(ec)); 1913 } else { 1914 errcheckln(ec, "FAIL: %s:%d: %s (%s)", file, line, message, u_errorName(ec)); 1915 } 1916 return FALSE; 1917 } else { 1918 logln("OK: %s:%d: %s - (%s)", file, line, message, u_errorName(ec)); 1919 } 1920 return TRUE; 1921 } 1922 1923 UBool IntlTest::assertEquals(const char* message, 1924 const UnicodeString& expected, 1925 const UnicodeString& actual, 1926 UBool possibleDataError) { 1927 if (expected != actual) { 1928 if (possibleDataError) { 1929 dataerrln((UnicodeString)"FAIL: " + message + "; got " + 1930 prettify(actual) + 1931 "; expected " + prettify(expected)); 1932 } else { 1933 errln((UnicodeString)"FAIL: " + message + "; got " + 1934 prettify(actual) + 1935 "; expected " + prettify(expected)); 1936 } 1937 return FALSE; 1938 } 1939 #ifdef VERBOSE_ASSERTIONS 1940 else { 1941 logln((UnicodeString)"Ok: " + message + "; got " + prettify(actual)); 1942 } 1943 #endif 1944 return TRUE; 1945 } 1946 1947 UBool IntlTest::assertEquals(const char* message, 1948 const char* expected, 1949 const char* actual) { 1950 if (uprv_strcmp(expected, actual) != 0) { 1951 errln((UnicodeString)"FAIL: " + message + "; got \"" + 1952 actual + 1953 "\"; expected \"" + expected + "\""); 1954 return FALSE; 1955 } 1956 #ifdef VERBOSE_ASSERTIONS 1957 else { 1958 logln((UnicodeString)"Ok: " + message + "; got \"" + actual + "\""); 1959 } 1960 #endif 1961 return TRUE; 1962 } 1963 1964 UBool IntlTest::assertEquals(const char* message, 1965 int32_t expected, 1966 int32_t actual) { 1967 if (expected != actual) { 1968 errln((UnicodeString)"FAIL: " + message + "; got " + 1969 actual + "=0x" + toHex(actual) + 1970 "; expected " + expected + "=0x" + toHex(expected)); 1971 return FALSE; 1972 } 1973 #ifdef VERBOSE_ASSERTIONS 1974 else { 1975 logln((UnicodeString)"Ok: " + message + "; got " + actual + "=0x" + toHex(actual)); 1976 } 1977 #endif 1978 return TRUE; 1979 } 1980 1981 UBool IntlTest::assertEquals(const char* message, 1982 int64_t expected, 1983 int64_t actual) { 1984 if (expected != actual) { 1985 errln((UnicodeString)"FAIL: " + message + "; got int64 " + 1986 Int64ToUnicodeString(actual) + 1987 "; expected " + Int64ToUnicodeString(expected) ); 1988 return FALSE; 1989 } 1990 #ifdef VERBOSE_ASSERTIONS 1991 else { 1992 logln((UnicodeString)"Ok: " + message + "; got int64 " + Int64ToUnicodeString(actual)); 1993 } 1994 #endif 1995 return TRUE; 1996 } 1997 1998 UBool IntlTest::assertEquals(const char* message, 1999 double expected, 2000 double actual) { 2001 if (expected != actual) { 2002 errln((UnicodeString)"FAIL: " + message + "; got " + 2003 actual + 2004 "; expected " + expected); 2005 return FALSE; 2006 } 2007 #ifdef VERBOSE_ASSERTIONS 2008 else { 2009 logln((UnicodeString)"Ok: " + message + "; got " + actual); 2010 } 2011 #endif 2012 return TRUE; 2013 } 2014 2015 2016 UBool IntlTest::assertEquals(const char* message, 2017 UBool expected, 2018 UBool actual) { 2019 if (expected != actual) { 2020 errln((UnicodeString)"FAIL: " + message + "; got " + 2021 toString(actual) + 2022 "; expected " + toString(expected)); 2023 return FALSE; 2024 } 2025 #ifdef VERBOSE_ASSERTIONS 2026 else { 2027 logln((UnicodeString)"Ok: " + message + "; got " + toString(actual)); 2028 } 2029 #endif 2030 return TRUE; 2031 } 2032 2033 #if !UCONFIG_NO_FORMATTING 2034 UBool IntlTest::assertEquals(const char* message, 2035 const Formattable& expected, 2036 const Formattable& actual, 2037 UBool possibleDataError) { 2038 if (expected != actual) { 2039 if (possibleDataError) { 2040 dataerrln((UnicodeString)"FAIL: " + message + "; got " + 2041 toString(actual) + 2042 "; expected " + toString(expected)); 2043 } else { 2044 errln((UnicodeString)"FAIL: " + message + "; got " + 2045 toString(actual) + 2046 "; expected " + toString(expected)); 2047 } 2048 return FALSE; 2049 } 2050 #ifdef VERBOSE_ASSERTIONS 2051 else { 2052 logln((UnicodeString)"Ok: " + message + "; got " + toString(actual)); 2053 } 2054 #endif 2055 return TRUE; 2056 } 2057 #endif 2058 2059 static char ASSERT_BUF[256]; 2060 2061 static const char* extractToAssertBuf(const UnicodeString& message) { 2062 UnicodeString buf; 2063 escape(message, buf); 2064 buf.extract(0, 0x7FFFFFFF, ASSERT_BUF, sizeof(ASSERT_BUF)-1, 0); 2065 ASSERT_BUF[sizeof(ASSERT_BUF)-1] = 0; 2066 return ASSERT_BUF; 2067 } 2068 2069 UBool IntlTest::assertTrue(const UnicodeString& message, UBool condition, UBool quiet) { 2070 return assertTrue(extractToAssertBuf(message), condition, quiet); 2071 } 2072 2073 UBool IntlTest::assertFalse(const UnicodeString& message, UBool condition, UBool quiet) { 2074 return assertFalse(extractToAssertBuf(message), condition, quiet); 2075 } 2076 2077 UBool IntlTest::assertSuccess(const UnicodeString& message, UErrorCode ec) { 2078 return assertSuccess(extractToAssertBuf(message), ec); 2079 } 2080 2081 UBool IntlTest::assertEquals(const UnicodeString& message, 2082 const UnicodeString& expected, 2083 const UnicodeString& actual, 2084 UBool possibleDataError) { 2085 return assertEquals(extractToAssertBuf(message), expected, actual, possibleDataError); 2086 } 2087 2088 UBool IntlTest::assertEquals(const UnicodeString& message, 2089 const char* expected, 2090 const char* actual) { 2091 return assertEquals(extractToAssertBuf(message), expected, actual); 2092 } 2093 UBool IntlTest::assertEquals(const UnicodeString& message, 2094 UBool expected, 2095 UBool actual) { 2096 return assertEquals(extractToAssertBuf(message), expected, actual); 2097 } 2098 UBool IntlTest::assertEquals(const UnicodeString& message, 2099 int32_t expected, 2100 int32_t actual) { 2101 return assertEquals(extractToAssertBuf(message), expected, actual); 2102 } 2103 UBool IntlTest::assertEquals(const UnicodeString& message, 2104 int64_t expected, 2105 int64_t actual) { 2106 return assertEquals(extractToAssertBuf(message), expected, actual); 2107 } 2108 2109 #if !UCONFIG_NO_FORMATTING 2110 UBool IntlTest::assertEquals(const UnicodeString& message, 2111 const Formattable& expected, 2112 const Formattable& actual) { 2113 return assertEquals(extractToAssertBuf(message), expected, actual); 2114 } 2115 #endif 2116 2117 void IntlTest::setProperty(const char* propline) { 2118 if (numProps < kMaxProps) { 2119 proplines[numProps] = propline; 2120 } 2121 numProps++; 2122 } 2123 2124 const char* IntlTest::getProperty(const char* prop) { 2125 const char* val = NULL; 2126 for (int32_t i = 0; i < numProps; i++) { 2127 int32_t plen = uprv_strlen(prop); 2128 if ((int32_t)uprv_strlen(proplines[i]) > plen + 1 2129 && proplines[i][plen] == '=' 2130 && uprv_strncmp(proplines[i], prop, plen) == 0) { 2131 val = &(proplines[i][plen+1]); 2132 break; 2133 } 2134 } 2135 return val; 2136 } 2137 2138 /* 2139 * Hey, Emacs, please set the following: 2140 * 2141 * Local Variables: 2142 * indent-tabs-mode: nil 2143 * End: 2144 * 2145 */ 2146