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