]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/test/intltest/intltest.cpp
ICU-511.32.tar.gz
[apple/icu.git] / icuSources / test / intltest / intltest.cpp
index 26d2b6a225fe4a56c662a6350dfa7c9123660cf9..6d08af153d822bae757e85211bbe2fccf7e62df9 100644 (file)
@@ -1,6 +1,6 @@
 /********************************************************************
  * COPYRIGHT:
- * Copyright (c) 1997-2004, International Business Machines Corporation and
+ * Copyright (c) 1997-2013, International Business Machines Corporation and
  * others. All Rights Reserved.
  ********************************************************************/
 
 #include "umutex.h"
 #include "uassert.h"
 #include "cmemory.h"
+#include "uoptions.h"
+
+#include "putilimp.h" // for uprv_getRawUTCtime()
+#include "unicode/locid.h"
+#include "unicode/ctest.h" // for str_timeDelta
 
 #ifdef XP_MAC_CONSOLE
 #include <console.h>
@@ -87,10 +92,10 @@ Int64ToUnicodeString(int64_t num)
     char buffer[64];    // nos changed from 10 to 64
     char danger = 'p';  // guard against overrunning the buffer (rtg)
 
-#ifdef WIN32
+#if defined(_MSC_VER)
     sprintf(buffer, "%I64d", num);
 #else
-    sprintf(buffer, "%lld", num);
+    sprintf(buffer, "%lld", (long long)num);
 #endif
     assert(danger == 'p');
 
