]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/test/intltest/intltest.cpp
ICU-62123.0.1.tar.gz
[apple/icu.git] / icuSources / test / intltest / intltest.cpp
index 58563504015d5481aab2f5cd3bfe1edfc2701ec1..e85ba87fca8ee51a2199db44065e434cad48884a 100644 (file)
@@ -1,6 +1,8 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /********************************************************************
  * COPYRIGHT:
- * Copyright (c) 1997-2011, International Business Machines Corporation and
+ * Copyright (c) 1997-2016, International Business Machines Corporation and
  * others. All Rights Reserved.
  ********************************************************************/
 
  * IntlTest is a base class for tests.
  */
 
-#include <stdio.h>
-#include <string.h>
 #include <assert.h>
 #include <stdarg.h>
+#include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <cmath>
 
-#include "unicode/unistr.h"
-#include "unicode/ures.h"
-#include "unicode/smpdtfmt.h"
-#include "unicode/ucnv.h"
-#include "unicode/uclean.h"
-#include "unicode/timezone.h"
+#include "unicode/ctest.h" // for str_timeDelta
 #include "unicode/curramt.h"
+#include "unicode/locid.h"
 #include "unicode/putil.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/timezone.h"
+#include "unicode/uclean.h"
+#include "unicode/ucnv.h"
+#include "unicode/unistr.h"
+#include "unicode/ures.h"
+#include "unicode/utf16.h"
 
 #include "intltest.h"
+
 #include "caltztst.h"
-#include "itmajor.h"
+#include "cmemory.h"
 #include "cstring.h"
-#include "umutex.h"
+#include "itmajor.h"
+#include "mutex.h"
+#include "putilimp.h" // for uprv_getRawUTCtime()
 #include "uassert.h"
-#include "cmemory.h"
+#include "udbgutil.h"
+#include "umutex.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>
 #include "Files.h"
@@ -49,6 +55,8 @@ static char* _testDataPath=NULL;
 
 // Static list of errors found
 static UnicodeString errorList;
+static void *knownList = NULL; // known issues
+static UBool noKnownIssues = FALSE; // if TRUE, don't emit known issues
 
 //-----------------------------------------------------------------------------
 //convenience classes to ease porting code that uses the Java
@@ -102,6 +110,18 @@ Int64ToUnicodeString(int64_t num)
     return buffer;
 }
 
+UnicodeString
+DoubleToUnicodeString(double num)
+{
+    char buffer[64];    // nos changed from 10 to 64
+    char danger = 'p';  // guard against overrunning the buffer (rtg)
+
+    sprintf(buffer, "%1.14e", num);
+    assert(danger == 'p');
+
+    return buffer;
+}
+
 // [LIU] Just to get things working
 UnicodeString
 operator+(const UnicodeString& left,
@@ -120,6 +140,14 @@ operator+(const UnicodeString& left,
     return left + buffer;
 }
 
+#if 0
+UnicodeString
+operator+(const UnicodeString& left,
+          int64_t num) {
+  return left + Int64ToUnicodeString(num);
+}
+#endif
+
 #if !UCONFIG_NO_FORMATTING
 
 /**
@@ -204,6 +232,18 @@ UnicodeString toString(int32_t n) {
     return UnicodeString() + (long)n;
 }
 
+
+
+UnicodeString toString(UBool b) {
+  return b ? UnicodeString("TRUE"):UnicodeString("FALSE");
+}
+
+UnicodeString toString(const UnicodeSet& uniset, UErrorCode& status) {
+    UnicodeString result;
+    uniset.toPattern(result, status);
+    return result;
+}
+
 // stephen - cleaned up 05/05/99
 UnicodeString operator+(const UnicodeString& left, char num)
 { return left + (long)num; }
@@ -233,22 +273,37 @@ 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:
         target += digitString[(number >> 28) & 0xF];
+        U_FALLTHROUGH;
     case 7:
         target += digitString[(number >> 24) & 0xF];
+        U_FALLTHROUGH;
     case 6:
         target += digitString[(number >> 20) & 0xF];
+        U_FALLTHROUGH;
     case 5:
         target += digitString[(number >> 16) & 0xF];
+        U_FALLTHROUGH;
     case 4:
         target += digitString[(number >> 12) & 0xF];
+        U_FALLTHROUGH;
     case 3:
         target += digitString[(number >>  8) & 0xF];
+        U_FALLTHROUGH;
     case 2:
         target += digitString[(number >>  4) & 0xF];
+        U_FALLTHROUGH;
     case 1:
         target += digitString[(number >>  0) & 0xF];
         break;
@@ -258,6 +313,13 @@ 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);
 }
@@ -413,7 +475,7 @@ void IntlTest::setICU_DATA() {
         }
         else {
             /* __FILE__ on MSVC7 does not contain the directory */
-            u_setDataDirectory(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING);
+            u_setDataDirectory(".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING);
             return;
         }
     }
