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