@@ -109,7 +114,7 @@ operator+(const UnicodeString& left,
     //  53*log(2)/log(10) = 15.95
     // so there is no need to show more than 16 digits. [alan]
 
-    sprintf(buffer, "%.16g", num);
+    sprintf(buffer, "%.17g", num);
     assert(danger == 'p');
 
     return left + buffer;
@@ -118,7 +123,7 @@ operator+(const UnicodeString& left,
 #if !UCONFIG_NO_FORMATTING
 
 /**
- * Return a string display for for this, without surrounding braces.
+ * Return a string display for this, without surrounding braces.
  */
 UnicodeString _toString(const Formattable& f) {
     UnicodeString s;
@@ -165,15 +170,15 @@ UnicodeString _toString(const Formattable& f) {
             }
         }
         break;
-    case Formattable::kObject:
-        if (f.getObject()->getDynamicClassID() ==
-            CurrencyAmount::getStaticClassID()) {
-            const CurrencyAmount& c = (const CurrencyAmount&) *f.getObject();
-            s = _toString(c.getNumber()) + " " + UnicodeString(c.getISOCurrency());
+    case Formattable::kObject: {
+        const CurrencyAmount* c = dynamic_cast<const CurrencyAmount*>(f.getObject());
+        if (c != NULL) {
+            s = _toString(c->getNumber()) + " " + UnicodeString(c->getISOCurrency());
         } else {
             s = UnicodeString("Unknown UObject");
         }
         break;
+    }
     default:
         s = UnicodeString("Unknown Formattable type=") + (int32_t)f.getType();
         break;
@@ -228,6 +233,14 @@ IntlTest::appendHex(uint32_t number,
         0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0
     }; /* "0123456789ABCDEF" */
 
+    if (digits < 0) {  // auto-digits
+        digits = 2;
+        uint32_t max = 0xff;
+        while (number > max) {
+            digits += 2;
+            max = (max << 8) | 0xff;
+        }
+    }
     switch (digits)
     {
     case 8:
@@ -253,6 +266,17 @@ IntlTest::appendHex(uint32_t number,
     return target;
 }
 
+UnicodeString
+IntlTest::toHex(uint32_t number, int32_t digits) {
+    UnicodeString result;
+    appendHex(number, digits, result);
+    return result;
+}
+
+static inline UBool isPrintable(UChar32 c) {
+    return c <= 0x7E && (c >= 0x20 || c == 9 || c == 0xA || c == 0xD);
+}
+
 // Replace nonprintable characters with unicode escapes
 UnicodeString&
 IntlTest::prettify(const UnicodeString &source,
@@ -266,9 +290,9 @@ IntlTest::prettify(const UnicodeString &source,
     for (i = 0; i < source.length(); )
     {
         UChar32 ch = source.char32At(i);
-        i += UTF_CHAR_LENGTH(ch);
+        i += U16_LENGTH(ch);
 
-        if (ch < 0x09 || (ch > 0x0A && ch < 0x20)|| ch > 0x7E)
+        if (!isPrintable(ch))
         {
             if (ch <= 0xFFFF) {
                 target += "\\u";
@@ -301,9 +325,9 @@ IntlTest::prettify(const UnicodeString &source, UBool parseBackslash)
     for (i = 0; i < source.length();)
     {
         UChar32 ch = source.char32At(i);
-        i += UTF_CHAR_LENGTH(ch);
+        i += U16_LENGTH(ch);
 
-        if (ch < 0x09 || (ch > 0x0A && ch < 0x20)|| ch > 0x7E)
+        if (!isPrintable(ch))
         {
             if (parseBackslash) {
                 // If we are preceded by an odd number of backslashes,
@@ -340,68 +364,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.
@@ -541,30 +503,52 @@ void it_errln( UnicodeString message )
         IntlTest::gTest->errln( message );
 }
 
+void it_dataerr( UnicodeString message )
+{
+    if (IntlTest::gTest)
+        IntlTest::gTest->dataerr( message );
+}
+
+void it_dataerrln( UnicodeString message )
+{
+    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_time = FALSE;
     no_err_msg = FALSE;
+    warn_on_missing_data = FALSE;
     quick = FALSE;
     leaks = FALSE;
+    threadCount = 1;
     testoutfp = stdout;
     LL_indentlevel = indentLevel_offset;
+    numProps = 0;
+    strcpy(basePath, "/");
 }
 
 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;
         testoutfp = caller->testoutfp;
         LL_indentlevel = caller->LL_indentlevel + indentLevel_offset;
+        numProps = caller->numProps;
+        for (int32_t i = 0; i < numProps; i++) {
+            proplines[i] = caller->proplines[i];
+        }
     }
 }
 
@@ -572,12 +556,15 @@ 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 );
+    strcpy(testToBeCalled.basePath, this->basePath );
+    UBool result = testToBeCalled.runTest( testPath, par, testToBeCalled.basePath );
+    strcpy(testToBeCalled.basePath, this->basePath ); // reset it.
+    return result;
 }
 
 void IntlTest::setPath( char* pathVal )
 {
-    this->path = pathVal;
+    this->testPath = pathVal;
 }
 
 UBool IntlTest::setVerbose( UBool verboseVal )
@@ -587,6 +574,20 @@ UBool IntlTest::setVerbose( UBool verboseVal )
     return rval;
 }
 
+UBool IntlTest::setNotime( UBool no_time )
+{
+    UBool rval = this->no_time;
+    this->no_time = no_time;
+    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;
@@ -608,43 +609,66 @@ UBool IntlTest::setLeaks( UBool leaksVal )
     return rval;
 }
 
+int32_t IntlTest::setThreadCount( int32_t count )
+{
+    int32_t rval = this->threadCount;
+    this->threadCount = count;
+    return rval;
+}
+
 int32_t IntlTest::getErrors( void )
 {
     return errorCount;
 }
 
-UBool IntlTest::runTest( char* name, char* par )
+int32_t IntlTest::getDataErrors( void )
+{
+    return dataErrorCount;
+}
+
+UBool IntlTest::runTest( char* name, char* par, char *baseName )
 {
     UBool rval;
     char* pos = NULL;
 
+    char* baseNameBuffer = NULL;
+
+    if(baseName == NULL) {
+      baseNameBuffer = (char*)malloc(1024);
+      baseName=baseNameBuffer;
+      strcpy(baseName, "/");
+    }
+
     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, par );
+      rval = runTestLoop( NULL, par, baseName );
 
     }else if (strcmp( name, "LIST" ) == 0) {
         this->usage();
         rval = TRUE;
 
     }else{
-        rval = runTestLoop( name, par );
+      rval = runTestLoop( name, par, baseName );
     }
 
     if (pos)
         *pos = delim;  // restore original value at pos
+    if(baseNameBuffer!=NULL) {
+      free(baseNameBuffer);
+    }
     return rval;
 }
 
 // call individual tests, to be overriden to call implementations
-void IntlTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* par )
+void IntlTest::runIndexedTest( int32_t /*index*/, UBool /*exec*/, const char* & /*name*/, char* /*par*/ )
 {
     // to be overriden by a method like:
     /*
@@ -655,11 +679,10 @@ void IntlTest::runIndexedTest( int32_t index, UBool exec, const char* &name, cha
     }
     */
     this->errln("*** runIndexedTest needs to be overriden! ***");
-    name = ""; exec = exec; index = index; par = par;
 }
 
 
-UBool IntlTest::runTestLoop( char* testname, char* par )
+UBool IntlTest::runTestLoop( char* testname, char* par, char *baseName )
 {
     int32_t    index = 0;
     const char*   name;
@@ -668,28 +691,69 @@ UBool IntlTest::runTestLoop( char* testname, char* par )
     UBool  rval = FALSE;
     UBool   lastTestFailed;
 
+    if(baseName == NULL) {
+      printf("ERROR: baseName can't be null.\n");
+      return FALSE;
+    } else {
+      if ((char *)this->basePath != baseName) {
+        strcpy(this->basePath, baseName);
+      }
+    }
+
+    char * saveBaseLoc = baseName+strlen(baseName);
+
     IntlTest* saveTest = gTest;
     gTest = this;
     do {
         this->runIndexedTest( index, FALSE, name, par );
-        if (!name || (name[0] == 0))
-            break;
-        if (!testname) {
-            run_this_test = TRUE;
-        }else{
-            run_this_test = (UBool) (strcmp( name, testname ) == 0);
+        if (strcmp(name,"skip") == 0) {
+            run_this_test = FALSE;
+        } else {
+            if (!name || (name[0] == 0))
+                break;
+            if (!testname) {
+                run_this_test = TRUE;
+            }else{
+                run_this_test = (UBool) (strcmp( name, testname ) == 0);
+            }
         }
         if (run_this_test) {
             lastErrorCount = errorCount;
             execCount++;
+            char msg[256];
+            sprintf(msg, "%s {", name);
+            LL_message(msg, TRUE);
+            UDate timeStart = uprv_getRawUTCtime();
+            strcpy(saveBaseLoc,name);
+            strcat(saveBaseLoc,"/");
+
             this->runIndexedTest( index, TRUE, name, par );
+
+            UDate timeStop = uprv_getRawUTCtime();
             rval = TRUE; // at least one test has been called
-            char msg[256];
+            char secs[256];
+            if(!no_time) {
+              sprintf(secs, "%f", (timeStop-timeStart)/1000.0);
+            } else {
+              secs[0]=0;
+            }
+            
+
+            strcpy(saveBaseLoc,name);
+
+
+            ctest_xml_testcase(baseName, name, secs, (lastErrorCount!=errorCount)?"err":NULL);
+            
+
+            saveBaseLoc[0]=0; /* reset path */
+            
             if (lastErrorCount == errorCount) {
-                sprintf( msg, "---OK:   %s", name );
+                sprintf( msg, "   } OK:   %s ", name );
+                if(!no_time) str_timeDelta(msg+strlen(msg),timeStop-timeStart);
                 lastTestFailed = FALSE;
             }else{
-                sprintf(msg, "---ERRORS (%li) in %s", (long)(errorCount-lastErrorCount), name);
+                sprintf(msg,  "   } ERRORS (%li) in %s", (long)(errorCount-lastErrorCount), name);
+                if(!no_time) str_timeDelta(msg+strlen(msg),timeStop-timeStart);
 
                 for(int i=0;i<LL_indentlevel;i++) {
                     errorList += " ";
@@ -711,6 +775,8 @@ UBool IntlTest::runTestLoop( char* testname, char* par )
         index++;
     }while(name);
 
+    *saveBaseLoc = 0;
+
     gTest = saveTest;
     return rval;
 }
@@ -773,7 +839,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();
 }
 
@@ -789,6 +863,39 @@ 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();
+    UnicodeString msg;
+    if (!warn_on_missing_data) {
+        IncErrorCount();
+        msg = message;
+    } else {
+        msg = UnicodeString("[DATA] " + message);
+    }
+
+    if (!no_err_msg) LL_message( msg + " - (Are you missing data?)", TRUE );
+}
+
+void IntlTest::errcheckln(UErrorCode status, const UnicodeString &message ) {
+    if (status == U_FILE_ACCESS_ERROR || status == U_MISSING_RESOURCE_ERROR) {
+        dataerrln(message);
+    } else {
+        errln(message);
+    }
+}
+
 /* convenience functions that include sprintf formatting */
 void IntlTest::log(const char *fmt, ...)
 {
@@ -865,6 +972,33 @@ 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::errcheckln(UErrorCode status, const char *fmt, ...)
+{
+    char buffer[4000];
+    va_list ap;
+
+    va_start(ap, fmt);
+    vsprintf(buffer, fmt, ap);
+    va_end(ap);
+    
+    if (status == U_FILE_ACCESS_ERROR || status == U_MISSING_RESOURCE_ERROR) {
+        dataerrln(UnicodeString(buffer, ""));
+    } else {
+        errln(UnicodeString(buffer, ""));
+    }
+}
+
 void IntlTest::printErrors()
 {
      IntlTest::LL_message(errorList, TRUE);
@@ -904,6 +1038,7 @@ void IntlTest::LL_message( UnicodeString message, UBool newline )
     // stream out the message
     length = message.extract(0, message.length(), buffer, sizeof(buffer));
     if (length > 0) {
+        length = length > 10000 ? 10000 : length;
         fwrite(buffer, sizeof(*buffer), length, (FILE *)testoutfp);
     }
 
@@ -964,31 +1099,24 @@ main(int argc, char* argv[])
     UBool all = FALSE;
     UBool verbose = FALSE;
     UBool no_err_msg = FALSE;
+    UBool no_time = FALSE;
     UBool quick = TRUE;
     UBool name = FALSE;
     UBool leaks = FALSE;
     UBool warnOnMissingData = FALSE;
+    UBool defaultDataFound = FALSE;
+    int32_t threadCount = 1;
     UErrorCode errorCode = U_ZERO_ERROR;
     UConverter *cnv = NULL;
     const char *warnOrErr = "Failure";
+    UDate startTime, endTime;
+    int32_t diffTime;
+    const char *props[IntlTest::kMaxProps];
+    int32_t nProps = 0;
 
-#ifdef XP_MAC_CONSOLE
-    argc = ccommand( &argv );
-#endif
-
-    /* Initialize ICU */
-    IntlTest::setICU_DATA();   // Must set data directory before u_init() is called.
-    u_init(&errorCode);
-    if (U_FAILURE(errorCode)) {
-        fprintf(stderr,
-                "#### %s: u_init() failed, error is \"%s\".\n"
-                "#### Most commonly indicates that the ICU data is not accesible.\n"
-                "#### Check setting of ICU_DATA, or check that ICU data library is available\n"
-                "#### ICU_DATA is currently set to \"%s\"\n", argv[0], u_errorName(errorCode), u_getDataDirectory());
-        u_cleanup();
-        return 1;
-    }
+    U_MAIN_INIT_ARGS(argc, argv);
 
+    startTime = uprv_getRawUTCtime();
 
     for (int i = 1; i < argc; ++i) {
         if (argv[i][0] == '-') {
@@ -1008,10 +1136,30 @@ main(int argc, char* argv[])
             else if (strcmp("leaks", str) == 0 ||
                      strcmp("l", str) == 0)
                 leaks = TRUE;
-            else if (strcmp("w", str) == 0) {
+            else if (strcmp("notime", str) == 0 ||
+                     strcmp("T", str) == 0)
+                no_time = TRUE;
+            else if (strcmp("x", str)==0) {
+              if(++i>=argc) {
+                printf("* Error: '-x' option requires an argument. usage: '-x outfile.xml'.\n");
+                syntax = TRUE;
+              }
+              if(ctest_xml_setFileName(argv[i])) { /* set the name */
+                return 1; /* error */
+              }
+            } else if (strcmp("w", str) == 0) {
               warnOnMissingData = TRUE;
               warnOrErr = "WARNING";
             }
+            else if (strncmp("threads:", str, 8) == 0) {
+                threadCount = atoi(str + 8);
+            }
+            else if (strncmp("prop:", str, 5) == 0) {
+                if (nProps < IntlTest::kMaxProps) {
+                    props[nProps] = str + 5;
+                }
+                nProps++;
+            }
             else {
                 syntax = TRUE;
             }
@@ -1030,8 +1178,13 @@ main(int argc, char* argv[])
         fprintf(stdout,
                 "### Syntax:\n"
                 "### IntlTest [-option1 -option2 ...] [testname1 testname2 ...] \n"
-                "### where options are: verbose (v), all (a), noerrormsg (n), \n"
-                "### exhaustive (e), leaks (l)"
+                "### \n"
+                "### Options are: verbose (v), all (a), noerrormsg (n), \n"
+                "### exhaustive (e), leaks (l), -x xmlfile.xml, prop:<propery>=<value>, \n"
+                "### notime (T), \n"
+                "### threads:<threadCount> (Mulithreading must first be \n"
+                "###     enabled otherwise this will be ignored. \n"
+                "###     The default thread count is 1.),\n"
                 "### (Specify either -all (shortcut -a) or a test name). \n"
                 "### -all will run all of the tests.\n"
                 "### \n"
@@ -1047,37 +1200,97 @@ main(int argc, char* argv[])
         return 1;
     }
 
+    if (nProps > IntlTest::kMaxProps) {
+        fprintf(stdout, "### Too many properties.  Exiting.\n");
+    }
+
     UBool all_tests_exist = TRUE;
     MajorTestLevel major;
     major.setVerbose( verbose );
     major.setNoErrMsg( no_err_msg );
     major.setQuick( quick );
     major.setLeaks( leaks );
+    major.setThreadCount( threadCount );
+    major.setWarnOnMissingData( warnOnMissingData );
+    major.setNotime (no_time);
+    for (int32_t i = 0; i < nProps; i++) {
+        major.setProperty(props[i]);
+    }
+
+
     fprintf(stdout, "-----------------------------------------------\n");
     fprintf(stdout, " IntlTest (C++) Test Suite for                 \n");
     fprintf(stdout, "   International Components for Unicode %s\n", U_ICU_VERSION);
+
+
+    {
+       const char *charsetFamily = "Unknown";
+        int32_t voidSize = (int32_t)sizeof(void*);
+        int32_t bits = voidSize * 8;
+        if(U_CHARSET_FAMILY==U_ASCII_FAMILY) {
+           charsetFamily="ASCII";
+        } else if(U_CHARSET_FAMILY==U_EBCDIC_FAMILY) {
+           charsetFamily="EBCDIC";
+        }
+        fprintf(stdout, 
+                    "   Bits: %d, Byte order: %s, Chars: %s\n",
+                     bits, U_IS_BIG_ENDIAN?"Big endian":"Little endian",
+                     charsetFamily);
+    }
     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, "   notime (T)               : %s\n", (no_time?             "On" : "Off"));
+    fprintf(stdout, "   Warn on missing data (w) : %s\n", (warnOnMissingData? "On" : "Off"));
+#if (ICU_USE_THREADS==0)
+    fprintf(stdout, "   Threads                  : Disabled\n");
+#else
+    fprintf(stdout, "   Threads                  : %d\n", threadCount);
+#endif
+    for (int32_t i = 0; i < nProps; i++) {
+        fprintf(stdout, "   Custom property (prop:)  : %s\n", props[i]);
+    }
     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, "*** Exiting.  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;
+            }
     }
 
 
@@ -1128,6 +1341,12 @@ main(int argc, char* argv[])
         }
     }
 
+    Locale originalLocale;  // Save the default locale for comparison later on.
+
+    if(ctest_xml_init("intltest")) 
+      return 1;
+
+
     /* TODO: Add option to call u_cleanup and rerun tests. */
     if (all) {
         major.runTest();
@@ -1139,13 +1358,17 @@ main(int argc, char* argv[])
             if (argv[i][0] != '-') {
                 char* name = argv[i];
                 fprintf(stdout, "\n=== Handling test: %s: ===\n", name);
+
+                char baseName[1024];
+                sprintf(baseName, "/%s/", name);
+
                 char* parameter = strchr( name, '@' );
                 if (parameter) {
                     *parameter = 0;
                     parameter += 1;
                 }
                 execCount = 0;
-                UBool res = major.runTest( name, parameter );
+                UBool res = major.runTest( name, parameter, baseName );
                 if (leaks && res) {
                     major.run_phase2( name, parameter );
                 }
@@ -1153,10 +1376,13 @@ main(int argc, char* argv[])
                     fprintf(stdout, "\n---ERROR: Test doesn't exist: %s!\n", name);
                     all_tests_exist = FALSE;
                 }
+            } else if(!strcmp(argv[i],"-x")) {
+              i++;
             }
         }
     }
 
+
 #if !UCONFIG_NO_FORMATTING
     CalendarTimeZoneTest::cleanup();
 #endif
@@ -1164,18 +1390,34 @@ 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();
     }
@@ -1185,6 +1427,19 @@ main(int argc, char* argv[])
     if (execCount <= 0) {
         fprintf(stdout, "***** Not all called tests actually exist! *****\n");
     }
+    if(!no_time) {
+      endTime = uprv_getRawUTCtime();
+      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));
+    }
+
+    if(ctest_xml_fini())
+      return 1;
+
     return major.getErrors();
 }
 