@@ -508,15 +570,17 @@ IntlTest::IntlTest()
     errorCount = 0;
     dataErrorCount = 0;
     verbose = FALSE;
+    no_time = FALSE;
     no_err_msg = FALSE;
     warn_on_missing_data = FALSE;
     quick = FALSE;
     leaks = FALSE;
-    threadCount = 1;
+    threadCount = 12;
     testoutfp = stdout;
     LL_indentlevel = indentLevel_offset;
     numProps = 0;
     strcpy(basePath, "/");
+    currName[0]=0;
 }
 
 void IntlTest::setCaller( IntlTest* callingTest )
@@ -527,6 +591,7 @@ void IntlTest::setCaller( IntlTest* callingTest )
         verbose = caller->verbose;
         no_err_msg = caller->no_err_msg;
         quick = caller->quick;
+        threadCount = caller->threadCount;
         testoutfp = caller->testoutfp;
         LL_indentlevel = caller->LL_indentlevel + indentLevel_offset;
         numProps = caller->numProps;
@@ -558,6 +623,13 @@ 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;
@@ -644,10 +716,10 @@ UBool IntlTest::runTest( char* name, char* par, char *baseName )
     return rval;
 }
 
-// call individual tests, to be overriden to call implementations
-void IntlTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* par )
+// call individual tests, to be overridden to call implementations
+void IntlTest::runIndexedTest( int32_t /*index*/, UBool /*exec*/, const char* & /*name*/, char* /*par*/ )
 {
-    // to be overriden by a method like:
+    // to be overridden by a method like:
     /*
     switch (index) {
         case 0: name = "First Test"; if (exec) FirstTest( par ); break;
@@ -655,8 +727,7 @@ void IntlTest::runIndexedTest( int32_t index, UBool exec, const char* &name, cha
         default: name = ""; break;
     }
     */
-    this->errln("*** runIndexedTest needs to be overriden! ***");
-    name = ""; exec = exec; index = index; par = par;
+    this->errln("*** runIndexedTest needs to be overridden! ***");
 }
 
 
@@ -705,12 +776,18 @@ UBool IntlTest::runTestLoop( char* testname, char* par, char *baseName )
             strcpy(saveBaseLoc,name);
             strcat(saveBaseLoc,"/");
 
+            strcpy(currName, name); // set
             this->runIndexedTest( index, TRUE, name, par );
+            currName[0]=0; // reset
 
             UDate timeStop = uprv_getRawUTCtime();
             rval = TRUE; // at least one test has been called
             char secs[256];
-            sprintf(secs, "%f", (timeStop-timeStart)/1000.0);
+            if(!no_time) {
+              sprintf(secs, "%f", (timeStop-timeStart)/1000.0);
+            } else {
+              secs[0]=0;
+            }
             
 
             strcpy(saveBaseLoc,name);
