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