@@ -1196,10 +1451,10 @@ const char* IntlTest::loadTestData(UErrorCode& err){
         const char* tdrelativepath;
 
 #if defined (U_TOPBUILDDIR)
-        tdrelativepath = "test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING"out"U_FILE_SEP_STRING;
+        tdrelativepath = "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
         directory = U_TOPBUILDDIR;
 #else
-        tdrelativepath = ".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING"out"U_FILE_SEP_STRING;
+        tdrelativepath = ".." U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
         directory = pathToDataDirectory();
 #endif
 
@@ -1217,7 +1472,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)"Could not load testtypes.res in testdata bundle with path " + tdpath + (UnicodeString)" - " + u_errorName(err));
             return "";
         }
         ures_close(test);
@@ -1235,17 +1490,17 @@ const char* IntlTest::getTestDataPath(UErrorCode& err) {
 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;
+    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");
+    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;
+        /* We're in icu/source/test/intltest/Platform/(Debug|Release) */
+        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;
     }
 #endif
     return srcDataDir;
@@ -1303,13 +1558,13 @@ 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");
+            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;
+                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;
+                fgDataDir = ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
             }
         }
     }
@@ -1321,13 +1576,11 @@ const char *  IntlTest::pathToDataDirectory()
 
 /*
  * This is a variant of cintltst/ccolltst.c:CharsToUChars().
- * It converts a character string into a UnicodeString, with
+ * It converts an invariant-character string into a UnicodeString, with
  * unescaping \u sequences.
  */