@@ -723,11 +800,11 @@ UBool IntlTest::runTestLoop( char* testname, char* par, char *baseName )
             
             if (lastErrorCount == errorCount) {
                 sprintf( msg, "   } OK:   %s ", name );
-                str_timeDelta(msg+strlen(msg),timeStop-timeStart);
+                if(!no_time) str_timeDelta(msg+strlen(msg),timeStop-timeStart);
                 lastTestFailed = FALSE;
             }else{
                 sprintf(msg,  "   } ERRORS (%li) in %s", (long)(errorCount-lastErrorCount), name);
-                str_timeDelta(msg+strlen(msg),timeStop-timeStart);
+                if(!no_time) str_timeDelta(msg+strlen(msg),timeStop-timeStart);
 
                 for(int i=0;i<LL_indentlevel;i++) {
                     errorList += " ";
@@ -850,7 +927,7 @@ void IntlTest::dataerr( const UnicodeString &message )
 
 void IntlTest::dataerrln( const UnicodeString &message )
 {
-    IncDataErrorCount();
+    int32_t errCount = IncDataErrorCount();
     UnicodeString msg;
     if (!warn_on_missing_data) {
         IncErrorCount();
@@ -859,7 +936,13 @@ void IntlTest::dataerrln( const UnicodeString &message )
         msg = UnicodeString("[DATA] " + message);
     }
 
-    if (!no_err_msg) LL_message( msg + " - (Are you missing data?)", TRUE );
+    if (!no_err_msg) {
+      if ( errCount == 1) {
+          LL_message( msg + " - (Are you missing data?)", TRUE ); // only show this message the first time
+      } else {
+          LL_message( msg , TRUE );
+      }
+    }
 }
 
 void IntlTest::errcheckln(UErrorCode status, const UnicodeString &message ) {
@@ -881,7 +964,7 @@ void IntlTest::log(const char *fmt, ...)
     vsprintf(buffer, fmt, ap);
     va_end(ap);
     if( verbose ) {
-        log(UnicodeString(buffer, ""));
+        log(UnicodeString(buffer, (const char *)NULL));
     }
 }
 
@@ -895,10 +978,47 @@ void IntlTest::logln(const char *fmt, ...)
     vsprintf(buffer, fmt, ap);
     va_end(ap);
     if( verbose ) {
-        logln(UnicodeString(buffer, ""));
+        logln(UnicodeString(buffer, (const char *)NULL));
     }
 }
 
+UBool IntlTest::logKnownIssue(const char *ticket, const char *fmt, ...)
+{
+    char buffer[4000];
+    va_list ap;
+
+    va_start(ap, fmt);
+    /* sprintf it just to make sure that the information is valid */
+    vsprintf(buffer, fmt, ap);
+    va_end(ap);
+    return logKnownIssue(ticket, UnicodeString(buffer, (const char *)NULL));
+}
+
+UBool IntlTest::logKnownIssue(const char *ticket) {
+  return logKnownIssue(ticket, UnicodeString());
+}
+
+UBool IntlTest::logKnownIssue(const char *ticket, const UnicodeString &msg) {
+  if(noKnownIssues) return FALSE;
+
+  char fullpath[2048];
+  strcpy(fullpath, basePath);
+  strcat(fullpath, currName);
+  UnicodeString msg2 = msg;
+  UBool firstForTicket = TRUE, firstForWhere = TRUE;
+  knownList = udbg_knownIssue_openU(knownList, ticket, fullpath, msg2.getTerminatedBuffer(), &firstForTicket, &firstForWhere);
+
+  msg2 = UNICODE_STRING_SIMPLE("(Known issue #") +
+      UnicodeString(ticket, -1, US_INV) + UNICODE_STRING_SIMPLE(") ") + msg;
+  if(firstForTicket || firstForWhere) {
+    infoln(msg2);
+  } else {
+    logln(msg2);
+  }
+
+  return TRUE;
+}
+
 /* convenience functions that include sprintf formatting */
 void IntlTest::info(const char *fmt, ...)
 {
@@ -909,7 +1029,7 @@ void IntlTest::info(const char *fmt, ...)
     /* sprintf it just to make sure that the information is valid */
     vsprintf(buffer, fmt, ap);
     va_end(ap);
-    info(UnicodeString(buffer, ""));
+    info(UnicodeString(buffer, (const char *)NULL));
 }
 
 void IntlTest::infoln(const char *fmt, ...)
@@ -921,7 +1041,7 @@ void IntlTest::infoln(const char *fmt, ...)
     /* sprintf it just to make sure that the information is valid */
     vsprintf(buffer, fmt, ap);
     va_end(ap);
-    infoln(UnicodeString(buffer, ""));
+    infoln(UnicodeString(buffer, (const char *)NULL));
 }
 
 void IntlTest::err(const char *fmt, ...)
@@ -932,7 +1052,7 @@ void IntlTest::err(const char *fmt, ...)
     va_start(ap, fmt);
     vsprintf(buffer, fmt, ap);
     va_end(ap);
