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