-UnicodeString CharsToUnicodeString(const char* chars)
-{
-    UnicodeString str(chars, ""); // Invariant conversion
-    return str.unescape();
+UnicodeString CharsToUnicodeString(const char* chars){
+    return UnicodeString(chars, -1, US_INV).unescape();
 }
 
 UnicodeString ctou(const char* chars) {
@@ -1401,11 +1654,28 @@ static UnicodeString& escape(const UnicodeString& s, UnicodeString& 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);
+UBool IntlTest::assertTrue(const char* message, UBool condition, UBool quiet, UBool possibleDataError, const char *file, int line) {
+    if (file != NULL) {
+        if (!condition) {
+            if (possibleDataError) {
+                dataerrln("%s:%d: FAIL: assertTrue() failed: %s", file, line, message);
+            } else {
+                errln("%s:%d: FAIL: assertTrue() failed: %s", file, line, message);
+            }
+        } else if (!quiet) {
+            logln("%s:%d: Ok: %s", file, line, message);
+        }
+    } else {
+        if (!condition) {
+            if (possibleDataError) {
+                dataerrln("FAIL: assertTrue() failed: %s", message);
+            } else {
+                errln("FAIL: assertTrue() failed: %s", message);
+            }
+        } else if (!quiet) {
+            logln("Ok: %s", message);
+        }
+
     }
     return condition;
 }
@@ -1419,9 +1689,14 @@ UBool IntlTest::assertFalse(const char* message, UBool condition, UBool quiet) {
     return !condition;
 }
 
-UBool IntlTest::assertSuccess(const char* message, UErrorCode ec) {
+UBool IntlTest::assertSuccess(const char* message, UErrorCode ec, UBool possibleDataError) {
     if (U_FAILURE(ec)) {
-        errln("FAIL: %s (%s)", message, u_errorName(ec));
+        if (possibleDataError) {
+            dataerrln("FAIL: %s (%s)", message, u_errorName(ec));
+        } else {
+            errcheckln(ec, "FAIL: %s (%s)", message, u_errorName(ec));
+        }
+        
         return FALSE;
     }
     return TRUE;
@@ -1429,11 +1704,18 @@ UBool IntlTest::assertSuccess(const char* message, UErrorCode ec) {
 
 UBool IntlTest::assertEquals(const char* message,
                              const UnicodeString& expected,
-                             const UnicodeString& actual) {
+                             const UnicodeString& actual,
+                             UBool possibleDataError) {
     if (expected != actual) {
-        errln((UnicodeString)"FAIL: " + message + "; got " +
-              prettify(actual) +
-              "; expected " + prettify(expected));
+        if (possibleDataError) {
+            dataerrln((UnicodeString)"FAIL: " + message + "; got " +
+                  prettify(actual) +
+                  "; expected " + prettify(expected));
+        } else {
+            errln((UnicodeString)"FAIL: " + message + "; got " +
+                  prettify(actual) +
+                  "; expected " + prettify(expected));
+        }
         return FALSE;
     }
 #ifdef VERBOSE_ASSERTIONS
@@ -1461,6 +1743,23 @@ UBool IntlTest::assertEquals(const char* message,
     return TRUE;
 }
 
+UBool IntlTest::assertEquals(const char* message,
+                             int32_t expected,
+                             int32_t actual) {
+    if (expected != actual) {
+        errln((UnicodeString)"FAIL: " + message + "; got " +
+              actual + "=0x" + toHex(actual) +
+              "; expected " + expected + "=0x" + toHex(expected));
+        return FALSE;
+    }
+#ifdef VERBOSE_ASSERTIONS
+    else {
+        logln((UnicodeString)"Ok: " + message + "; got " + actual + "=0x" + toHex(actual));
+    }
+#endif
+    return TRUE;
+}
+
 #if !UCONFIG_NO_FORMATTING
 UBool IntlTest::assertEquals(const char* message,
                              const Formattable& expected,
@@ -1518,10 +1817,11 @@ UBool IntlTest::assertEquals(const UnicodeString& message,
 //             release
 //--------------------------------------------------------------------
 
-UBool IntlTest::isICUVersionAtLeast(const UVersionInfo x) {
-    UVersionInfo v;
-    u_getVersion(v);
-    return (uprv_memcmp(v, x, U_MAX_VERSION_LENGTH) >= 0);
+UBool IntlTest::isICUVersionBefore(int major, int minor, int milli) {
+    UVersionInfo iv;
+    UVersionInfo ov = { (uint8_t)major, (uint8_t)minor, (uint8_t)milli, 0 };
+    u_getVersion(iv);
+    return uprv_memcmp(iv, ov, U_MAX_VERSION_LENGTH) < 0;
 }
 
 #if !UCONFIG_NO_FORMATTING
@@ -1532,6 +1832,27 @@ UBool IntlTest::assertEquals(const UnicodeString& message,
 }
 #endif
 
+void IntlTest::setProperty(const char* propline) {
+    if (numProps < kMaxProps) {
+        proplines[numProps] = propline;
+    }
+    numProps++;
+}
+
+const char* IntlTest::getProperty(const char* prop) {
+    const char* val = NULL;
+    for (int32_t i = 0; i < numProps; i++) {
+        int32_t plen = uprv_strlen(prop);
+        if ((int32_t)uprv_strlen(proplines[i]) > plen + 1
+                && proplines[i][plen] == '='
+                && uprv_strncmp(proplines[i], prop, plen) == 0) {
+            val = &(proplines[i][plen+1]);
+            break;
+        }
+    }
+    return val;
+}
+
 /*
  * Hey, Emacs, please set the following:
  *