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