]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/test/intltest/intltest.cpp
ICU-400.42.tar.gz
[apple/icu.git] / icuSources / test / intltest / intltest.cpp
index 5251c66ce718f5de5267b04d81d96e576a29e3e4..9094de902cd1bdd70ac1792d9eb25ee7078a47d1 100644 (file)
@@ -1,6 +1,6 @@
 /********************************************************************
  * COPYRIGHT:
- * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * Copyright (c) 1997-2008, International Business Machines Corporation and
  * others. All Rights Reserved.
  ********************************************************************/
 
 #include "unicode/smpdtfmt.h"
 #include "unicode/ucnv.h"
 #include "unicode/uclean.h"
+#include "unicode/timezone.h"
+#include "unicode/curramt.h"
+#include "unicode/putil.h"
 
 #include "intltest.h"
 #include "caltztst.h"
 #include "itmajor.h"
-#include "tsmutex.h"
-
+#include "cstring.h"
 #include "umutex.h"
+#include "uassert.h"
+#include "cmemory.h"
+#include "uoptions.h"
+
+#include "putilimp.h" // for uprv_getUTCtime()
+#include "unicode/locid.h"
+
 
 #ifdef XP_MAC_CONSOLE
 #include <console.h>
@@ -50,16 +59,6 @@ UnicodeString
 UCharToUnicodeString(UChar c)
 { return UnicodeString(c); }
 