-    err(UnicodeString(buffer, ""));
+    err(UnicodeString(buffer, (const char *)NULL));
 }
 
 void IntlTest::errln(const char *fmt, ...)
@@ -943,7 +1063,7 @@ void IntlTest::errln(const char *fmt, ...)
     va_start(ap, fmt);
     vsprintf(buffer, fmt, ap);
     va_end(ap);
-    errln(UnicodeString(buffer, ""));
+    errln(UnicodeString(buffer, (const char *)NULL));
 }
 
 void IntlTest::dataerrln(const char *fmt, ...)
@@ -954,7 +1074,7 @@ void IntlTest::dataerrln(const char *fmt, ...)
     va_start(ap, fmt);
     vsprintf(buffer, fmt, ap);
     va_end(ap);
-    dataerrln(UnicodeString(buffer, ""));
+    dataerrln(UnicodeString(buffer, (const char *)NULL));
 }
 
 void IntlTest::errcheckln(UErrorCode status, const char *fmt, ...)
@@ -967,9 +1087,9 @@ void IntlTest::errcheckln(UErrorCode status, const char *fmt, ...)
     va_end(ap);
     
     if (status == U_FILE_ACCESS_ERROR || status == U_MISSING_RESOURCE_ERROR) {
-        dataerrln(UnicodeString(buffer, ""));
+        dataerrln(UnicodeString(buffer, (const char *)NULL));
     } else {
-        errln(UnicodeString(buffer, ""));
+        errln(UnicodeString(buffer, (const char *)NULL));
     }
 }
 
@@ -978,8 +1098,27 @@ void IntlTest::printErrors()
      IntlTest::LL_message(errorList, TRUE);
 }
 
+UBool IntlTest::printKnownIssues()
+{
+  if(knownList != NULL) {
+    udbg_knownIssue_print(knownList);
+    udbg_knownIssue_close(knownList);
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+static UMutex messageMutex = U_MUTEX_INITIALIZER;
+
 void IntlTest::LL_message( UnicodeString message, UBool newline )
 {
+    // Synchronize this function.
+    // All error messages generated by tests funnel through here.
+    // Multithreaded tests can concurrently generate errors, requiring synchronization
+    // to keep each message together.
+    Mutex lock(&messageMutex);
+
     // string that starts with a LineFeed character and continues
     // with spaces according to the current indentation
     static const UChar indentUChars[] = {
@@ -995,9 +1134,10 @@ void IntlTest::LL_message( UnicodeString message, UBool newline )
         32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
         32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32
     };
+    U_ASSERT(1 + LL_indentlevel <= UPRV_LENGTHOF(indentUChars));
     UnicodeString indent(FALSE, indentUChars, 1 + LL_indentlevel);
 
-    char buffer[10000];
+    char buffer[30000];
     int32_t length;
 
     // stream out the indentation string first if necessary
@@ -1012,7 +1152,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;
+        length = length > 30000 ? 30000 : length;
         fwrite(buffer, sizeof(*buffer), length, (FILE *)testoutfp);
     }
 
@@ -1066,6 +1206,10 @@ IntlTest::run_phase2( char* name, char* par ) // supports reporting memory leaks
 #   define TRY_CNV_2 "sjis"
 #endif
 
+#ifdef UNISTR_COUNT_FINAL_STRING_LENGTHS
+U_CAPI void unistr_printLengths();
+#endif
+
 int
 main(int argc, char* argv[])
 {
@@ -1073,12 +1217,15 @@ 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 utf8 = FALSE;
+    const char *summary_file = NULL;
     UBool warnOnMissingData = FALSE;
     UBool defaultDataFound = FALSE;
-    int32_t threadCount = 1;
+    int32_t threadCount = 12;
     UErrorCode errorCode = U_ZERO_ERROR;
     UConverter *cnv = NULL;
     const char *warnOrErr = "Failure";
@@ -1106,9 +1253,20 @@ main(int argc, char* argv[])
             else if (strcmp("all", str) == 0 ||
                      strcmp("a", str) == 0)
                 all = TRUE;
+            else if (strcmp("utf-8", str) == 0 ||
+                     strcmp("u", str) == 0)
+                utf8 = TRUE;
+            else if (strcmp("noknownissues", str) == 0 ||
+                     strcmp("K", str) == 0)
+                noKnownIssues = TRUE;
             else if (strcmp("leaks", str) == 0 ||
                      strcmp("l", str) == 0)
                 leaks = TRUE;
+            else if (strcmp("notime", str) == 0 ||
+                     strcmp("T", str) == 0)
+                no_time = TRUE;
+            else if (strncmp("E", str, 1) == 0)
+                summary_file = str+1;
             else if (strcmp("x", str)==0) {
               if(++i>=argc) {
                 printf("* Error: '-x' option requires an argument. usage: '-x outfile.xml'.\n");
@@ -1151,9 +1309,9 @@ main(int argc, char* argv[])
                 "### \n"
                 "### Options are: verbose (v), all (a), noerrormsg (n), \n"
                 "### exhaustive (e), leaks (l), -x xmlfile.xml, prop:<propery>=<value>, \n"
-                "### threads:<threadCount> (Mulithreading must first be \n"
-                "###     enabled otherwise this will be ignored. \n"
-                "###     The default thread count is 1.),\n"
+                "### notime (T), \n"
+                "### threads:<threadCount>\n"
+                "###     (The default thread count is 12.),\n"
                 "### (Specify either -all (shortcut -a) or a test name). \n"
                 "### -all will run all of the tests.\n"
                 "### \n"
@@ -1173,7 +1331,6 @@ main(int argc, char* argv[])
         fprintf(stdout, "### Too many properties.  Exiting.\n");
     }
 
-    UBool all_tests_exist = TRUE;
     MajorTestLevel major;
     major.setVerbose( verbose );
     major.setNoErrMsg( no_err_msg );
@@ -1181,6 +1338,7 @@ main(int argc, char* argv[])
     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]);
     }
@@ -1212,17 +1370,19 @@ main(int argc, char* argv[])
     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, "   utf-8 (u)                : %s\n", (utf8?              "On" : "Off"));
