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