-// [LIU] Just to get things working
-UnicodeString
-operator+(const UnicodeString& left,
-      const UnicodeString& right)
-{
-    UnicodeString str(left);
-    str += right;
-    return str;
-}
-
 // [rtg] Just to get things working
 UnicodeString
 operator+(const UnicodeString& left,
@@ -87,6 +86,22 @@ operator+(const UnicodeString& left,
     return left + buffer;
 }
 
+UnicodeString
+Int64ToUnicodeString(int64_t num)
+{
+    char buffer[64];    // nos changed from 10 to 64
+    char danger = 'p';  // guard against overrunning the buffer (rtg)
+
+#ifdef U_WINDOWS
+    sprintf(buffer, "%I64d", num);
+#else
+    sprintf(buffer, "%lld", (long long)num);
+#endif
+    assert(danger == 'p');
+
+    return buffer;
+}
+
 // [LIU] Just to get things working
 UnicodeString
 operator+(const UnicodeString& left,
@@ -95,7 +110,11 @@ operator+(const UnicodeString& left,
     char buffer[64];   // was 32, made it arbitrarily bigger (rtg)
     char danger = 'p'; // guard against overrunning the buffer (rtg)
 
-    sprintf(buffer, "%.30g", num); // nos changed from 99 to 30
+    // IEEE floating point has 52 bits of mantissa, plus one assumed bit
+    //  53*log(2)/log(10) = 15.95
+    // so there is no need to show more than 16 digits. [alan]
+
+    sprintf(buffer, "%.17g", num);
     assert(danger == 'p');
 
     return left + buffer;
@@ -104,10 +123,9 @@ operator+(const UnicodeString& left,
 #if !UCONFIG_NO_FORMATTING
 
 /**
- * Originally coded this as operator+, but that makes the expression
- * + char* ambiguous. - liu
+ * Return a string display for for this, without surrounding braces.
  */
-UnicodeString toString(const Formattable& f) {
+UnicodeString _toString(const Formattable& f) {
     UnicodeString s;
     switch (f.getType()) {
     case Formattable::kDate:
@@ -117,45 +135,75 @@ UnicodeString toString(const Formattable& f) {
             if (U_SUCCESS(status)) {
                 FieldPosition pos;
                 fmt.format(f.getDate(), s, pos);
-                s.insert(0, "[Date:");
-                s.insert(s.length(), (UChar)0x005d);
+                s.insert(0, "Date:");
             } else {
-                s = UnicodeString("[Error creating date format]");
+                s = UnicodeString("Error creating date format]");
             }
         }
         break;
     case Formattable::kDouble:
-        s = UnicodeString("[Double:") + f.getDouble() + "]";
+        s = UnicodeString("double:") + f.getDouble();
         break;
     case Formattable::kLong:
-        s = UnicodeString("[Long:") + f.getLong() + "]";
+        s = UnicodeString("long:") + f.getLong();
         break;
+
+    case Formattable::kInt64:
+        s = UnicodeString("int64:") + Int64ToUnicodeString(f.getInt64());
+        break;
+
     case Formattable::kString:
         f.getString(s);
-        s.insert(0, "[String:");
-        s.insert(s.length(), (UChar)0x005d);
+        s.insert(0, "String:");
         break;
     case Formattable::kArray:
         {
             int32_t i, n;
             const Formattable* array = f.getArray(n);
-            s.insert(0, UnicodeString("[Array:"));
+            s.insert(0, UnicodeString("Array:"));
             UnicodeString delim(", ");
             for (i=0; i<n; ++i) {
                 if (i > 0) {
                     s.append(delim);
                 }
-                s = s + toString(array[i]);
+                s = s + _toString(array[i]);
             }
-            s.append(UChar(0x005d));
         }
         break;
+    case Formattable::kObject:
+        if (f.getObject()->getDynamicClassID() ==
+            CurrencyAmount::getStaticClassID()) {
+            const CurrencyAmount& c = (const CurrencyAmount&) *f.getObject();
+            s = _toString(c.getNumber()) + " " + UnicodeString(c.getISOCurrency());
+        } else {
+            s = UnicodeString("Unknown UObject");
+        }
+        break;
+    default:
+        s = UnicodeString("Unknown Formattable type=") + (int32_t)f.getType();
+        break;
     }
     return s;
 }
 
+/**
+ * Originally coded this as operator+, but that makes the expression
+ * + char* ambiguous. - liu
+ */
+UnicodeString toString(const Formattable& f) {
+    UnicodeString s((UChar)91/*[*/);
+    s.append(_toString(f));
+    s.append((UChar)0x5d/*]*/);
+    return s;
+}
+
 #endif
 
+// useful when operator+ won't cooperate
+UnicodeString toString(int32_t n) {
+    return UnicodeString() + (long)n;
+}
+
 // stephen - cleaned up 05/05/99
 UnicodeString operator+(const UnicodeString& left, char num)
 { return left + (long)num; }
@@ -297,68 +345,6 @@ IntlTest::prettify(const UnicodeString &source, UBool parseBackslash)
     return target;
 }
 
-#if defined(_WIN32) || defined(WIN32) || defined(__OS2__) || defined(OS2)
-#define PREV_DIR ".."
-#else
-#define PREV_DIR "/../"
-#endif
-
-void
-IntlTest::pathnameInContext( char* fullname, int32_t maxsize, const char* relPath ) //nosmac
-{
-    const char* mainDir;
-    char  sepChar;
-    const char inpSepChar = '|';
-
-    // So what's going on is that ICU_DATA during tests points to:
-    //              ICU | source | data
-    //and we want   ICU | source |
-    //
-    // We'll add                 | test | testdata
-    //
-    // So, just add a .. here - back up one level
-
-    mainDir = u_getDataDirectory();
-    sepChar = U_FILE_SEP_CHAR;
-    char sepString[] = U_FILE_SEP_STRING;
-
-#if defined(XP_MAC)
-    Str255 volName;
-    int16_t volNum;
-    OSErr err = GetVol( volName, &volNum );
-    if (err != noErr)
-        volName[0] = 0;
-    mainDir = (char*) &(volName[1]);
-    mainDir[volName[0]] = 0;
-#else
-    char mainDirBuffer[255];
-    if(mainDir!=NULL) {
-        strcpy(mainDirBuffer, mainDir);
-        strcat(mainDirBuffer, PREV_DIR);
-    } else {
-        mainDirBuffer[0]='\0';
-    }
-    mainDir=mainDirBuffer;
-#endif
-
-    if (relPath[0] == '|')
-        relPath++;
-    int32_t lenMainDir = strlen(mainDir);
-    int32_t lenRelPath = strlen(relPath);
-    if (maxsize < lenMainDir + lenRelPath + 2) {
-        fullname[0] = 0;
-        return;
-    }
-    strcpy(fullname, mainDir);
-    strcat(fullname, sepString);
-    strcat(fullname, relPath);
-    char* tmp = strchr(fullname, inpSepChar);
-    while (tmp) {
-        *tmp = sepChar;
-        tmp = strchr(tmp+1, inpSepChar);
-    }
-}
-
 /*  IntlTest::setICU_DATA  - if the ICU_DATA environment variable is not already
  *                       set, try to deduce the directory in which ICU was built,
  *                       and set ICU_DATA to "icu/source/data" in that location.
@@ -381,7 +367,7 @@ void IntlTest::setICU_DATA() {
     //              may not be the same as the source directory, depending on
     //              the configure options used.  At any rate,
     //              set the data path to the built data from this directory.
-    //              The value is complete with quotes, so it can be used 
+    //              The value is complete with quotes, so it can be used
     //              as-is as a string constant.
 
 #if defined (U_TOPBUILDDIR)
@@ -498,56 +484,28 @@ void it_errln( UnicodeString message )
         IntlTest::gTest->errln( message );
 }
 
-IntlTest& operator<<(IntlTest& test, const UnicodeString&   string)
+void it_dataerr( UnicodeString message )
 {
-/* NULL shouldn't happen */
-//    if (&test == NULL)
-//        return *((IntlTest*) NULL);
-    test.log( string );
-    return test;
-}
-
-IntlTest& operator<<(IntlTest& test, const char*    string)
-{
-/* NULL shouldn't happen */
-//    if (&test == NULL)
-//        return *((IntlTest*) NULL);
-    test.log( string );
-    return test;
-}
-
-IntlTest& operator<<(IntlTest& test, const int32_t num)
-{
-/* NULL shouldn't happen */
-//    if (&test == NULL)
-//        return *((IntlTest*) NULL);
-    char convert[20];
-    sprintf(convert, "%li", (long)num);
-    test.log(convert);
-    return test;
-}
-
-IntlTest& endl( IntlTest& test )
-{
-    test.logln();
-    return test;
+    if (IntlTest::gTest)
+        IntlTest::gTest->dataerr( message );
 }
 
-IntlTest& operator<<(IntlTest& test,  IntlTest& ( * _f)(IntlTest&))
+void it_dataerrln( UnicodeString message )
 {
-    (*_f)(test);
-    return test;
+    if (IntlTest::gTest)
+        IntlTest::gTest->dataerrln( message );
 }
 
-
 IntlTest::IntlTest()
 {
     caller = NULL;
-    path = NULL;
+    testPath = NULL;
     LL_linestart = TRUE;
     errorCount = 0;
+    dataErrorCount = 0;
     verbose = FALSE;
     no_err_msg = FALSE;
+    warn_on_missing_data = FALSE;
     quick = FALSE;
     leaks = FALSE;
     testoutfp = stdout;
@@ -558,6 +516,7 @@ void IntlTest::setCaller( IntlTest* callingTest )
 {
     caller = callingTest;
     if (caller) {
+        warn_on_missing_data = caller->warn_on_missing_data;
         verbose = caller->verbose;
         no_err_msg = caller->no_err_msg;
         quick = caller->quick;
@@ -570,12 +529,12 @@ UBool IntlTest::callTest( IntlTest& testToBeCalled, char* par )
 {
     execCount--; // correct a previously assumed test-exec, as this only calls a subtest
     testToBeCalled.setCaller( this );
-    return testToBeCalled.runTest( path, par );
+    return testToBeCalled.runTest( testPath, par );
 }
 
 void IntlTest::setPath( char* pathVal )
 {
-    this->path = pathVal;
+    this->testPath = pathVal;
 }
 
 UBool IntlTest::setVerbose( UBool verboseVal )
@@ -585,6 +544,13 @@ UBool IntlTest::setVerbose( UBool verboseVal )
     return rval;
 }
 
+UBool IntlTest::setWarnOnMissingData( UBool warn_on_missing_dataVal )
+{
+    UBool rval = this->warn_on_missing_data;
+    this->warn_on_missing_data = warn_on_missing_dataVal;
+    return rval;
+}
+
 UBool IntlTest::setNoErrMsg( UBool no_err_msgVal )
 {
     UBool rval = this->no_err_msg;
@@ -611,6 +577,11 @@ int32_t IntlTest::getErrors( void )
     return errorCount;
 }
 
+int32_t IntlTest::getDataErrors( void )
+{
+    return dataErrorCount;
+}
+
 UBool IntlTest::runTest( char* name, char* par )
 {
     UBool rval;
@@ -619,14 +590,14 @@ UBool IntlTest::runTest( char* name, char* par )
     if (name)
         pos = strchr( name, delim ); // check if name contains path (by looking for '/')
     if (pos) {
-        path = pos+1;   // store subpath for calling subtest
+        testPath = pos+1;   // store subpath for calling subtest
         *pos = 0;       // split into two strings
     }else{
-        path = NULL;
+        testPath = NULL;
     }
 
     if (!name || (name[0] == 0) || (strcmp(name, "*") == 0)) {
-        rval = runTestLoop( NULL, NULL );
+        rval = runTestLoop( NULL, par );
 
     }else if (strcmp( name, "LIST" ) == 0) {
         this->usage();
@@ -669,7 +640,7 @@ UBool IntlTest::runTestLoop( char* testname, char* par )
     IntlTest* saveTest = gTest;
     gTest = this;
     do {
-        this->runIndexedTest( index, FALSE, name );
+        this->runIndexedTest( index, FALSE, name, par );
         if (!name || (name[0] == 0))
             break;
         if (!testname) {
@@ -771,7 +742,15 @@ int32_t IntlTest::IncErrorCount( void )
     return errorCount;
 }
 
-void IntlTest::err() {
+int32_t IntlTest::IncDataErrorCount( void )
+{
+    dataErrorCount++;
+    if (caller) caller->IncDataErrorCount();
+    return dataErrorCount;
+}
+
+void IntlTest::err()
+{
     IncErrorCount();
 }
 
@@ -787,10 +766,32 @@ void IntlTest::errln( const UnicodeString &message )
     if (!no_err_msg) LL_message( message, TRUE );
 }
 
+void IntlTest::dataerr( const UnicodeString &message )
+{
+    IncDataErrorCount();
+
+    if (!warn_on_missing_data) {
+        IncErrorCount();
+    }
+
+    if (!no_err_msg) LL_message( message, FALSE );
+}
+
+void IntlTest::dataerrln( const UnicodeString &message )
+{
+    IncDataErrorCount();
+
+    if (!warn_on_missing_data) {
+        IncErrorCount();
+    }
+
+    if (!no_err_msg) LL_message( message, TRUE );
+}
+
 /* convenience functions that include sprintf formatting */
 void IntlTest::log(const char *fmt, ...)
 {
-    char buffer[512];
+    char buffer[4000];
     va_list ap;
 
     va_start(ap, fmt);
@@ -804,7 +805,7 @@ void IntlTest::log(const char *fmt, ...)
 
 void IntlTest::logln(const char *fmt, ...)
 {
-    char buffer[512];
+    char buffer[4000];
     va_list ap;
 
     va_start(ap, fmt);
@@ -819,7 +820,7 @@ void IntlTest::logln(const char *fmt, ...)
 /* convenience functions that include sprintf formatting */
 void IntlTest::info(const char *fmt, ...)
 {
-    char buffer[512];
+    char buffer[4000];
     va_list ap;
 
     va_start(ap, fmt);
@@ -831,7 +832,7 @@ void IntlTest::info(const char *fmt, ...)
 
 void IntlTest::infoln(const char *fmt, ...)
 {
-    char buffer[512];
+    char buffer[4000];
     va_list ap;
 
     va_start(ap, fmt);
@@ -843,7 +844,7 @@ void IntlTest::infoln(const char *fmt, ...)
 
 void IntlTest::err(const char *fmt, ...)
 {
-    char buffer[512];
+    char buffer[4000];
     va_list ap;
 
     va_start(ap, fmt);
@@ -854,7 +855,7 @@ void IntlTest::err(const char *fmt, ...)
 
 void IntlTest::errln(const char *fmt, ...)
 {
-    char buffer[512];
+    char buffer[4000];
     va_list ap;
 
     va_start(ap, fmt);
@@ -863,6 +864,17 @@ void IntlTest::errln(const char *fmt, ...)
     errln(UnicodeString(buffer, ""));
 }
 
+void IntlTest::dataerrln(const char *fmt, ...)
+{
+    char buffer[4000];
+    va_list ap;
+
+    va_start(ap, fmt);
+    vsprintf(buffer, fmt, ap);
+    va_end(ap);
+    dataerrln(UnicodeString(buffer, ""));
+}
+
 void IntlTest::printErrors()
 {
      IntlTest::LL_message(errorList, TRUE);
@@ -893,7 +905,7 @@ void IntlTest::LL_message( UnicodeString message, UBool newline )
     // stream out the indentation string first if necessary
     length = indent.extract(1, indent.length(), buffer, sizeof(buffer));
     if (length > 0) {
-        fwrite(buffer, sizeof(*buffer), length, testoutfp);
+        fwrite(buffer, sizeof(*buffer), length, (FILE *)testoutfp);
     }
 
     // replace each LineFeed by the indentation string
@@ -902,17 +914,18 @@ void IntlTest::LL_message( UnicodeString message, UBool newline )
     // stream out the message
     length = message.extract(0, message.length(), buffer, sizeof(buffer));
     if (length > 0) {
-        fwrite(buffer, sizeof(*buffer), length, testoutfp);
+        length = length > 10000 ? 10000 : length;
+        fwrite(buffer, sizeof(*buffer), length, (FILE *)testoutfp);
     }
 
     if (newline) {
         char newLine = '\n';
-        fwrite(&newLine, sizeof(newLine), 1, testoutfp);
+        fwrite(&newLine, sizeof(newLine), 1, (FILE *)testoutfp);
     }
 
     // A newline usually flushes the buffer, but
     // flush the message just in case of a core dump.
-    fflush(testoutfp);
+    fflush((FILE *)testoutfp);
 }
 
 /**
@@ -959,83 +972,66 @@ int
 main(int argc, char* argv[])
 {
     UBool syntax = FALSE;
-    UBool all = TRUE;
+    UBool all = FALSE;
     UBool verbose = FALSE;
     UBool no_err_msg = FALSE;
     UBool quick = TRUE;
     UBool name = FALSE;
     UBool leaks = FALSE;
     UBool warnOnMissingData = FALSE;
+    UBool defaultDataFound = FALSE;
     UErrorCode errorCode = U_ZERO_ERROR;
     UConverter *cnv = NULL;
-    const char *warnOrErr = "Failure"; 
-
-    /* This must be tested before using anything! */
-    MutexTest::gMutexInitialized = umtx_isInitialized(NULL);
-
-#ifdef XP_MAC_CONSOLE
-    argc = ccommand( &argv );
-#endif
+    const char *warnOrErr = "Failure";
+    UDate startTime, endTime;
+    int32_t diffTime;
 
-    /* try opening the data from dll instead of the dat file */
-    cnv = ucnv_open(TRY_CNV_1, &errorCode);
-    if(cnv != 0) {
-        /* ok */
-        ucnv_close(cnv);
-    } else {
-        fprintf(stderr,
-                "#### WARNING! The converter for " TRY_CNV_1 " cannot be loaded from data dll/so."
-                "Proceeding to load data from dat file.\n");
-        errorCode = U_ZERO_ERROR;
+    U_MAIN_INIT_ARGS(argc, argv);
 
-    }
-    // If user didn't set ICU_DATA, attempt to generate one.
-    IntlTest::setICU_DATA();
+    startTime = uprv_getUTCtime();
 
     for (int i = 1; i < argc; ++i) {
         if (argv[i][0] == '-') {
             const char* str = argv[i] + 1;
-            if (strcmp("verbose", str) == 0)
-                verbose = TRUE;
-            else if (strcmp("v", str) == 0)
+            if (strcmp("verbose", str) == 0 ||
+                strcmp("v", str) == 0)
                 verbose = TRUE;
-            else if (strcmp("noerrormsg", str) == 0)
+            else if (strcmp("noerrormsg", str) == 0 ||
+                     strcmp("n", str) == 0)
                 no_err_msg = TRUE;
-            else if (strcmp("n", str) == 0)
-                no_err_msg = TRUE;
-            else if (strcmp("exhaustive", str) == 0)
-                quick = FALSE;
-            else if (strcmp("e", str) == 0)
+            else if (strcmp("exhaustive", str) == 0 ||
+                     strcmp("e", str) == 0)
                 quick = FALSE;
-            else if (strcmp("all", str) == 0)
+            else if (strcmp("all", str) == 0 ||
+                     strcmp("a", str) == 0)
                 all = TRUE;
-            else if (strcmp("a", str) == 0)
-                all = TRUE;
-            else if (strcmp("leaks", str) == 0)
-                leaks = TRUE;
-            else if (strcmp("l", str) == 0)
+            else if (strcmp("leaks", str) == 0 ||
+                     strcmp("l", str) == 0)
                 leaks = TRUE;
             else if (strcmp("w", str) == 0) {
               warnOnMissingData = TRUE;
               warnOrErr = "WARNING";
-            } else {
+            }
+            else {
                 syntax = TRUE;
             }
         }else{
             name = TRUE;
-            all = FALSE;
         }
     }
 
-    if (all && name) syntax = TRUE;
-    if (!all && !name) syntax = TRUE;
+    if (!all && !name) {
+        all = TRUE;
+    } else if (all && name) {
+        syntax = TRUE;
+    }
 
     if (syntax) {
         fprintf(stdout,
                 "### Syntax:\n"
                 "### IntlTest [-option1 -option2 ...] [testname1 testname2 ...] \n"
                 "### where options are: verbose (v), all (a), noerrormsg (n), \n"
-                "### exhaustive (e) and leaks (l). \n"
+                "### exhaustive (e), leaks (l)"
                 "### (Specify either -all (shortcut -a) or a test name). \n"
                 "### -all will run all of the tests.\n"
                 "### \n"
@@ -1057,31 +1053,55 @@ main(int argc, char* argv[])
     major.setNoErrMsg( no_err_msg );
     major.setQuick( quick );
     major.setLeaks( leaks );
+    major.setWarnOnMissingData( warnOnMissingData );
     fprintf(stdout, "-----------------------------------------------\n");
     fprintf(stdout, " IntlTest (C++) Test Suite for                 \n");
     fprintf(stdout, "   International Components for Unicode %s\n", U_ICU_VERSION);
     fprintf(stdout, "-----------------------------------------------\n");
     fprintf(stdout, " Options:                                       \n");
-    fprintf(stdout, "   all (a)               : %s\n", (all?        "On" : "Off"));
-    fprintf(stdout, "   Verbose (v)           : %s\n", (verbose?    "On" : "Off"));
-    fprintf(stdout, "   No error messages (n) : %s\n", (no_err_msg? "On" : "Off"));
-    fprintf(stdout, "   Exhaustive (e)        : %s\n", (!quick?     "On" : "Off"));
-    fprintf(stdout, "   Leaks (l)             : %s\n", (leaks?      "On" : "Off"));
+    fprintf(stdout, "   all (a)                  : %s\n", (all?               "On" : "Off"));
+    fprintf(stdout, "   Verbose (v)              : %s\n", (verbose?           "On" : "Off"));
+    fprintf(stdout, "   No error messages (n)    : %s\n", (no_err_msg?        "On" : "Off"));
+    fprintf(stdout, "   Exhaustive (e)           : %s\n", (!quick?            "On" : "Off"));
+    fprintf(stdout, "   Leaks (l)                : %s\n", (leaks?             "On" : "Off"));
+    fprintf(stdout, "   Warn on missing data (w) : %s\n", (warnOnMissingData? "On" : "Off"));
     fprintf(stdout, "-----------------------------------------------\n");
 
-    // Check that u_init() works
+    /* Check whether ICU will initialize without forcing the build data directory into
+     *  the ICU_DATA path.  Success here means either the data dll contains data, or that
+     *  this test program was run with ICU_DATA set externally.  Failure of this check
+     *  is normal when ICU data is not packaged into a shared library.
+     *
+     *  Whether or not this test succeeds, we want to cleanup and reinitialize
+     *  with a data path so that data loading from individual files can be tested.
+     */
+    u_init(&errorCode);
+    if (U_FAILURE(errorCode)) {
+        fprintf(stderr,
+            "#### Note:  ICU Init without build-specific setDataDirectory() failed.\n");
+        defaultDataFound = FALSE;
+    }
+    else {
+        defaultDataFound = TRUE;
+    }
+    u_cleanup();
     errorCode = U_ZERO_ERROR;
+
+    /* Initialize ICU */
+    if (!defaultDataFound) {
+        IntlTest::setICU_DATA();   // Must set data directory before u_init() is called.
+    }
     u_init(&errorCode);
     if (U_FAILURE(errorCode)) {
-        fprintf(stdout,
-            "*** u_init() failed with error code = %s\n"
-                "*** Check the ICU_DATA environment variable and\n"
-                "*** check that the data files are present.\n",
-                u_errorName(errorCode));
-        if(!warnOnMissingData) {
-          fprintf(stdout, "*** Exitting.  Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
-          return 1;
-        }
+        fprintf(stderr,
+            "#### ERROR! %s: u_init() failed with status = \"%s\".\n"
+            "*** Check the ICU_DATA environment variable and \n"
+            "*** check that the data files are present.\n", argv[0], u_errorName(errorCode));
+            if(warnOnMissingData == 0) {
+                fprintf(stderr, "*** Exiting.  Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
+                u_cleanup();
+                return 1;
+            }
     }
 
 
@@ -1098,7 +1118,7 @@ main(int argc, char* argv[])
                 "*** check that the data files are present.\n",
                 warnOrErr, ucnv_getDefaultName());
         if(!warnOnMissingData) {
-          fprintf(stdout, "*** Exitting.  Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
+          fprintf(stdout, "*** Exiting.  Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
           return 1;
         }
     }
@@ -1114,7 +1134,7 @@ main(int argc, char* argv[])
                 "*** Check the ICU_DATA environment variable and \n"
                 "*** check that the data files are present.\n", warnOrErr);
         if(!warnOnMissingData) {
-          fprintf(stdout, "*** Exitting.  Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
+          fprintf(stdout, "*** Exiting.  Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
           return 1;
         }
     }
@@ -1127,11 +1147,13 @@ main(int argc, char* argv[])
                 "*** Check the ICU_DATA environment variable and \n"
                 "*** check that the data files are present.\n", warnOrErr);
         if(!warnOnMissingData) {
-          fprintf(stdout, "*** Exitting.  Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
+          fprintf(stdout, "*** Exiting.  Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
           return 1;
         }
     }
 
+    Locale originalLocale;  // Save the default locale for comparison later on.
+
     /* TODO: Add option to call u_cleanup and rerun tests. */
     if (all) {
         major.runTest();
@@ -1168,39 +1190,50 @@ main(int argc, char* argv[])
     free(_testDataPath);
     _testDataPath = 0;
 
+    Locale lastDefaultLocale;
+    if (originalLocale != lastDefaultLocale) {
+        major.errln("FAILURE: A test changed the default locale without resetting it.");
+    }
+
     fprintf(stdout, "\n--------------------------------------\n");
     if (major.getErrors() == 0) {
         /* Call it twice to make sure that the defaults were reset. */
         /* Call it before the OK message to verify proper cleanup. */
         u_cleanup();
-     u_cleanup();
+        u_cleanup();
 
         fprintf(stdout, "OK: All tests passed without error.\n");
+
+        if (major.getDataErrors() != 0) {
+            fprintf(stdout, "\t*WARNING* some data-loading errors were ignored by the -w option.\n");
+        }
     }else{
         fprintf(stdout, "Errors in total: %ld.\n", (long)major.getErrors());
         major.printErrors();
 
+
+        if (major.getDataErrors() != 0) {
+            fprintf(stdout, "\t*Note* some errors are data-loading related. If the data used is not the \n"
+                    "\tstock ICU data (i.e some have been added or removed), consider using\n"
+                    "\tthe '-w' option to turn these errors into warnings.\n");
+        }
+
         /* Call afterwards to display errors. */
         u_cleanup();
     }
 
     fprintf(stdout, "--------------------------------------\n");
 
-    if (!MutexTest::gMutexInitialized) {
-        fprintf(stderr,
-            "#### WARNING!\n"
-            "  The global mutex was not initialized during C++ static initialization.\n"
-            "  You must use an ICU API in a single thread, like ucnv_open() or\n"
-            "  uloc_countAvailable(), before using ICU in multiple threads.\n"
-            "  Most ICU API functions will initialize the global mutex for you.\n"
-            "  If you are using ICU in a single threaded application, please ignore this\n"
-            "  warning.\n"
-            "#### WARNING!\n"
-            );
-    }
     if (execCount <= 0) {
         fprintf(stdout, "***** Not all called tests actually exist! *****\n");
     }
+    endTime = uprv_getUTCtime();
+    diffTime = (int32_t)(endTime - startTime);
+    printf("Elapsed Time: %02d:%02d:%02d.%03d\n",
+        (int)((diffTime%U_MILLIS_PER_DAY)/U_MILLIS_PER_HOUR),
+        (int)((diffTime%U_MILLIS_PER_HOUR)/U_MILLIS_PER_MINUTE),
+        (int)((diffTime%U_MILLIS_PER_MINUTE)/U_MILLIS_PER_SECOND),
+        (int)(diffTime%U_MILLIS_PER_SECOND));
     return major.getErrors();
 }
 
@@ -1225,7 +1258,7 @@ const char* IntlTest::loadTestData(UErrorCode& err){
         /* u_getDataDirectory shoul return \source\data ... set the
          * directory to ..\source\data\..\test\testdata\out\testdata
          */
-               strcpy(tdpath, directory);
+        strcpy(tdpath, directory);
         strcat(tdpath, tdrelativepath);
         strcat(tdpath,"testdata");
 
@@ -1233,7 +1266,7 @@ const char* IntlTest::loadTestData(UErrorCode& err){
 
         if(U_FAILURE(err)){
             err = U_FILE_ACCESS_ERROR;
-            it_errln((UnicodeString)"Could not load testtypes.res in testdata bundle with path " + tdpath + (UnicodeString)" - " + u_errorName(err));
+            it_dataerrln((UnicodeString)"[DATA] Could not load testtypes.res in testdata bundle with path " + tdpath + (UnicodeString)" - " + u_errorName(err));
             return "";
         }
         ures_close(test);
@@ -1243,6 +1276,30 @@ const char* IntlTest::loadTestData(UErrorCode& err){
     return _testDataPath;
 }
 
+const char* IntlTest::getTestDataPath(UErrorCode& err) {
+    return loadTestData(err);
+}
+
+/* Returns the path to icu/source/test/testdata/ */
+const char *IntlTest::getSourceTestData(UErrorCode& /*err*/) {
+    const char *srcDataDir = NULL;
+#ifdef U_TOPSRCDIR
+    srcDataDir = U_TOPSRCDIR U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING;
+#else
+    srcDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING;
+    FILE *f = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING"rbbitst.txt", "r");
+    if (f) {
+        /* We're in icu/source/test/intltest/ */
+        fclose(f);
+    }
+    else {
+        /* We're in icu/source/test/intltest/(Debug|Release) */
+        srcDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING;
+    }
+#endif
+    return srcDataDir;
+}
+
 const char* IntlTest::fgDataDir = NULL;
 
 /* returns the path to icu/source/data */
@@ -1295,14 +1352,14 @@ const char *  IntlTest::pathToDataDirectory()
         }
         else {
             /* __FILE__ on MSVC7 does not contain the directory */
-                       FILE *file = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "Makefile.in", "r");
-                       if (file) {
-                               fclose(file);
-                   fgDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
-                       }
-                       else {
-                   fgDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
-                       }
+            FILE *file = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "Makefile.in", "r");
+            if (file) {
+                fclose(file);
+                fgDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
+            }
+            else {
+                fgDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
+            }
         }
     }
 #endif
@@ -1322,6 +1379,212 @@ UnicodeString CharsToUnicodeString(const char* chars)
     return str.unescape();
 }
 
+UnicodeString ctou(const char* chars) {
+    return CharsToUnicodeString(chars);
+}
+
+#define RAND_M  (714025)
+#define RAND_IA (1366)
+#define RAND_IC (150889)
+
+static int32_t RAND_SEED;
+
+/**
+ * Returns a uniform random value x, with 0.0 <= x < 1.0.  Use
+ * with care: Does not return all possible values; returns one of
+ * 714,025 values, uniformly spaced.  However, the period is
+ * effectively infinite.  See: Numerical Recipes, section 7.1.
+ *
+ * @param seedp pointer to seed. Set *seedp to any negative value
+ * to restart the sequence.
+ */
+float IntlTest::random(int32_t* seedp) {
+    static int32_t iy, ir[98];
+    static UBool first=TRUE;
+    int32_t j;
+    if (*seedp < 0 || first) {
+        first = FALSE;
+        if ((*seedp=(RAND_IC-(*seedp)) % RAND_M) < 0) *seedp = -(*seedp);
+        for (j=1;j<=97;++j) {
+            *seedp=(RAND_IA*(*seedp)+RAND_IC) % RAND_M;
+            ir[j]=(*seedp);
+        }
+        *seedp=(RAND_IA*(*seedp)+RAND_IC) % RAND_M;
+        iy=(*seedp);
+    }
+    j=(int32_t)(1 + 97.0*iy/RAND_M);
+    U_ASSERT(j>=1 && j<=97);
+    iy=ir[j];
+    *seedp=(RAND_IA*(*seedp)+RAND_IC) % RAND_M;
+    ir[j]=(*seedp);
+    return (float) iy/RAND_M;
+}
+
+/**
+ * Convenience method using a global seed.
+ */
+float IntlTest::random() {
+    return random(&RAND_SEED);
+}
+
+static inline UChar toHex(int32_t i) {
+    return (UChar)(i + (i < 10 ? 0x30 : (0x41 - 10)));
+}
+
+static UnicodeString& escape(const UnicodeString& s, UnicodeString& result) {
+    for (int32_t i=0; i<s.length(); ++i) {
+        UChar c = s[i];
+        if (c <= (UChar)0x7F) {
+            result += c;
+        } else {
+            result += (UChar)0x5c;
+            result += (UChar)0x75;
+            result += toHex((c >> 12) & 0xF);
+            result += toHex((c >>  8) & 0xF);
+            result += toHex((c >>  4) & 0xF);
+            result += toHex( c        & 0xF);
+        }
+    }
+    return result;
+}
+
+#define VERBOSE_ASSERTIONS
+
+UBool IntlTest::assertTrue(const char* message, UBool condition, UBool quiet) {
+    if (!condition) {
+        errln("FAIL: assertTrue() failed: %s", message);
+    } else if (!quiet) {
+        logln("Ok: %s", message);
+    }
+    return condition;
+}
+
+UBool IntlTest::assertFalse(const char* message, UBool condition, UBool quiet) {
+    if (condition) {
+        errln("FAIL: assertFalse() failed: %s", message);
+    } else if (!quiet) {
+        logln("Ok: %s", message);
+    }
+    return !condition;
+}
+
+UBool IntlTest::assertSuccess(const char* message, UErrorCode ec) {
+    if (U_FAILURE(ec)) {
+        if (ec == U_FILE_ACCESS_ERROR) {
+            dataerrln("[DATA] Fail: %s.", message);
+        } else {
+            errln("FAIL: %s (%s)", message, u_errorName(ec));
+        }
+        return FALSE;
+    }
+    return TRUE;
+}
+
+UBool IntlTest::assertEquals(const char* message,
+                             const UnicodeString& expected,
+                             const UnicodeString& actual) {
+    if (expected != actual) {
+        errln((UnicodeString)"FAIL: " + message + "; got " +
+              prettify(actual) +
+              "; expected " + prettify(expected));
+        return FALSE;
+    }
+#ifdef VERBOSE_ASSERTIONS
+    else {
+        logln((UnicodeString)"Ok: " + message + "; got " + prettify(actual));
+    }
+#endif
+    return TRUE;
+}
+
+UBool IntlTest::assertEquals(const char* message,
+                             const char* expected,
+                             const char* actual) {
+    if (uprv_strcmp(expected, actual) != 0) {
+        errln((UnicodeString)"FAIL: " + message + "; got \"" +
+              actual +
+              "\"; expected \"" + expected + "\"");
+        return FALSE;
+    }
+#ifdef VERBOSE_ASSERTIONS
+    else {
+        logln((UnicodeString)"Ok: " + message + "; got \"" + actual + "\"");
+    }
+#endif
+    return TRUE;
+}
+
+#if !UCONFIG_NO_FORMATTING
+UBool IntlTest::assertEquals(const char* message,
+                             const Formattable& expected,
+                             const Formattable& actual) {
+    if (expected != actual) {
+        errln((UnicodeString)"FAIL: " + message + "; got " +
+              toString(actual) +
+              "; expected " + toString(expected));
+        return FALSE;
+    }
+#ifdef VERBOSE_ASSERTIONS
+    else {
+        logln((UnicodeString)"Ok: " + message + "; got " + toString(actual));
+    }
+#endif
+    return TRUE;
+}
+#endif
+
+static char ASSERT_BUF[256];
+
+static const char* extractToAssertBuf(const UnicodeString& message) {
+    UnicodeString buf;
+    escape(message, buf);
+    buf.extract(0, 0x7FFFFFFF, ASSERT_BUF, sizeof(ASSERT_BUF)-1, 0);
+    ASSERT_BUF[sizeof(ASSERT_BUF)-1] = 0;
+    return ASSERT_BUF;
+}
+
+UBool IntlTest::assertTrue(const UnicodeString& message, UBool condition, UBool quiet) {
+    return assertTrue(extractToAssertBuf(message), condition, quiet);
+}
+
+UBool IntlTest::assertFalse(const UnicodeString& message, UBool condition, UBool quiet) {
+    return assertFalse(extractToAssertBuf(message), condition, quiet);
+}
+
+UBool IntlTest::assertSuccess(const UnicodeString& message, UErrorCode ec) {
+    return assertSuccess(extractToAssertBuf(message), ec);
+}
+
+UBool IntlTest::assertEquals(const UnicodeString& message,
+                             const UnicodeString& expected,
+                             const UnicodeString& actual) {
+    return assertEquals(extractToAssertBuf(message), expected, actual);
+}
+
+UBool IntlTest::assertEquals(const UnicodeString& message,
+                             const char* expected,
+                             const char* actual) {
+    return assertEquals(extractToAssertBuf(message), expected, actual);
+}
+//--------------------------------------------------------------------
+// Time bomb - allows temporary behavior that expires at a given
+//             release
+//--------------------------------------------------------------------
+
+UBool IntlTest::isICUVersionAtLeast(const UVersionInfo x) {
+    UVersionInfo v;
+    u_getVersion(v);
+    return (uprv_memcmp(v, x, U_MAX_VERSION_LENGTH) >= 0);
+}
+
+#if !UCONFIG_NO_FORMATTING
+UBool IntlTest::assertEquals(const UnicodeString& message,
+                             const Formattable& expected,
+                             const Formattable& actual) {
+    return assertEquals(extractToAssertBuf(message), expected, actual);
+}
+#endif
+
 /*
  * Hey, Emacs, please set the following:
  *
@@ -1330,4 +1593,3 @@ UnicodeString CharsToUnicodeString(const char* chars)
  * End:
  *
  */
-