+    fprintf(stdout, "   notime (T)               : %s\n", (no_time?             "On" : "Off"));
+    fprintf(stdout, "   noknownissues (K)        : %s\n", (noKnownIssues?      "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");
 
+    if(utf8) {
+      ucnv_setDefaultName("utf-8");
+    }
     /* 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
@@ -1241,6 +1401,9 @@ main(int argc, char* argv[])
         defaultDataFound = TRUE;
     }
     u_cleanup();
+    if(utf8) {
+      ucnv_setDefaultName("utf-8");
+    }
     errorCode = U_ZERO_ERROR;
 
     /* Initialize ICU */
@@ -1260,7 +1423,6 @@ main(int argc, char* argv[])
             }
     }
 
-
     // initial check for the default converter
     errorCode = U_ZERO_ERROR;
     cnv = ucnv_open(0, &errorCode);
@@ -1341,7 +1503,6 @@ main(int argc, char* argv[])
                 }
                 if (!res || (execCount <= 0)) {
                     fprintf(stdout, "\n---ERROR: Test doesn't exist: %s!\n", name);
-                    all_tests_exist = FALSE;
                 }
             } else if(!strcmp(argv[i],"-x")) {
               i++;
@@ -1363,6 +1524,9 @@ main(int argc, char* argv[])
     }
 
     fprintf(stdout, "\n--------------------------------------\n");
