Home | History | Annotate | Download | only in intltest
      1 /********************************************************************
      2  * COPYRIGHT:
      3  * Copyright (c) 1999-2011, International Business Machines Corporation and
      4  * others. All Rights Reserved.
      5  ********************************************************************/
      6 
      7 #if defined(hpux)
      8 # ifndef _INCLUDE_POSIX_SOURCE
      9 #  define _INCLUDE_POSIX_SOURCE
     10 # endif
     11 #endif
     12 
     13 #include "simplethread.h"
     14 
     15 #include "unicode/utypes.h"
     16 #include "unicode/ustring.h"
     17 #include "umutex.h"
     18 #include "cmemory.h"
     19 #include "cstring.h"
     20 #include "uparse.h"
     21 #include "unicode/localpointer.h"
     22 #include "unicode/resbund.h"
     23 #include "unicode/udata.h"
     24 #include "unicode/uloc.h"
     25 #include "unicode/locid.h"
     26 #include "putilimp.h"
     27 #if !defined(U_WINDOWS) && !defined(XP_MAC) && !defined(U_RHAPSODY)
     28 #define POSIX 1
     29 #endif
     30 
     31 /* Needed by z/OS to get usleep */
     32 #if defined(OS390)
     33 #define __DOT1 1
     34 #define __UU
     35 #define _XOPEN_SOURCE_EXTENDED 1
     36 #ifndef _XPG4_2
     37 #define _XPG4_2
     38 #endif
     39 #include <unistd.h>
     40 /*#include "platform_xopen_source_extended.h"*/
     41 #endif
     42 #if defined(POSIX) || defined(U_SOLARIS) || defined(U_AIX) || defined(U_HPUX)
     43 
     44 #define HAVE_IMP
     45 
     46 #if (ICU_USE_THREADS == 1)
     47 #include <pthread.h>
     48 #endif
     49 
     50 #if defined(__hpux) && defined(HPUX_CMA)
     51 # if defined(read)  // read being defined as cma_read causes trouble with iostream::read
     52 #  undef read
     53 # endif
     54 #endif
     55 
     56 /* Define __EXTENSIONS__ for Solaris and old friends in strict mode. */
     57 #ifndef __EXTENSIONS__
     58 #define __EXTENSIONS__
     59 #endif
     60 
     61 #if defined(OS390)
     62 #include <sys/types.h>
     63 #endif
     64 
     65 #if !defined(OS390)
     66 #include <signal.h>
     67 #endif
     68 
     69 /* Define _XPG4_2 for Solaris and friends. */
     70 #ifndef _XPG4_2
     71 #define _XPG4_2
     72 #endif
     73 
     74 /* Define __USE_XOPEN_EXTENDED for Linux and glibc. */
     75 #ifndef __USE_XOPEN_EXTENDED
     76 #define __USE_XOPEN_EXTENDED
     77 #endif
     78 
     79 /* Define _INCLUDE_XOPEN_SOURCE_EXTENDED for HP/UX (11?). */
     80 #ifndef _INCLUDE_XOPEN_SOURCE_EXTENDED
     81 #define _INCLUDE_XOPEN_SOURCE_EXTENDED
     82 #endif
     83 
     84 #include <unistd.h>
     85 
     86 #endif
     87 /* HPUX */
     88 #ifdef sleep
     89 #undef sleep
     90 #endif
     91 
     92 
     93 
     94 #include "tsmthred.h"
     95 
     96 #define TSMTHREAD_FAIL(msg) errln("%s at file %s, line %d", msg, __FILE__, __LINE__)
     97 #define TSMTHREAD_ASSERT(expr) {if (!(expr)) {TSMTHREAD_FAIL("Fail");}}
     98 
     99 MultithreadTest::MultithreadTest()
    100 {
    101 }
    102 
    103 MultithreadTest::~MultithreadTest()
    104 {
    105 }
    106 
    107 
    108 
    109 #if (ICU_USE_THREADS==0)
    110 void MultithreadTest::runIndexedTest( int32_t index, UBool exec,
    111                 const char* &name, char* /*par*/ ) {
    112   if (exec) logln("TestSuite MultithreadTest: ");
    113 
    114   if(index == 0)
    115       name = "NO_THREADED_TESTS";
    116   else
    117       name = "";
    118 
    119   if(exec) { logln("MultithreadTest - test DISABLED.  ICU_USE_THREADS set to 0, check your configuration if this is a problem..");
    120   }
    121 }
    122 #else
    123 
    124 #include <stdio.h>
    125 #include <string.h>
    126 #include <ctype.h>    // tolower, toupper
    127 
    128 #include "unicode/putil.h"
    129 
    130 // for mthreadtest
    131 #include "unicode/numfmt.h"
    132 #include "unicode/choicfmt.h"
    133 #include "unicode/msgfmt.h"
    134 #include "unicode/locid.h"
    135 #include "unicode/ucol.h"
    136 #include "unicode/calendar.h"
    137 #include "ucaconf.h"
    138 
    139 void SimpleThread::errorFunc() {
    140     // *(char *)0 = 3;            // Force entry into a debugger via a crash;
    141 }
    142 
    143 void MultithreadTest::runIndexedTest( int32_t index, UBool exec,
    144                 const char* &name, char* /*par*/ ) {
    145     if (exec)
    146         logln("TestSuite MultithreadTest: ");
    147     switch (index) {
    148     case 0:
    149         name = "TestThreads";
    150         if (exec)
    151             TestThreads();
    152         break;
    153 
    154     case 1:
    155         name = "TestMutex";
    156         if (exec)
    157             TestMutex();
    158         break;
    159 
    160     case 2:
    161         name = "TestThreadedIntl";
    162 #if !UCONFIG_NO_FORMATTING
    163         if (exec) {
    164             TestThreadedIntl();
    165         }
    166 #endif
    167         break;
    168 
    169     case 3:
    170       name = "TestCollators";
    171 #if !UCONFIG_NO_COLLATION
    172       if (exec) {
    173             TestCollators();
    174       }
    175 #endif /* #if !UCONFIG_NO_COLLATION */
    176       break;
    177 
    178     case 4:
    179         name = "TestString";
    180         if (exec) {
    181             TestString();
    182         }
    183         break;
    184 
    185     default:
    186         name = "";
    187         break; //needed to end loop
    188     }
    189 }
    190 
    191 
    192 //-----------------------------------------------------------------------------------
    193 //
    194 //   TestThreads -- see if threads really work at all.
    195 //
    196 //   Set up N threads pointing at N chars. When they are started, they will
    197 //   each sleep 1 second and then set their chars. At the end we make sure they
    198 //   are all set.
    199 //
    200 //-----------------------------------------------------------------------------------
    201 #define THREADTEST_NRTHREADS 8
    202 
    203 class TestThreadsThread : public SimpleThread
    204 {
    205 public:
    206     TestThreadsThread(char* whatToChange) { fWhatToChange = whatToChange; }
    207     virtual void run() { SimpleThread::sleep(1000);
    208                          Mutex m;
    209                          *fWhatToChange = '*';
    210     }
    211 private:
    212     char *fWhatToChange;
    213 };
    214 
    215 void MultithreadTest::TestThreads()
    216 {
    217     char threadTestChars[THREADTEST_NRTHREADS + 1];
    218     SimpleThread *threads[THREADTEST_NRTHREADS];
    219     int32_t numThreadsStarted = 0;
    220 
    221     int32_t i;
    222     for(i=0;i<THREADTEST_NRTHREADS;i++)
    223     {
    224         threadTestChars[i] = ' ';
    225         threads[i] = new TestThreadsThread(&threadTestChars[i]);
    226     }
    227     threadTestChars[THREADTEST_NRTHREADS] = '\0';
    228 
    229     logln("->" + UnicodeString(threadTestChars) + "<- Firing off threads.. ");
    230     for(i=0;i<THREADTEST_NRTHREADS;i++)
    231     {
    232         if (threads[i]->start() != 0) {
    233             errln("Error starting thread %d", i);
    234         }
    235         else {
    236             numThreadsStarted++;
    237         }
    238         SimpleThread::sleep(100);
    239         logln(" Subthread started.");
    240     }
    241 
    242     logln("Waiting for threads to be set..");
    243     if (numThreadsStarted == 0) {
    244         errln("No threads could be started for testing!");
    245         return;
    246     }
    247 
    248     int32_t patience = 40; // seconds to wait
    249 
    250     while(patience--)
    251     {
    252         int32_t count = 0;
    253         umtx_lock(NULL);
    254         for(i=0;i<THREADTEST_NRTHREADS;i++)
    255         {
    256             if(threadTestChars[i] == '*')
    257             {
    258                 count++;
    259             }
    260         }
    261         umtx_unlock(NULL);
    262 
    263         if(count == THREADTEST_NRTHREADS)
    264         {
    265             logln("->" + UnicodeString(threadTestChars) + "<- Got all threads! cya");
    266             for(i=0;i<THREADTEST_NRTHREADS;i++)
    267             {
    268                 delete threads[i];
    269             }
    270             return;
    271         }
    272 
    273         logln("->" + UnicodeString(threadTestChars) + "<- Waiting..");
    274         SimpleThread::sleep(500);
    275     }
    276 
    277     errln("->" + UnicodeString(threadTestChars) + "<- PATIENCE EXCEEDED!! Still missing some.");
    278     for(i=0;i<THREADTEST_NRTHREADS;i++)
    279     {
    280         delete threads[i];
    281     }
    282 }
    283 
    284 
    285 //-----------------------------------------------------------------------
    286 //
    287 //  TestMutex  - a simple (non-stress) test to verify that ICU mutexes
    288 //               are actually mutexing.  Does not test the use of
    289 //               mutexes within ICU services, but rather that the
    290 //               platform's mutex support is at least superficially there.
    291 //
    292 //----------------------------------------------------------------------
    293 static UMTX    gTestMutexA = NULL;
    294 static UMTX    gTestMutexB = NULL;
    295 
    296 static int     gThreadsStarted = 0;
    297 static int     gThreadsInMiddle = 0;
    298 static int     gThreadsDone = 0;
    299 
    300 static const int TESTMUTEX_THREAD_COUNT = 4;
    301 
    302 static int safeIncr(int &var, int amt) {
    303     // Thread safe (using global mutex) increment of a variable.
    304     // Return the updated value.
    305     // Can also be used as a safe load of a variable by incrementing it by 0.
    306     Mutex m;
    307     var += amt;
    308     return var;
    309 }
    310 
    311 class TestMutexThread : public SimpleThread
    312 {
    313 public:
    314     virtual void run()
    315     {
    316         // This is the code that each of the spawned threads runs.
    317         // All of the spawned threads bunch up together at each of the two mutexes
    318         // because the main holds the mutexes until they do.
    319         //
    320         safeIncr(gThreadsStarted, 1);
    321         umtx_lock(&gTestMutexA);
    322         umtx_unlock(&gTestMutexA);
    323         safeIncr(gThreadsInMiddle, 1);
    324         umtx_lock(&gTestMutexB);
    325         umtx_unlock(&gTestMutexB);
    326         safeIncr(gThreadsDone, 1);
    327     }
    328 };
    329 
    330 void MultithreadTest::TestMutex()
    331 {
    332     // Start up the test threads.  They should all pile up waiting on
    333     // gTestMutexA, which we (the main thread) hold until the test threads
    334     //   all get there.
    335     gThreadsStarted = 0;
    336     gThreadsInMiddle = 0;
    337     gThreadsDone = 0;
    338     umtx_lock(&gTestMutexA);
    339     TestMutexThread  *threads[TESTMUTEX_THREAD_COUNT];
    340     int i;
    341     int32_t numThreadsStarted = 0;
    342     for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
    343         threads[i] = new TestMutexThread;
    344         if (threads[i]->start() != 0) {
    345             errln("Error starting thread %d", i);
    346         }
    347         else {
    348             numThreadsStarted++;
    349         }
    350     }
    351     if (numThreadsStarted == 0) {
    352         errln("No threads could be started for testing!");
    353         return;
    354     }
    355 
    356     int patience = 0;
    357     while (safeIncr(gThreadsStarted, 0) != TESTMUTEX_THREAD_COUNT) {
    358         if (patience++ > 24) {
    359             TSMTHREAD_FAIL("Patience Exceeded");
    360             return;
    361         }
    362         SimpleThread::sleep(500);
    363     }
    364     // None of the test threads should have advanced past the first mutex.
    365     TSMTHREAD_ASSERT(gThreadsInMiddle==0);
    366     TSMTHREAD_ASSERT(gThreadsDone==0);
    367 
    368     //  All of the test threads have made it to the first mutex.
    369     //  We (the main thread) now let them advance to the second mutex,
    370     //   where they should all pile up again.
    371     umtx_lock(&gTestMutexB);
    372     umtx_unlock(&gTestMutexA);
    373 
    374     patience = 0;
    375     while (safeIncr(gThreadsInMiddle, 0) != TESTMUTEX_THREAD_COUNT) {
    376         if (patience++ > 24) {
    377             TSMTHREAD_FAIL("Patience Exceeded");
    378             return;
    379         }
    380         SimpleThread::sleep(500);
    381     }
    382     TSMTHREAD_ASSERT(gThreadsDone==0);
    383 
    384     //  All test threads made it to the second mutex.
    385     //   Now let them proceed from there.  They will all terminate.
    386     umtx_unlock(&gTestMutexB);
    387     patience = 0;
    388     while (safeIncr(gThreadsDone, 0) != TESTMUTEX_THREAD_COUNT) {
    389         if (patience++ > 24) {
    390             TSMTHREAD_FAIL("Patience Exceeded");
    391             return;
    392         }
    393         SimpleThread::sleep(500);
    394     }
    395 
    396     // All threads made it by both mutexes.
    397     // Destroy the test mutexes.
    398     umtx_destroy(&gTestMutexA);
    399     umtx_destroy(&gTestMutexB);
    400     gTestMutexA=NULL;
    401     gTestMutexB=NULL;
    402 
    403     for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
    404         delete threads[i];
    405     }
    406 
    407 }
    408 
    409 
    410 //-------------------------------------------------------------------------------------------
    411 //
    412 // class ThreadWithStatus - a thread that we can check the status and error condition of
    413 //
    414 //-------------------------------------------------------------------------------------------
    415 class ThreadWithStatus : public SimpleThread
    416 {
    417 public:
    418     UBool  getError() { return (fErrors > 0); }
    419     UBool  getError(UnicodeString& fillinError) { fillinError = fErrorString; return (fErrors > 0); }
    420     virtual ~ThreadWithStatus(){}
    421 protected:
    422     ThreadWithStatus() :  fErrors(0) {}
    423     void error(const UnicodeString &error) {
    424         fErrors++; fErrorString = error;
    425         SimpleThread::errorFunc();
    426     }
    427     void error() { error("An error occured."); }
    428 private:
    429     int32_t fErrors;
    430     UnicodeString fErrorString;
    431 };
    432 
    433 
    434 
    435 //-------------------------------------------------------------------------------------------
    436 //
    437 //   TestMultithreadedIntl.  Test ICU Formatting n a multi-threaded environment
    438 //
    439 //-------------------------------------------------------------------------------------------
    440 
    441 
    442 // * Show exactly where the string's differences lie.
    443 UnicodeString showDifference(const UnicodeString& expected, const UnicodeString& result)
    444 {
    445     UnicodeString res;
    446     res = expected + "<Expected\n";
    447     if(expected.length() != result.length())
    448         res += " [ Different lengths ] \n";
    449     else
    450     {
    451         for(int32_t i=0;i<expected.length();i++)
    452         {
    453             if(expected[i] == result[i])
    454             {
    455                 res += " ";
    456             }
    457             else
    458             {
    459                 res += "|";
    460             }
    461         }
    462         res += "<Differences";
    463         res += "\n";
    464     }
    465     res += result + "<Result\n";
    466 
    467     return res;
    468 }
    469 
    470 
    471 
    472 
    473 //-------------------------------------------------------------------------------------------
    474 //
    475 //   FormatThreadTest - a thread that tests performing a number of numberformats.
    476 //
    477 //-------------------------------------------------------------------------------------------
    478 
    479 const int kFormatThreadIterations = 20;  // # of iterations per thread
    480 const int kFormatThreadThreads    = 10;  // # of threads to spawn
    481 const int kFormatThreadPatience   = 60;  // time in seconds to wait for all threads
    482 
    483 #if !UCONFIG_NO_FORMATTING
    484 
    485 
    486 
    487 struct FormatThreadTestData
    488 {
    489     double number;
    490     UnicodeString string;
    491     FormatThreadTestData(double a, const UnicodeString& b) : number(a),string(b) {}
    492 } ;
    493 
    494 
    495 // "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
    496 
    497 void formatErrorMessage(UErrorCode &realStatus, const UnicodeString& pattern, const Locale& theLocale,
    498                      UErrorCode inStatus0, /* statusString 1 */ const Locale &inCountry2, double currency3, // these numbers are the message arguments.
    499                      UnicodeString &result)
    500 {
    501     if(U_FAILURE(realStatus))
    502         return; // you messed up
    503 
    504     UnicodeString errString1(u_errorName(inStatus0));
    505 
    506     UnicodeString countryName2;
    507     inCountry2.getDisplayCountry(theLocale,countryName2);
    508 
    509     Formattable myArgs[] = {
    510         Formattable((int32_t)inStatus0),   // inStatus0      {0}
    511         Formattable(errString1), // statusString1 {1}
    512         Formattable(countryName2),  // inCountry2 {2}
    513         Formattable(currency3)// currency3  {3,number,currency}
    514     };
    515 
    516     MessageFormat *fmt = new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus);
    517     fmt->setLocale(theLocale);
    518     fmt->applyPattern(pattern, realStatus);
    519 
    520     if (U_FAILURE(realStatus)) {
    521         delete fmt;
    522         return;
    523     }
    524 
    525     FieldPosition ignore = 0;
    526     fmt->format(myArgs,4,result,ignore,realStatus);
    527 
    528     delete fmt;
    529 }
    530 
    531 
    532 UBool U_CALLCONV isAcceptable(void *, const char *, const char *, const UDataInfo *) {
    533     return TRUE;
    534 }
    535 
    536 //static UMTX debugMutex = NULL;
    537 //static UMTX gDebugMutex;
    538 
    539 
    540 class FormatThreadTest : public ThreadWithStatus
    541 {
    542 public:
    543     int     fNum;
    544     int     fTraceInfo;
    545 
    546     FormatThreadTest() // constructor is NOT multithread safe.
    547         : ThreadWithStatus(),
    548         fNum(0),
    549         fTraceInfo(0),
    550         fOffset(0)
    551         // the locale to use
    552     {
    553         static int32_t fgOffset = 0;
    554         fgOffset += 3;
    555         fOffset = fgOffset;
    556     }
    557 
    558 
    559     virtual void run()
    560     {
    561         fTraceInfo                     = 1;
    562         LocalPointer<NumberFormat> percentFormatter;
    563         UErrorCode status = U_ZERO_ERROR;
    564 
    565 #if 0
    566         // debugging code,
    567         for (int i=0; i<4000; i++) {
    568             status = U_ZERO_ERROR;
    569             UDataMemory *data1 = udata_openChoice(0, "res", "en_US", isAcceptable, 0, &status);
    570             UDataMemory *data2 = udata_openChoice(0, "res", "fr", isAcceptable, 0, &status);
    571             udata_close(data1);
    572             udata_close(data2);
    573             if (U_FAILURE(status)) {
    574                 error("udata_openChoice failed.\n");
    575                 break;
    576             }
    577         }
    578         return;
    579 #endif
    580 
    581 #if 0
    582         // debugging code,
    583         int m;
    584         for (m=0; m<4000; m++) {
    585             status         = U_ZERO_ERROR;
    586             UResourceBundle *res   = NULL;
    587             const char *localeName = NULL;
    588 
    589             Locale  loc = Locale::getEnglish();
    590 
    591             localeName = loc.getName();
    592             // localeName = "en";
    593 
    594             // ResourceBundle bund = ResourceBundle(0, loc, status);
    595             //umtx_lock(&gDebugMutex);
    596             res = ures_open(NULL, localeName, &status);
    597             //umtx_unlock(&gDebugMutex);
    598 
    599             //umtx_lock(&gDebugMutex);
    600             ures_close(res);
    601             //umtx_unlock(&gDebugMutex);
    602 
    603             if (U_FAILURE(status)) {
    604                 error("Resource bundle construction failed.\n");
    605                 break;
    606             }
    607         }
    608         return;
    609 #endif
    610 
    611         // Keep this data here to avoid static initialization.
    612         FormatThreadTestData kNumberFormatTestData[] =
    613         {
    614             FormatThreadTestData((double)5.0, UnicodeString("5", "")),
    615                 FormatThreadTestData( 6.0, UnicodeString("6", "")),
    616                 FormatThreadTestData( 20.0, UnicodeString("20", "")),
    617                 FormatThreadTestData( 8.0, UnicodeString("8", "")),
    618                 FormatThreadTestData( 8.3, UnicodeString("8.3", "")),
    619                 FormatThreadTestData( 12345, UnicodeString("12,345", "")),
    620                 FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")),
    621         };
    622         int32_t kNumberFormatTestDataLength = (int32_t)(sizeof(kNumberFormatTestData) /
    623                                                         sizeof(kNumberFormatTestData[0]));
    624 
    625         // Keep this data here to avoid static initialization.
    626         FormatThreadTestData kPercentFormatTestData[] =
    627         {
    628             FormatThreadTestData((double)5.0, CharsToUnicodeString("500\\u00a0%")),
    629                 FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")),
    630                 FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")),
    631                 FormatThreadTestData(
    632                    16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP
    633                 FormatThreadTestData(
    634                     81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")),
    635         };
    636         int32_t kPercentFormatTestDataLength =
    637                 (int32_t)(sizeof(kPercentFormatTestData) / sizeof(kPercentFormatTestData[0]));
    638         int32_t iteration;
    639 
    640         status = U_ZERO_ERROR;
    641         LocalPointer<NumberFormat> formatter(NumberFormat::createInstance(Locale::getEnglish(),status));
    642         if(U_FAILURE(status)) {
    643             error("Error on NumberFormat::createInstance().");
    644             goto cleanupAndReturn;
    645         }
    646 
    647         percentFormatter.adoptInstead(NumberFormat::createPercentInstance(Locale::getFrench(),status));
    648         if(U_FAILURE(status))             {
    649             error("Error on NumberFormat::createPercentInstance().");
    650             goto cleanupAndReturn;
    651         }
    652 
    653         for(iteration = 0;!getError() && iteration<kFormatThreadIterations;iteration++)
    654         {
    655 
    656             int32_t whichLine = (iteration + fOffset)%kNumberFormatTestDataLength;
    657 
    658             UnicodeString  output;
    659 
    660             formatter->format(kNumberFormatTestData[whichLine].number, output);
    661 
    662             if(0 != output.compare(kNumberFormatTestData[whichLine].string)) {
    663                 error("format().. expected " + kNumberFormatTestData[whichLine].string
    664                         + " got " + output);
    665                 goto cleanupAndReturn;
    666             }
    667 
    668             // Now check percent.
    669             output.remove();
    670             whichLine = (iteration + fOffset)%kPercentFormatTestDataLength;
    671 
    672             percentFormatter->format(kPercentFormatTestData[whichLine].number, output);
    673             if(0 != output.compare(kPercentFormatTestData[whichLine].string))
    674             {
    675                 error("percent format().. \n" +
    676                         showDifference(kPercentFormatTestData[whichLine].string,output));
    677                 goto cleanupAndReturn;
    678             }
    679 
    680             // Test message error
    681             const int       kNumberOfMessageTests = 3;
    682             UErrorCode      statusToCheck;
    683             UnicodeString   patternToCheck;
    684             Locale          messageLocale;
    685             Locale          countryToCheck;
    686             double          currencyToCheck;
    687 
    688             UnicodeString   expected;
    689 
    690             // load the cases.
    691             switch((iteration+fOffset) % kNumberOfMessageTests)
    692             {
    693             default:
    694             case 0:
    695                 statusToCheck=                      U_FILE_ACCESS_ERROR;
    696                 patternToCheck=        "0:Someone from {2} is receiving a #{0}"
    697                                        " error - {1}. Their telephone call is costing "
    698                                        "{3,number,currency}."; // number,currency
    699                 messageLocale=                      Locale("en","US");
    700                 countryToCheck=                     Locale("","HR");
    701                 currencyToCheck=                    8192.77;
    702                 expected=  "0:Someone from Croatia is receiving a #4 error - "
    703                             "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77.";
    704                 break;
    705             case 1:
    706                 statusToCheck=                      U_INDEX_OUTOFBOUNDS_ERROR;
    707                 patternToCheck=                     "1:A customer in {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}."; // number,currency
    708                 messageLocale=                      Locale("de","DE@currency=DEM");
    709                 countryToCheck=                     Locale("","BF");
    710                 currencyToCheck=                    2.32;
    711                 expected=                           CharsToUnicodeString(
    712                                                     "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing 2,32\\u00A0DEM.");
    713                 break;
    714             case 2:
    715                 statusToCheck=                      U_MEMORY_ALLOCATION_ERROR;
    716                 patternToCheck=   "2:user in {2} is receiving a #{0} error - {1}. "
    717                                   "They insist they just spent {3,number,currency} "
    718                                   "on memory."; // number,currency
    719                 messageLocale=                      Locale("de","AT@currency=ATS"); // Austrian German
    720                 countryToCheck=                     Locale("","US"); // hmm
    721                 currencyToCheck=                    40193.12;
    722                 expected=       CharsToUnicodeString(
    723                             "2:user in Vereinigte Staaten is receiving a #7 error"
    724                             " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent"
    725                             " \\u00f6S\\u00A040.193,12 on memory.");
    726                 break;
    727             }
    728 
    729             UnicodeString result;
    730             UErrorCode status = U_ZERO_ERROR;
    731             formatErrorMessage(status,patternToCheck,messageLocale,statusToCheck,
    732                                 countryToCheck,currencyToCheck,result);
    733             if(U_FAILURE(status))
    734             {
    735                 UnicodeString tmp(u_errorName(status));
    736                 error("Failure on message format, pattern=" + patternToCheck +
    737                         ", error = " + tmp);
    738                 goto cleanupAndReturn;
    739             }
    740 
    741             if(result != expected)
    742             {
    743                 error("PatternFormat: \n" + showDifference(expected,result));
    744                 goto cleanupAndReturn;
    745             }
    746         }   /*  end of for loop */
    747 
    748 cleanupAndReturn:
    749         //  while (fNum == 4) {SimpleThread::sleep(10000);}   // Force a failure by preventing thread from finishing
    750         fTraceInfo = 2;
    751     }
    752 
    753 private:
    754     int32_t fOffset; // where we are testing from.
    755 };
    756 
    757 // ** The actual test function.
    758 
    759 void MultithreadTest::TestThreadedIntl()
    760 {
    761     int i;
    762     UnicodeString theErr;
    763     UBool   haveDisplayedInfo[kFormatThreadThreads];
    764     static const int32_t PATIENCE_SECONDS = 45;
    765 
    766     //
    767     //  Create and start the test threads
    768     //
    769     logln("Spawning: %d threads * %d iterations each.",
    770                 kFormatThreadThreads, kFormatThreadIterations);
    771     LocalArray<FormatThreadTest> tests(new FormatThreadTest[kFormatThreadThreads]);
    772     for(int32_t j = 0; j < kFormatThreadThreads; j++) {
    773         tests[j].fNum = j;
    774         int32_t threadStatus = tests[j].start();
    775         if (threadStatus != 0) {
    776             errln("System Error %d starting thread number %d.", threadStatus, j);
    777             SimpleThread::errorFunc();
    778             return;
    779         }
    780         haveDisplayedInfo[j] = FALSE;
    781     }
    782 
    783 
    784     // Spin, waiting for the test threads to finish.
    785     UBool   stillRunning;
    786     UDate startTime, endTime;
    787     startTime = Calendar::getNow();
    788     do {
    789         /*  Spin until the test threads  complete. */
    790         stillRunning = FALSE;
    791         endTime = Calendar::getNow();
    792         if (((int32_t)(endTime - startTime)/U_MILLIS_PER_SECOND) > PATIENCE_SECONDS) {
    793             errln("Patience exceeded. Test is taking too long.");
    794             return;
    795         }
    796         /*
    797          The following sleep must be here because the *BSD operating systems
    798          have a brain dead thread scheduler. They starve the child threads from
    799          CPU time.
    800         */
    801         SimpleThread::sleep(1); // yield
    802         for(i=0;i<kFormatThreadThreads;i++) {
    803             if (tests[i].isRunning()) {
    804                 stillRunning = TRUE;
    805             } else if (haveDisplayedInfo[i] == FALSE) {
    806                 logln("Thread # %d is complete..", i);
    807                 if(tests[i].getError(theErr)) {
    808                     dataerrln(UnicodeString("#") + i + ": " + theErr);
    809                     SimpleThread::errorFunc();
    810                 }
    811                 haveDisplayedInfo[i] = TRUE;
    812             }
    813         }
    814     } while (stillRunning);
    815 
    816     //
    817     //  All threads have finished.
    818     //
    819 }
    820 #endif /* #if !UCONFIG_NO_FORMATTING */
    821 
    822 
    823 
    824 
    825 
    826 //-------------------------------------------------------------------------------------------
    827 //
    828 // Collation threading test
    829 //
    830 //-------------------------------------------------------------------------------------------
    831 #if !UCONFIG_NO_COLLATION
    832 
    833 #define kCollatorThreadThreads   10  // # of threads to spawn
    834 #define kCollatorThreadPatience kCollatorThreadThreads*30
    835 
    836 struct Line {
    837     UChar buff[25];
    838     int32_t buflen;
    839 } ;
    840 
    841 class CollatorThreadTest : public ThreadWithStatus
    842 {
    843 private:
    844     const UCollator *coll;
    845     const Line *lines;
    846     int32_t noLines;
    847 public:
    848     CollatorThreadTest()  : ThreadWithStatus(),
    849         coll(NULL),
    850         lines(NULL),
    851         noLines(0)
    852     {
    853     };
    854     void setCollator(UCollator *c, Line *l, int32_t nl)
    855     {
    856         coll = c;
    857         lines = l;
    858         noLines = nl;
    859     }
    860     virtual void run() {
    861         //sleep(10000);
    862         int32_t line = 0;
    863 
    864         uint8_t sk1[1024], sk2[1024];
    865         uint8_t *oldSk = NULL, *newSk = sk1;
    866         int32_t resLen = 0, oldLen = 0;
    867         int32_t i = 0;
    868 
    869         for(i = 0; i < noLines; i++) {
    870             resLen = ucol_getSortKey(coll, lines[i].buff, lines[i].buflen, newSk, 1024);
    871 
    872             int32_t res = 0, cmpres = 0, cmpres2 = 0;
    873 
    874             if(oldSk != NULL) {
    875                 res = strcmp((char *)oldSk, (char *)newSk);
    876                 cmpres = ucol_strcoll(coll, lines[i-1].buff, lines[i-1].buflen, lines[i].buff, lines[i].buflen);
    877                 cmpres2 = ucol_strcoll(coll, lines[i].buff, lines[i].buflen, lines[i-1].buff, lines[i-1].buflen);
    878                 //cmpres = res;
    879                 //cmpres2 = -cmpres;
    880 
    881                 if(cmpres != -cmpres2) {
    882                     error("Compare result not symmetrical on line "+ line);
    883                     break;
    884                 }
    885 
    886                 if(((res&0x80000000) != (cmpres&0x80000000)) || (res == 0 && cmpres != 0) || (res != 0 && cmpres == 0)) {
    887                     error(UnicodeString("Difference between ucol_strcoll and sortkey compare on line ")+ UnicodeString(line));
    888                     break;
    889                 }
    890 
    891                 if(res > 0) {
    892                     error(UnicodeString("Line %i is not greater or equal than previous line ")+ UnicodeString(i));
    893                     break;
    894                 } else if(res == 0) { /* equal */
    895                     res = u_strcmpCodePointOrder(lines[i-1].buff, lines[i].buff);
    896                     if (res == 0) {
    897                         error(UnicodeString("Probable error in test file on line %i (comparing identical strings)")+ UnicodeString(i));
    898                         break;
    899                     }
    900                     /*
    901                      * UCA 6.0 test files can have lines that compare == if they are
    902                      * different strings but canonically equivalent.
    903                     else if (res > 0) {
    904                         error(UnicodeString("Sortkeys are identical, but code point compare gives >0 on line ")+ UnicodeString(i));
    905                         break;
    906                     }
    907                      */
    908                 }
    909             }
    910 
    911             oldSk = newSk;
    912             oldLen = resLen;
    913 
    914             newSk = (newSk == sk1)?sk2:sk1;
    915         }
    916     }
    917 };
    918 
    919 void MultithreadTest::TestCollators()
    920 {
    921 
    922     UErrorCode status = U_ZERO_ERROR;
    923     FILE *testFile = NULL;
    924     char testDataPath[1024];
    925     strcpy(testDataPath, IntlTest::getSourceTestData(status));
    926     if (U_FAILURE(status)) {
    927         errln("ERROR: could not open test data %s", u_errorName(status));
    928         return;
    929     }
    930     strcat(testDataPath, "CollationTest_");
    931 
    932     const char* type = "NON_IGNORABLE";
    933 
    934     const char *ext = ".txt";
    935     if(testFile) {
    936         fclose(testFile);
    937     }
    938     char buffer[1024];
    939     strcpy(buffer, testDataPath);
    940     strcat(buffer, type);
    941     size_t bufLen = strlen(buffer);
    942 
    943     // we try to open 3 files:
    944     // path/CollationTest_type.txt
    945     // path/CollationTest_type_SHORT.txt
    946     // path/CollationTest_type_STUB.txt
    947     // we are going to test with the first one that we manage to open.
    948 
    949     strcpy(buffer+bufLen, ext);
    950 
    951     testFile = fopen(buffer, "rb");
    952 
    953     if(testFile == 0) {
    954         strcpy(buffer+bufLen, "_SHORT");
    955         strcat(buffer, ext);
    956         testFile = fopen(buffer, "rb");
    957 
    958         if(testFile == 0) {
    959             strcpy(buffer+bufLen, "_STUB");
    960             strcat(buffer, ext);
    961             testFile = fopen(buffer, "rb");
    962 
    963             if (testFile == 0) {
    964                 *(buffer+bufLen) = 0;
    965                 dataerrln("could not open any of the conformance test files, tried opening base %s", buffer);
    966                 return;
    967             } else {
    968                 infoln(
    969                     "INFO: Working with the stub file.\n"
    970                     "If you need the full conformance test, please\n"
    971                     "download the appropriate data files from:\n"
    972                     "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/");
    973             }
    974         }
    975     }
    976 
    977     Line *lines = new Line[200000];
    978     memset(lines, 0, sizeof(Line)*200000);
    979     int32_t lineNum = 0;
    980 
    981     UChar bufferU[1024];
    982     int32_t buflen = 0;
    983     uint32_t first = 0;
    984     uint32_t offset = 0;
    985 
    986     while (fgets(buffer, 1024, testFile) != NULL) {
    987         offset = 0;
    988         if(*buffer == 0 || strlen(buffer) < 3 || buffer[0] == '#') {
    989             continue;
    990         }
    991         offset = u_parseString(buffer, bufferU, 1024, &first, &status);
    992         buflen = offset;
    993         bufferU[offset++] = 0;
    994         lines[lineNum].buflen = buflen;
    995         //lines[lineNum].buff = new UChar[buflen+1];
    996         u_memcpy(lines[lineNum].buff, bufferU, buflen);
    997         lineNum++;
    998     }
    999     fclose(testFile);
   1000     if(U_FAILURE(status)) {
   1001       dataerrln("Couldn't read the test file!");
   1002       return;
   1003     }
   1004 
   1005     UCollator *coll = ucol_open("root", &status);
   1006     if(U_FAILURE(status)) {
   1007         errcheckln(status, "Couldn't open UCA collator");
   1008         return;
   1009     }
   1010     ucol_setAttribute(coll, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
   1011     ucol_setAttribute(coll, UCOL_CASE_FIRST, UCOL_OFF, &status);
   1012     ucol_setAttribute(coll, UCOL_CASE_LEVEL, UCOL_OFF, &status);
   1013     ucol_setAttribute(coll, UCOL_STRENGTH, UCOL_TERTIARY, &status);
   1014     ucol_setAttribute(coll, UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE, &status);
   1015 
   1016     int32_t noSpawned = 0;
   1017     int32_t spawnResult = 0;
   1018     LocalArray<CollatorThreadTest> tests(new CollatorThreadTest[kCollatorThreadThreads]);
   1019 
   1020     logln(UnicodeString("Spawning: ") + kCollatorThreadThreads + " threads * " + kFormatThreadIterations + " iterations each.");
   1021     int32_t j = 0;
   1022     for(j = 0; j < kCollatorThreadThreads; j++) {
   1023         //logln("Setting collator %i", j);
   1024         tests[j].setCollator(coll, lines, lineNum);
   1025     }
   1026     for(j = 0; j < kCollatorThreadThreads; j++) {
   1027         log("%i ", j);
   1028         spawnResult = tests[j].start();
   1029         if(spawnResult != 0) {
   1030             infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned);
   1031             break;
   1032         }
   1033         noSpawned++;
   1034     }
   1035     logln("Spawned all");
   1036     if (noSpawned == 0) {
   1037         errln("No threads could be spawned.");
   1038         return;
   1039     }
   1040 
   1041     for(int32_t patience = kCollatorThreadPatience;patience > 0; patience --)
   1042     {
   1043         logln("Waiting...");
   1044 
   1045         int32_t i;
   1046         int32_t terrs = 0;
   1047         int32_t completed =0;
   1048 
   1049         for(i=0;i<kCollatorThreadThreads;i++)
   1050         {
   1051             if (tests[i].isRunning() == FALSE)
   1052             {
   1053                 completed++;
   1054 
   1055                 //logln(UnicodeString("Test #") + i + " is complete.. ");
   1056 
   1057                 UnicodeString theErr;
   1058                 if(tests[i].getError(theErr))
   1059                 {
   1060                     terrs++;
   1061                     errln(UnicodeString("#") + i + ": " + theErr);
   1062                 }
   1063                 // print out the error, too, if any.
   1064             }
   1065         }
   1066         logln("Completed %i tests", completed);
   1067 
   1068         if(completed == noSpawned)
   1069         {
   1070             logln("Done! All %i tests are finished", noSpawned);
   1071 
   1072             if(terrs)
   1073             {
   1074                 errln("There were errors.");
   1075                 SimpleThread::errorFunc();
   1076             }
   1077             ucol_close(coll);
   1078             //for(i = 0; i < lineNum; i++) {
   1079             //delete[] lines[i].buff;
   1080             //}
   1081             delete[] lines;
   1082 
   1083             return;
   1084         }
   1085 
   1086         SimpleThread::sleep(900);
   1087     }
   1088     errln("patience exceeded. ");
   1089     SimpleThread::errorFunc();
   1090     ucol_close(coll);
   1091 }
   1092 
   1093 #endif /* #if !UCONFIG_NO_COLLATION */
   1094 
   1095 
   1096 
   1097 
   1098 //-------------------------------------------------------------------------------------------
   1099 //
   1100 //   StringThreadTest2
   1101 //
   1102 //-------------------------------------------------------------------------------------------
   1103 
   1104 const int kStringThreadIterations = 2500;// # of iterations per thread
   1105 const int kStringThreadThreads    = 10;  // # of threads to spawn
   1106 const int kStringThreadPatience   = 120; // time in seconds to wait for all threads
   1107 
   1108 
   1109 class StringThreadTest2 : public ThreadWithStatus
   1110 {
   1111 public:
   1112     int                 fNum;
   1113     int                 fTraceInfo;
   1114     const UnicodeString *fSharedString;
   1115 
   1116     StringThreadTest2(const UnicodeString *sharedString, int num) // constructor is NOT multithread safe.
   1117         : ThreadWithStatus(),
   1118         fNum(num),
   1119         fTraceInfo(0),
   1120         fSharedString(sharedString)
   1121     {
   1122     };
   1123 
   1124 
   1125     virtual void run()
   1126     {
   1127         fTraceInfo    = 1;
   1128         int loopCount = 0;
   1129 
   1130         for (loopCount = 0; loopCount < kStringThreadIterations; loopCount++) {
   1131             if (*fSharedString != "This is the original test string.") {
   1132                 error("Original string is corrupt.");
   1133                 break;
   1134             }
   1135             UnicodeString s1 = *fSharedString;
   1136             s1 += "cat this";
   1137             UnicodeString s2(s1);
   1138             UnicodeString s3 = *fSharedString;
   1139             s2 = s3;
   1140             s3.truncate(12);
   1141             s2.truncate(0);
   1142         }
   1143 
   1144         //  while (fNum == 4) {SimpleThread::sleep(10000);}   // Force a failure by preventing thread from finishing
   1145         fTraceInfo = 2;
   1146     }
   1147 
   1148 };
   1149 
   1150 // ** The actual test function.
   1151 
   1152 void MultithreadTest::TestString()
   1153 {
   1154     int     patience;
   1155     int     terrs = 0;
   1156     int     j;
   1157 
   1158     UnicodeString *testString = new UnicodeString("This is the original test string.");
   1159 
   1160     // Not using LocalArray<StringThreadTest2> tests[kStringThreadThreads];
   1161     // because we don't always want to delete them.
   1162     // See the comments below the cleanupAndReturn label.
   1163     StringThreadTest2  *tests[kStringThreadThreads];
   1164     for(j = 0; j < kStringThreadThreads; j++) {
   1165         tests[j] = new StringThreadTest2(testString, j);
   1166     }
   1167 
   1168     logln(UnicodeString("Spawning: ") + kStringThreadThreads + " threads * " + kStringThreadIterations + " iterations each.");
   1169     for(j = 0; j < kStringThreadThreads; j++) {
   1170         int32_t threadStatus = tests[j]->start();
   1171         if (threadStatus != 0) {
   1172             errln("System Error %d starting thread number %d.", threadStatus, j);
   1173             SimpleThread::errorFunc();
   1174             goto cleanupAndReturn;
   1175         }
   1176     }
   1177 
   1178     for(patience = kStringThreadPatience;patience > 0; patience --)
   1179     {
   1180         logln("Waiting...");
   1181 
   1182         int32_t i;
   1183         terrs = 0;
   1184         int32_t completed =0;
   1185 
   1186         for(i=0;i<kStringThreadThreads;i++) {
   1187             if (tests[i]->isRunning() == FALSE)
   1188             {
   1189                 completed++;
   1190 
   1191                 logln(UnicodeString("Test #") + i + " is complete.. ");
   1192 
   1193                 UnicodeString theErr;
   1194                 if(tests[i]->getError(theErr))
   1195                 {
   1196                     terrs++;
   1197                     errln(UnicodeString("#") + i + ": " + theErr);
   1198                 }
   1199                 // print out the error, too, if any.
   1200             }
   1201         }
   1202 
   1203         if(completed == kStringThreadThreads)
   1204         {
   1205             logln("Done!");
   1206             if(terrs) {
   1207                 errln("There were errors.");
   1208             }
   1209             break;
   1210         }
   1211 
   1212         SimpleThread::sleep(900);
   1213     }
   1214 
   1215     if (patience <= 0) {
   1216         errln("patience exceeded. ");
   1217         // while (TRUE) {SimpleThread::sleep(10000);}   // TODO:   for debugging.  Sleep forever on failure.
   1218         terrs++;
   1219     }
   1220 
   1221     if (terrs > 0) {
   1222         SimpleThread::errorFunc();
   1223     }
   1224 
   1225 cleanupAndReturn:
   1226     if (terrs == 0) {
   1227         /*
   1228         Don't clean up if there are errors. This prevents crashes if the
   1229         threads are still running and using this data. This will only happen
   1230         if there is an error with the test, ICU, or the machine is too slow.
   1231         It's better to leak than crash.
   1232         */
   1233         for(j = 0; j < kStringThreadThreads; j++) {
   1234             delete tests[j];
   1235         }
   1236         delete testString;
   1237     }
   1238 }
   1239 
   1240 #endif // ICU_USE_THREADS
   1241