+    if( major.printKnownIssues() ) {
+      fprintf(stdout, " To run suppressed tests, use the -K option. \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. */
@@ -1378,6 +1542,16 @@ main(int argc, char* argv[])
         fprintf(stdout, "Errors in total: %ld.\n", (long)major.getErrors());
         major.printErrors();
 
+        if(summary_file != NULL) {
+          FILE *summf = fopen(summary_file, "w");
+          if( summf != NULL) {
+            char buf[10000];
+            int32_t length = errorList.extract(0, errorList.length(), buf, sizeof(buf));
+            fwrite(buf, sizeof(*buf), length, (FILE*)summf);
+            fclose(summf);
+          }
+        }
+
 
         if (major.getDataErrors() != 0) {
             fprintf(stdout, "\t*Note* some errors are data-loading related. If the data used is not the \n"
@@ -1389,18 +1563,24 @@ main(int argc, char* argv[])
         u_cleanup();
     }
 
+#ifdef UNISTR_COUNT_FINAL_STRING_LENGTHS
+    unistr_printLengths();
+#endif
+
     fprintf(stdout, "--------------------------------------\n");
 
     if (execCount <= 0) {
         fprintf(stdout, "***** Not all called tests actually exist! *****\n");
     }
-    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(!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;
@@ -1416,10 +1596,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
 
@@ -1455,22 +1635,65 @@ 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/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;
+        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;
 }
 
+char *IntlTest::getUnidataPath(char path[]) {
+    const int kUnicodeDataTxtLength = 15;  // strlen("UnicodeData.txt")
+
+    // Look inside ICU_DATA first.
+    strcpy(path, pathToDataDirectory());
+    strcat(path, "unidata" U_FILE_SEP_STRING "UnicodeData.txt");
+    FILE *f = fopen(path, "r");
+    if(f != NULL) {
+        fclose(f);
+        *(strchr(path, 0) - kUnicodeDataTxtLength) = 0;  // Remove the basename.
+        return path;
+    }
+
+    // As a fallback, try to guess where the source data was located
+    // at the time ICU was built, and look there.
+#   ifdef U_TOPSRCDIR
+        strcpy(path, U_TOPSRCDIR  U_FILE_SEP_STRING "data");
+#   else
+        UErrorCode errorCode = U_ZERO_ERROR;
+        const char *testDataPath = loadTestData(errorCode);
+        if(U_FAILURE(errorCode)) {
+            it_errln(UnicodeString(
+                        "unable to find path to source/data/unidata/ and loadTestData() failed: ") +
+                    u_errorName(errorCode));
+            return NULL;
+        }
+        strcpy(path, testDataPath);
+        strcat(path, U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".."
+                     U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".."
+                     U_FILE_SEP_STRING "data");
+#   endif
+    strcat(path, U_FILE_SEP_STRING);
+    strcat(path, "unidata" U_FILE_SEP_STRING "UnicodeData.txt");
+    f = fopen(path, "r");
+    if(f != NULL) {
+        fclose(f);
+        *(strchr(path, 0) - kUnicodeDataTxtLength) = 0;  // Remove the basename.
+        return path;
+    }
+    return NULL;
+}
+
 const char* IntlTest::fgDataDir = NULL;
 
 /* returns the path to icu/source/data */
@@ -1523,13 +1746,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".."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;
             }
         }
     }
@@ -1596,6 +1819,39 @@ float IntlTest::random() {
     return random(&RAND_SEED);
 }
 
+
+/*
+ * Integer random number class implementation.
+ * Similar to C++ std::minstd_rand, with the same algorithm & constants.
+ */
+IntlTest::icu_rand::icu_rand(uint32_t seed) {
+    seed = seed % 2147483647UL;
+    if (seed == 0) {
+        seed = 1;
+    }
+    fLast = seed;
+}
+
+IntlTest::icu_rand::~icu_rand() {}
+
+void IntlTest::icu_rand::seed(uint32_t seed) {
+    if (seed == 0) {
+        seed = 1;
+    }
+    fLast = seed;
+}
+
+uint32_t IntlTest::icu_rand::operator() () {
+    fLast = ((uint64_t)fLast * 48271UL) % 2147483647UL;
+    return fLast;
+}
+
+uint32_t IntlTest::icu_rand::getSeed() {
+    return (uint32_t) fLast;
+}
+
+
+
 static inline UChar toHex(int32_t i) {
     return (UChar)(i + (i < 10 ? 0x30 : (0x41 - 10)));
 }
@@ -1619,37 +1875,58 @@ static UnicodeString& escape(const UnicodeString& s, UnicodeString& result) {
 
 #define VERBOSE_ASSERTIONS
 
-UBool IntlTest::assertTrue(const char* message, UBool condition, UBool quiet, UBool possibleDataError) {
-    if (!condition) {
-        if (possibleDataError) {
-            dataerrln("FAIL: assertTrue() failed: %s", message);
-        } else {
-            errln("FAIL: assertTrue() failed: %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 (!quiet) {
-        logln("Ok: %s", 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;
 }
 
-UBool IntlTest::assertFalse(const char* message, UBool condition, UBool quiet) {
+UBool IntlTest::assertFalse(const char* message, UBool condition, UBool quiet, UBool possibleDataError) {
     if (condition) {
-        errln("FAIL: assertFalse() failed: %s", message);
+        if (possibleDataError) {
+            dataerrln("FAIL: assertTrue() failed: %s", message);
+        } else {
+            errln("FAIL: assertTrue() failed: %s", message);
+        }
     } else if (!quiet) {
         logln("Ok: %s", message);
     }
     return !condition;
 }
 
-UBool IntlTest::assertSuccess(const char* message, UErrorCode ec, UBool possibleDataError) {
+UBool IntlTest::assertSuccess(const char* message, UErrorCode ec, UBool possibleDataError, const char *file, int line) {
+    if( file==NULL ) {
+      file = ""; // prevent failure if no file given
+    }
     if (U_FAILURE(ec)) {
         if (possibleDataError) {
-            dataerrln("FAIL: %s (%s)", message, u_errorName(ec));
+          dataerrln("FAIL: %s:%d: %s (%s)", file, line, message, u_errorName(ec));
         } else {
-            errcheckln(ec, "FAIL: %s (%s)", message, u_errorName(ec));
+          errcheckln(ec, "FAIL: %s:%d: %s (%s)", file, line, message, u_errorName(ec));
         }
-        
         return FALSE;
+    } else {
+      logln("OK: %s:%d: %s - (%s)", file, line, message, u_errorName(ec));
     }
     return TRUE;
 }
@@ -1695,16 +1972,130 @@ UBool IntlTest::assertEquals(const char* message,
     return TRUE;
 }
 
-#if !UCONFIG_NO_FORMATTING
 UBool IntlTest::assertEquals(const char* message,
-                             const Formattable& expected,
-                             const Formattable& actual) {
+                             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;
+}
+
+UBool IntlTest::assertEquals(const char* message,
+                             int64_t expected,
+                             int64_t actual) {
+    if (expected != actual) {
+        errln((UnicodeString)"FAIL: " + message + "; got int64 " +
+              Int64ToUnicodeString(actual) + 
+              "; expected " + Int64ToUnicodeString(expected) );
+        return FALSE;
+    }
+#ifdef VERBOSE_ASSERTIONS
+    else {
+      logln((UnicodeString)"Ok: " + message + "; got int64 " + Int64ToUnicodeString(actual));
+    }
+#endif
+    return TRUE;
+}
+
+UBool IntlTest::assertEquals(const char* message,
+                             double expected,
+                             double actual) {
+    bool bothNaN = std::isnan(expected) && std::isnan(actual);
+    if (expected != actual && !bothNaN) {
+        errln((UnicodeString)"FAIL: " + message + "; got " +
+              actual + 
+              "; expected " + expected);
+        return FALSE;
+    }
+#ifdef VERBOSE_ASSERTIONS
+    else {
+        logln((UnicodeString)"Ok: " + message + "; got " + actual);
+    }
+#endif
+    return TRUE;
+}
+
+
+UBool IntlTest::assertEquals(const char* message,
+                             UBool expected,
+                             UBool 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;
+}
+
+
+UBool IntlTest::assertEquals(const char* message,
+                             UErrorCode expected,
+                             UErrorCode actual) {
+    if (expected != actual) {
+        errln((UnicodeString)"FAIL: " + message + "; got " +
+              u_errorName(actual) + 
+              "; expected " + u_errorName(expected));
+        return FALSE;
+    }
+#ifdef VERBOSE_ASSERTIONS
+    else {
+        logln((UnicodeString)"Ok: " + message + "; got " + u_errorName(actual));
+    }
+#endif
+    return TRUE;
+}
+
+UBool IntlTest::assertEquals(const char* message,
+                             const UnicodeSet& expected,
+                             const UnicodeSet& actual) {
+    IcuTestErrorCode status(*this, "assertEqualsUniSet");
+    if (expected != actual) {
+        errln((UnicodeString)"FAIL: " + message + "; got " +
+              toString(actual, status) +
+              "; expected " + toString(expected, status));
+        return FALSE;
+    }
+#ifdef VERBOSE_ASSERTIONS
+    else {
+        logln((UnicodeString)"Ok: " + message + "; got " + toString(actual, status));
+    }
+#endif
+    return TRUE;
+}
+
+
+#if !UCONFIG_NO_FORMATTING
+UBool IntlTest::assertEquals(const char* message,
+                             const Formattable& expected,
+                             const Formattable& actual,
+                             UBool possibleDataError) {
+    if (expected != actual) {
+        if (possibleDataError) {
+            dataerrln((UnicodeString)"FAIL: " + message + "; got " +
+                  toString(actual) +
+                  "; expected " + toString(expected));
+        } else {
+            errln((UnicodeString)"FAIL: " + message + "; got " +
+                  toString(actual) +
+                  "; expected " + toString(expected));
+        }
+        return FALSE;
+    }
 #ifdef VERBOSE_ASSERTIONS
     else {
         logln((UnicodeString)"Ok: " + message + "; got " + toString(actual));
@@ -1724,12 +2115,12 @@ static const char* extractToAssertBuf(const UnicodeString& message) {
     return ASSERT_BUF;
 }
 
-UBool IntlTest::assertTrue(const UnicodeString& message, UBool condition, UBool quiet) {
-    return assertTrue(extractToAssertBuf(message), condition, quiet);
+UBool IntlTest::assertTrue(const UnicodeString& message, UBool condition, UBool quiet, UBool possibleDataError) {
+    return assertTrue(extractToAssertBuf(message), condition, quiet, possibleDataError);
 }
 
-UBool IntlTest::assertFalse(const UnicodeString& message, UBool condition, UBool quiet) {
-    return assertFalse(extractToAssertBuf(message), condition, quiet);
+UBool IntlTest::assertFalse(const UnicodeString& message, UBool condition, UBool quiet, UBool possibleDataError) {
+    return assertFalse(extractToAssertBuf(message), condition, quiet, possibleDataError);
 }
 
 UBool IntlTest::assertSuccess(const UnicodeString& message, UErrorCode ec) {
@@ -1738,8 +2129,9 @@ UBool IntlTest::assertSuccess(const UnicodeString& message, UErrorCode ec) {
 
 UBool IntlTest::assertEquals(const UnicodeString& message,
                              const UnicodeString& expected,
-                             const UnicodeString& actual) {
-    return assertEquals(extractToAssertBuf(message), expected, actual);
+                             const UnicodeString& actual,
+                             UBool possibleDataError) {
+    return assertEquals(extractToAssertBuf(message), expected, actual, possibleDataError);
 }
 
 UBool IntlTest::assertEquals(const UnicodeString& message,
@@ -1747,16 +2139,35 @@ UBool IntlTest::assertEquals(const UnicodeString& message,
                              const char* actual) {
     return assertEquals(extractToAssertBuf(message), expected, actual);
 }
-//--------------------------------------------------------------------
-// Time bomb - allows temporary behavior that expires at a given
-//             release
-//--------------------------------------------------------------------
-
-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;
+UBool IntlTest::assertEquals(const UnicodeString& message,
+                             UBool expected,
+                             UBool actual) {
+    return assertEquals(extractToAssertBuf(message), expected, actual);
+}
+UBool IntlTest::assertEquals(const UnicodeString& message,
+                             int32_t expected,
+                             int32_t actual) {
+    return assertEquals(extractToAssertBuf(message), expected, actual);
+}
+UBool IntlTest::assertEquals(const UnicodeString& message,
+                             int64_t expected,
+                             int64_t actual) {
+    return assertEquals(extractToAssertBuf(message), expected, actual);
+}
+UBool IntlTest::assertEquals(const UnicodeString& message,
+                             double expected,
+                             double actual) {
+    return assertEquals(extractToAssertBuf(message), expected, actual);
+}
+UBool IntlTest::assertEquals(const UnicodeString& message,
+                             UErrorCode expected,
+                             UErrorCode actual) {
+    return assertEquals(extractToAssertBuf(message), expected, actual);
+}
+UBool IntlTest::assertEquals(const UnicodeString& message,
+                             const UnicodeSet& expected,
+                             const UnicodeSet& actual) {
+    return assertEquals(extractToAssertBuf(message), expected, actual);
 }
 
 #if !UCONFIG_NO_FORMATTING