Imported Upstream version 58.1
[platform/upstream/icu.git] / source / test / intltest / tsmthred.cpp
1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4  * COPYRIGHT:
5  * Copyright (c) 1999-2015, International Business Machines Corporation and
6  * others. All Rights Reserved.
7  ********************************************************************/
8
9 #include "simplethread.h"
10
11 #include "unicode/utypes.h"
12 #include "unicode/ustring.h"
13 #include "umutex.h"
14 #include "cmemory.h"
15 #include "cstring.h"
16 #include "uparse.h"
17 #include "unicode/localpointer.h"
18 #include "unicode/resbund.h"
19 #include "unicode/udata.h"
20 #include "unicode/uloc.h"
21 #include "unicode/locid.h"
22 #include "putilimp.h"
23 #include "intltest.h"
24 #include "tsmthred.h"
25 #include "unicode/ushape.h"
26 #include "unicode/translit.h"
27 #include "sharedobject.h"
28 #include "unifiedcache.h"
29 #include "uassert.h"
30
31
32 #define TSMTHREAD_FAIL(msg) errln("%s at file %s, line %d", msg, __FILE__, __LINE__)
33 #define TSMTHREAD_ASSERT(expr) {if (!(expr)) {TSMTHREAD_FAIL("Fail");}}
34 #define TSMTHREAD_ASSERT_SUCCESS(status) {if (U_FAILURE(status)) { \
35                   errln("file: %s:%d status = %s\n", __FILE__, __LINE__, u_errorName(status));}}
36
37 MultithreadTest::MultithreadTest()
38 {
39 }
40
41 MultithreadTest::~MultithreadTest()
42 {
43 }
44
45 #include <stdio.h>
46 #include <string.h>
47 #include <ctype.h>    // tolower, toupper
48
49 #include "unicode/putil.h"
50
51 // for mthreadtest
52 #include "unicode/numfmt.h"
53 #include "unicode/choicfmt.h"
54 #include "unicode/msgfmt.h"
55 #include "unicode/locid.h"
56 #include "unicode/coll.h"
57 #include "unicode/calendar.h"
58 #include "ucaconf.h"
59
60
61 void MultithreadTest::runIndexedTest( int32_t index, UBool exec,
62                 const char* &name, char* /*par*/ ) {
63     if (exec)
64         logln("TestSuite MultithreadTest: ");
65     switch (index) {
66     case 0:
67         name = "TestThreads";
68         if (exec)
69             TestThreads();
70         break;
71
72     case 1:
73         name = "TestMutex";
74         if (exec)
75             TestMutex();
76         break;
77
78     case 2:
79         name = "TestThreadedIntl";
80 #if !UCONFIG_NO_FORMATTING
81         if (exec) {
82             TestThreadedIntl();
83         }
84 #endif
85         break;
86
87     case 3:
88       name = "TestCollators";
89 #if !UCONFIG_NO_COLLATION
90       if (exec) {
91             TestCollators();
92       }
93 #endif /* #if !UCONFIG_NO_COLLATION */
94       break;
95
96     case 4:
97         name = "TestString";
98         if (exec) {
99             TestString();
100         }
101         break;
102
103     case 5:
104         name = "TestArabicShapingThreads";
105         if (exec) {
106             TestArabicShapingThreads();
107         }
108         break;
109
110     case 6:
111         name = "TestAnyTranslit";
112         if (exec) {
113             TestAnyTranslit();
114         }
115         break;
116
117     case 7:
118         name = "TestConditionVariables";
119         if (exec) {
120             TestConditionVariables();
121         }
122         break;
123     case 8:
124         name = "TestUnifiedCache";
125         if (exec) {
126             TestUnifiedCache();
127         }
128         break;
129 #if !UCONFIG_NO_TRANSLITERATION
130     case 9:
131         name = "TestBreakTranslit";
132         if (exec) {
133             TestBreakTranslit();
134         }
135         break;
136 #endif
137     default:
138         name = "";
139         break; //needed to end loop
140     }
141 }
142
143
144 //-----------------------------------------------------------------------------------
145 //
146 //   TestThreads -- see if threads really work at all.
147 //
148 //   Set up N threads pointing at N chars. When they are started, they will
149 //   set their chars. At the end we make sure they are all set.
150 //
151 //-----------------------------------------------------------------------------------
152
153 class TestThreadsThread : public SimpleThread
154 {
155 public:
156     TestThreadsThread(char* whatToChange) { fWhatToChange = whatToChange; }
157     virtual void run() { Mutex m;
158                          *fWhatToChange = '*';
159     }
160 private:
161     char *fWhatToChange;
162 };
163
164
165 void MultithreadTest::TestThreads()
166 {
167     static const int32_t THREADTEST_NRTHREADS = 8;
168     char threadTestChars[THREADTEST_NRTHREADS + 1];
169     SimpleThread *threads[THREADTEST_NRTHREADS];
170     int32_t numThreadsStarted = 0;
171
172     int32_t i;
173     for(i=0;i<THREADTEST_NRTHREADS;i++)
174     {
175         threadTestChars[i] = ' ';
176         threads[i] = new TestThreadsThread(&threadTestChars[i]);
177     }
178     threadTestChars[THREADTEST_NRTHREADS] = '\0';
179
180     logln("->" + UnicodeString(threadTestChars) + "<- Firing off threads.. ");
181     for(i=0;i<THREADTEST_NRTHREADS;i++)
182     {
183         if (threads[i]->start() != 0) {
184             errln("Error starting thread %d", i);
185         }
186         else {
187             numThreadsStarted++;
188         }
189         logln(" Subthread started.");
190     }
191
192     if (numThreadsStarted != THREADTEST_NRTHREADS) {
193         errln("Not all threads could be started for testing!");
194         return;
195     }
196
197     logln("Waiting for threads to be set..");
198     for(i=0; i<THREADTEST_NRTHREADS; i++) {
199         threads[i]->join();
200         if (threadTestChars[i] != '*') {
201             errln("%s:%d Thread %d failed.", __FILE__, __LINE__, i);
202         }
203         delete threads[i];
204     }
205 }
206
207
208 //-----------------------------------------------------------------------------------
209 //
210 //   TestArabicShapeThreads -- see if calls to u_shapeArabic in many threads works successfully
211 //
212 //   Set up N threads pointing at N chars. When they are started, they will make calls to doTailTest which tests
213 //   u_shapeArabic, if the calls are successful it will the set * chars.
214 //   At the end we make sure all threads managed to run u_shapeArabic successfully.
215 //   This is a unit test for ticket 9473
216 //
217 //-----------------------------------------------------------------------------------
218
219 class TestArabicShapeThreads : public SimpleThread
220 {
221 public:
222     TestArabicShapeThreads() {};
223     virtual void run() { doTailTest(); };
224 private:
225         void doTailTest();
226 };
227
228
229 void TestArabicShapeThreads::doTailTest(void) {
230     static const UChar src[] = { 0x0020, 0x0633, 0 };
231     static const UChar dst_old[] = { 0xFEB1, 0x200B,0 };
232     static const UChar dst_new[] = { 0xFEB1, 0xFE73,0 };
233     UChar dst[3] = { 0x0000, 0x0000,0 };
234     int32_t length;
235     UErrorCode status;
236
237     for (int32_t loopCount = 0; loopCount < 100; loopCount++) {
238         status = U_ZERO_ERROR;
239         length = u_shapeArabic(src, -1, dst, UPRV_LENGTHOF(dst),
240                 U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR, &status);
241         if(U_FAILURE(status)) {
242             IntlTest::gTest->errln("Fail: status %s\n", u_errorName(status));
243             return;
244         } else if(length!=2) {
245             IntlTest::gTest->errln("Fail: len %d expected 3\n", length);
246             return;
247         } else if(u_strncmp(dst,dst_old,UPRV_LENGTHOF(dst))) {
248             IntlTest::gTest->errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
249                     dst[0],dst[1],dst_old[0],dst_old[1]);
250             return;
251         }
252
253
254         //"Trying new tail
255         status = U_ZERO_ERROR;
256         length = u_shapeArabic(src, -1, dst, UPRV_LENGTHOF(dst),
257                 U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR|U_SHAPE_TAIL_NEW_UNICODE, &status);
258         if(U_FAILURE(status)) {
259             IntlTest::gTest->errln("Fail: status %s\n", u_errorName(status));
260             return;
261         } else if(length!=2) {
262             IntlTest::gTest->errln("Fail: len %d expected 3\n", length);
263             return;
264         } else if(u_strncmp(dst,dst_new,UPRV_LENGTHOF(dst))) {
265             IntlTest::gTest->errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
266                     dst[0],dst[1],dst_new[0],dst_new[1]);
267             return;
268         }
269     }
270     return;
271 }
272         
273
274 void MultithreadTest::TestArabicShapingThreads()
275 {
276     TestArabicShapeThreads threads[30];
277
278     int32_t i;
279
280     logln("-> do TestArabicShapingThreads <- Firing off threads.. ");
281     for(i=0; i < UPRV_LENGTHOF(threads); i++) {
282         if (threads[i].start() != 0) {
283             errln("Error starting thread %d", i);
284         }
285     }
286
287     for(i=0; i < UPRV_LENGTHOF(threads); i++) {
288         threads[i].join();
289     }
290     logln("->TestArabicShapingThreads <- Got all threads! cya");
291 }
292
293
294 //-----------------------------------------------------------------------
295 //
296 //  TestMutex  - a simple (non-stress) test to verify that ICU mutexes
297 //               and condition variables are functioning.  Does not test the use of
298 //               mutexes within ICU services, but rather that the
299 //               platform's mutex support is at least superficially there.
300 //
301 //----------------------------------------------------------------------
302 static UMutex         gTestMutexA          = U_MUTEX_INITIALIZER;
303 static UConditionVar  gThreadsCountChanged = U_CONDITION_INITIALIZER;
304
305 static int     gThreadsStarted = 0;
306 static int     gThreadsInMiddle = 0;
307 static int     gThreadsDone = 0;
308
309 static const int TESTMUTEX_THREAD_COUNT = 40;
310
311 class TestMutexThread : public SimpleThread
312 {
313 public:
314     virtual void run() {
315         // This is the code that each of the spawned threads runs.
316         // All threads move together throught the started - middle - done sequence together,
317         // waiting for all other threads to reach each point before advancing.
318         umtx_lock(&gTestMutexA);
319         gThreadsStarted += 1;
320         umtx_condBroadcast(&gThreadsCountChanged);
321         while (gThreadsStarted < TESTMUTEX_THREAD_COUNT) {
322             if (gThreadsInMiddle != 0) {
323                 IntlTest::gTest->errln(
324                     "%s:%d gThreadsInMiddle = %d. Expected 0.", __FILE__, __LINE__, gThreadsInMiddle);
325                 return;
326             }
327             umtx_condWait(&gThreadsCountChanged, &gTestMutexA);
328         }
329
330         gThreadsInMiddle += 1;
331         umtx_condBroadcast(&gThreadsCountChanged);
332         while (gThreadsInMiddle < TESTMUTEX_THREAD_COUNT) {
333             if (gThreadsDone != 0) {
334                 IntlTest::gTest->errln(
335                     "%s:%d gThreadsDone = %d. Expected 0.", __FILE__, __LINE__, gThreadsDone);
336                 return;
337             }
338             umtx_condWait(&gThreadsCountChanged, &gTestMutexA);
339         }
340
341         gThreadsDone += 1;
342         umtx_condBroadcast(&gThreadsCountChanged);
343         while (gThreadsDone < TESTMUTEX_THREAD_COUNT) {
344             umtx_condWait(&gThreadsCountChanged, &gTestMutexA);
345         }
346         umtx_unlock(&gTestMutexA);
347     }
348 };
349
350 void MultithreadTest::TestMutex()
351 {
352     gThreadsStarted = 0;
353     gThreadsInMiddle = 0;
354     gThreadsDone = 0;
355     int32_t i = 0;
356     TestMutexThread  threads[TESTMUTEX_THREAD_COUNT];
357     umtx_lock(&gTestMutexA);
358     for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
359         if (threads[i].start() != 0) {
360             errln("%s:%d Error starting thread %d", __FILE__, __LINE__, i);
361             return;
362         }
363     }
364
365     // Because we are holding gTestMutexA, all of the threads should be blocked
366     // at the start of their run() function.
367     if (gThreadsStarted != 0) {
368         errln("%s:%d gThreadsStarted=%d. Expected 0.", __FILE__, __LINE__, gThreadsStarted);
369         return;
370     }
371
372     while (gThreadsInMiddle < TESTMUTEX_THREAD_COUNT) {
373         if (gThreadsDone != 0) {
374             errln("%s:%d gThreadsDone=%d. Expected 0.", __FILE__, __LINE__, gThreadsStarted);
375             return;
376         }
377         umtx_condWait(&gThreadsCountChanged, &gTestMutexA);
378     }
379
380     while (gThreadsDone < TESTMUTEX_THREAD_COUNT) {
381         umtx_condWait(&gThreadsCountChanged, &gTestMutexA);
382     }
383     umtx_unlock(&gTestMutexA);
384
385     for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
386         threads[i].join();
387     }
388 }
389
390
391 //-------------------------------------------------------------------------------------------
392 //
393 //   TestMultithreadedIntl.  Test ICU Formatting in a multi-threaded environment
394 //
395 //-------------------------------------------------------------------------------------------
396
397
398 // * Show exactly where the string's differences lie.
399 UnicodeString showDifference(const UnicodeString& expected, const UnicodeString& result)
400 {
401     UnicodeString res;
402     res = expected + "<Expected\n";
403     if(expected.length() != result.length())
404         res += " [ Different lengths ] \n";
405     else
406     {
407         for(int32_t i=0;i<expected.length();i++)
408         {
409             if(expected[i] == result[i])
410             {
411                 res += " ";
412             }
413             else
414             {
415                 res += "|";
416             }
417         }
418         res += "<Differences";
419         res += "\n";
420     }
421     res += result + "<Result\n";
422
423     return res;
424 }
425
426
427 //-------------------------------------------------------------------------------------------
428 //
429 //   FormatThreadTest - a thread that tests performing a number of numberformats.
430 //
431 //-------------------------------------------------------------------------------------------
432
433 const int kFormatThreadIterations = 100;  // # of iterations per thread
434 const int kFormatThreadThreads    = 10;  // # of threads to spawn
435
436 #if !UCONFIG_NO_FORMATTING
437
438
439
440 struct FormatThreadTestData
441 {
442     double number;
443     UnicodeString string;
444     FormatThreadTestData(double a, const UnicodeString& b) : number(a),string(b) {}
445 } ;
446
447
448 // "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
449
450 static void formatErrorMessage(UErrorCode &realStatus, const UnicodeString& pattern, const Locale& theLocale,
451                      UErrorCode inStatus0, /* statusString 1 */ const Locale &inCountry2, double currency3, // these numbers are the message arguments.
452                      UnicodeString &result)
453 {
454     if(U_FAILURE(realStatus))
455         return; // you messed up
456
457     UnicodeString errString1(u_errorName(inStatus0));
458
459     UnicodeString countryName2;
460     inCountry2.getDisplayCountry(theLocale,countryName2);
461
462     Formattable myArgs[] = {
463         Formattable((int32_t)inStatus0),   // inStatus0      {0}
464         Formattable(errString1), // statusString1 {1}
465         Formattable(countryName2),  // inCountry2 {2}
466         Formattable(currency3)// currency3  {3,number,currency}
467     };
468
469     MessageFormat *fmt = new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus);
470     fmt->setLocale(theLocale);
471     fmt->applyPattern(pattern, realStatus);
472
473     if (U_FAILURE(realStatus)) {
474         delete fmt;
475         return;
476     }
477
478     FieldPosition ignore = 0;
479     fmt->format(myArgs,4,result,ignore,realStatus);
480
481     delete fmt;
482 }
483
484 /**
485   * Shared formatters &  data used by instances of ThreadSafeFormat.
486   * Exactly one instance of this class is created, and it is then shared concurrently
487   * by the multiple instances of ThreadSafeFormat.
488   */
489 class ThreadSafeFormatSharedData {
490   public:
491     ThreadSafeFormatSharedData(UErrorCode &status);
492     ~ThreadSafeFormatSharedData();
493     LocalPointer<NumberFormat>  fFormat;
494     Formattable    fYDDThing;
495     Formattable    fBBDThing;
496     UnicodeString  fYDDStr;
497     UnicodeString  fBBDStr;
498 };
499
500 const ThreadSafeFormatSharedData *gSharedData = NULL;
501
502 ThreadSafeFormatSharedData::ThreadSafeFormatSharedData(UErrorCode &status) {
503     fFormat.adoptInstead(NumberFormat::createCurrencyInstance(Locale::getUS(), status));
504     static const UChar kYDD[] = { 0x59, 0x44, 0x44, 0x00 };
505     static const UChar kBBD[] = { 0x42, 0x42, 0x44, 0x00 };
506     fYDDThing.adoptObject(new CurrencyAmount(123.456, kYDD, status));
507     fBBDThing.adoptObject(new CurrencyAmount(987.654, kBBD, status));
508     if (U_FAILURE(status)) {
509         return;
510     }
511     fFormat->format(fYDDThing, fYDDStr, NULL, status);
512     fFormat->format(fBBDThing, fBBDStr, NULL, status);
513     gSharedData = this;
514 }
515
516 ThreadSafeFormatSharedData::~ThreadSafeFormatSharedData() {
517     gSharedData = NULL;
518 }
519
520 /**
521  * Class for thread-safe testing of format.
522  *   Instances of this class appear as members of class FormatThreadTest.
523  *   Multiple instances of FormatThreadTest coexist.
524  *   ThreadSafeFormat::doStuff() is called concurrently to test the thread safety of
525  *   various shared format operations.
526  */
527 class ThreadSafeFormat {
528 public:
529   /* give a unique offset to each thread */
530   ThreadSafeFormat(UErrorCode &status);
531   UBool doStuff(int32_t offset, UnicodeString &appendErr, UErrorCode &status) const;
532 private:
533   LocalPointer<NumberFormat> fFormat; // formatter - en_US constructed currency
534 };
535
536
537 ThreadSafeFormat::ThreadSafeFormat(UErrorCode &status) {
538   fFormat.adoptInstead(NumberFormat::createCurrencyInstance(Locale::getUS(), status));
539 }
540
541 static const UChar kUSD[] = { 0x55, 0x53, 0x44, 0x00 };
542
543 UBool ThreadSafeFormat::doStuff(int32_t offset, UnicodeString &appendErr, UErrorCode &status) const {
544   UBool okay = TRUE;
545
546   if(u_strcmp(fFormat->getCurrency(), kUSD)) {
547     appendErr.append("fFormat currency != ")
548       .append(kUSD)
549       .append(", =")
550       .append(fFormat->getCurrency())
551       .append("! ");
552     okay = FALSE;
553   }
554
555   if(u_strcmp(gSharedData->fFormat->getCurrency(), kUSD)) {
556     appendErr.append("gFormat currency != ")
557       .append(kUSD)
558       .append(", =")
559       .append(gSharedData->fFormat->getCurrency())
560       .append("! ");
561     okay = FALSE;
562   }
563   UnicodeString str;
564   const UnicodeString *o=NULL;
565   Formattable f;
566   const NumberFormat *nf = NULL; // only operate on it as const.
567   switch(offset%4) {
568   case 0:  f = gSharedData->fYDDThing;  o = &gSharedData->fYDDStr;  nf = gSharedData->fFormat.getAlias();  break;
569   case 1:  f = gSharedData->fBBDThing;  o = &gSharedData->fBBDStr;  nf = gSharedData->fFormat.getAlias();  break;
570   case 2:  f = gSharedData->fYDDThing;  o = &gSharedData->fYDDStr;  nf = fFormat.getAlias();  break;
571   case 3:  f = gSharedData->fBBDThing;  o = &gSharedData->fBBDStr;  nf = fFormat.getAlias();  break;
572   }
573   nf->format(f, str, NULL, status);
574
575   if(*o != str) {
576     appendErr.append(showDifference(*o, str));
577     okay = FALSE;
578   }
579   return okay;
580 }
581
582 UBool U_CALLCONV isAcceptable(void *, const char *, const char *, const UDataInfo *) {
583     return TRUE;
584 }
585
586 //static UMTX debugMutex = NULL;
587 //static UMTX gDebugMutex;
588
589
590 class FormatThreadTest : public SimpleThread
591 {
592 public:
593     int     fNum;
594     int     fTraceInfo;
595
596     LocalPointer<ThreadSafeFormat> fTSF;
597
598     FormatThreadTest() // constructor is NOT multithread safe.
599         : SimpleThread(),
600         fNum(0),
601         fTraceInfo(0),
602         fTSF(NULL),
603         fOffset(0)
604         // the locale to use
605     {
606         UErrorCode status = U_ZERO_ERROR;      // TODO: rearrange code to allow checking of status.
607         fTSF.adoptInstead(new ThreadSafeFormat(status));
608         static int32_t fgOffset = 0;
609         fgOffset += 3;
610         fOffset = fgOffset;
611     }
612
613
614     virtual void run()
615     {
616         fTraceInfo                     = 1;
617         LocalPointer<NumberFormat> percentFormatter;
618         UErrorCode status = U_ZERO_ERROR;
619
620 #if 0
621         // debugging code,
622         for (int i=0; i<4000; i++) {
623             status = U_ZERO_ERROR;
624             UDataMemory *data1 = udata_openChoice(0, "res", "en_US", isAcceptable, 0, &status);
625             UDataMemory *data2 = udata_openChoice(0, "res", "fr", isAcceptable, 0, &status);
626             udata_close(data1);
627             udata_close(data2);
628             if (U_FAILURE(status)) {
629                 error("udata_openChoice failed.\n");
630                 break;
631             }
632         }
633         return;
634 #endif
635
636 #if 0
637         // debugging code,
638         int m;
639         for (m=0; m<4000; m++) {
640             status         = U_ZERO_ERROR;
641             UResourceBundle *res   = NULL;
642             const char *localeName = NULL;
643
644             Locale  loc = Locale::getEnglish();
645
646             localeName = loc.getName();
647             // localeName = "en";
648
649             // ResourceBundle bund = ResourceBundle(0, loc, status);
650             //umtx_lock(&gDebugMutex);
651             res = ures_open(NULL, localeName, &status);
652             //umtx_unlock(&gDebugMutex);
653
654             //umtx_lock(&gDebugMutex);
655             ures_close(res);
656             //umtx_unlock(&gDebugMutex);
657
658             if (U_FAILURE(status)) {
659                 error("Resource bundle construction failed.\n");
660                 break;
661             }
662         }
663         return;
664 #endif
665
666         // Keep this data here to avoid static initialization.
667         FormatThreadTestData kNumberFormatTestData[] =
668         {
669             FormatThreadTestData((double)5.0, UnicodeString("5", "")),
670                 FormatThreadTestData( 6.0, UnicodeString("6", "")),
671                 FormatThreadTestData( 20.0, UnicodeString("20", "")),
672                 FormatThreadTestData( 8.0, UnicodeString("8", "")),
673                 FormatThreadTestData( 8.3, UnicodeString("8.3", "")),
674                 FormatThreadTestData( 12345, UnicodeString("12,345", "")),
675                 FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")),
676         };
677         int32_t kNumberFormatTestDataLength = UPRV_LENGTHOF(kNumberFormatTestData);
678
679         // Keep this data here to avoid static initialization.
680         FormatThreadTestData kPercentFormatTestData[] =
681         {
682             FormatThreadTestData((double)5.0, CharsToUnicodeString("500\\u00a0%")),
683                 FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")),
684                 FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")),
685                 FormatThreadTestData(
686                    16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP
687                 FormatThreadTestData(
688                     81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")),
689         };
690         int32_t kPercentFormatTestDataLength = UPRV_LENGTHOF(kPercentFormatTestData);
691         int32_t iteration;
692
693         status = U_ZERO_ERROR;
694         LocalPointer<NumberFormat> formatter(NumberFormat::createInstance(Locale::getEnglish(),status));
695         if(U_FAILURE(status)) {
696             IntlTest::gTest->dataerrln("%s:%d Error %s on NumberFormat::createInstance().",
697                     __FILE__, __LINE__, u_errorName(status));
698             goto cleanupAndReturn;
699         }
700
701         percentFormatter.adoptInstead(NumberFormat::createPercentInstance(Locale::getFrench(),status));
702         if(U_FAILURE(status))             {
703             IntlTest::gTest->errln("%s:%d Error %s on NumberFormat::createPercentInstance().",
704                     __FILE__, __LINE__, u_errorName(status));
705             goto cleanupAndReturn;
706         }
707
708         for(iteration = 0;!IntlTest::gTest->getErrors() && iteration<kFormatThreadIterations;iteration++)
709         {
710
711             int32_t whichLine = (iteration + fOffset)%kNumberFormatTestDataLength;
712
713             UnicodeString  output;
714
715             formatter->format(kNumberFormatTestData[whichLine].number, output);
716
717             if(0 != output.compare(kNumberFormatTestData[whichLine].string)) {
718                 IntlTest::gTest->errln("format().. expected " + kNumberFormatTestData[whichLine].string
719                         + " got " + output);
720                 goto cleanupAndReturn;
721             }
722
723             // Now check percent.
724             output.remove();
725             whichLine = (iteration + fOffset)%kPercentFormatTestDataLength;
726
727             percentFormatter->format(kPercentFormatTestData[whichLine].number, output);
728             if(0 != output.compare(kPercentFormatTestData[whichLine].string))
729             {
730                 IntlTest::gTest->errln("percent format().. \n" +
731                         showDifference(kPercentFormatTestData[whichLine].string,output));
732                 goto cleanupAndReturn;
733             }
734
735             // Test message error
736             const int       kNumberOfMessageTests = 3;
737             UErrorCode      statusToCheck;
738             UnicodeString   patternToCheck;
739             Locale          messageLocale;
740             Locale          countryToCheck;
741             double          currencyToCheck;
742
743             UnicodeString   expected;
744
745             // load the cases.
746             switch((iteration+fOffset) % kNumberOfMessageTests)
747             {
748             default:
749             case 0:
750                 statusToCheck=                      U_FILE_ACCESS_ERROR;
751                 patternToCheck=        "0:Someone from {2} is receiving a #{0}"
752                                        " error - {1}. Their telephone call is costing "
753                                        "{3,number,currency}."; // number,currency
754                 messageLocale=                      Locale("en","US");
755                 countryToCheck=                     Locale("","HR");
756                 currencyToCheck=                    8192.77;
757                 expected=  "0:Someone from Croatia is receiving a #4 error - "
758                             "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77.";
759                 break;
760             case 1:
761                 statusToCheck=                      U_INDEX_OUTOFBOUNDS_ERROR;
762                 patternToCheck=                     "1:A customer in {2} is receiving a #{0} error - {1}. "
763                                                     "Their telephone call is costing {3,number,currency}."; // number,currency
764                 messageLocale=                      Locale("de","DE@currency=DEM");
765                 countryToCheck=                     Locale("","BF");
766                 currencyToCheck=                    2.32;
767                 expected=                           CharsToUnicodeString(
768                                                     "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. "
769                                                     "Their telephone call is costing 2,32\\u00A0DM.");
770                 break;
771             case 2:
772                 statusToCheck=                      U_MEMORY_ALLOCATION_ERROR;
773                 patternToCheck=   "2:user in {2} is receiving a #{0} error - {1}. "
774                                   "They insist they just spent {3,number,currency} "
775                                   "on memory."; // number,currency
776                 messageLocale=                      Locale("de","AT@currency=ATS"); // Austrian German
777                 countryToCheck=                     Locale("","US"); // hmm
778                 currencyToCheck=                    40193.12;
779                 expected=       CharsToUnicodeString(
780                             "2:user in Vereinigte Staaten is receiving a #7 error"
781                             " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent"
782                             " \\u00f6S\\u00A040.193,12 on memory.");
783                 break;
784             }
785
786             UnicodeString result;
787             UErrorCode status = U_ZERO_ERROR;
788             formatErrorMessage(status,patternToCheck,messageLocale,statusToCheck,
789                                 countryToCheck,currencyToCheck,result);
790             if(U_FAILURE(status))
791             {
792                 UnicodeString tmp(u_errorName(status));
793                 IntlTest::gTest->errln("Failure on message format, pattern=" + patternToCheck +
794                         ", error = " + tmp);
795                 goto cleanupAndReturn;
796             }
797
798             if(result != expected)
799             {
800                 IntlTest::gTest->errln("PatternFormat: \n" + showDifference(expected,result));
801                 goto cleanupAndReturn;
802             }
803             // test the Thread Safe Format
804             UnicodeString appendErr;
805             if(!fTSF->doStuff(fNum, appendErr, status)) {
806               IntlTest::gTest->errln(appendErr);
807               goto cleanupAndReturn;
808             }
809         }   /*  end of for loop */
810
811
812
813 cleanupAndReturn:
814         fTraceInfo = 2;
815     }
816
817 private:
818     int32_t fOffset; // where we are testing from.
819 };
820
821 // ** The actual test function.
822
823 void MultithreadTest::TestThreadedIntl()
824 {
825     UnicodeString theErr;
826
827     UErrorCode threadSafeErr = U_ZERO_ERROR;
828
829     ThreadSafeFormatSharedData sharedData(threadSafeErr);
830     assertSuccess("initializing ThreadSafeFormat", threadSafeErr, TRUE);
831
832     //
833     //  Create and start the test threads
834     //
835     logln("Spawning: %d threads * %d iterations each.",
836                 kFormatThreadThreads, kFormatThreadIterations);
837     FormatThreadTest tests[kFormatThreadThreads];
838     int32_t j;
839     for(j = 0; j < UPRV_LENGTHOF(tests); j++) {
840         tests[j].fNum = j;
841         int32_t threadStatus = tests[j].start();
842         if (threadStatus != 0) {
843             errln("%s:%d System Error %d starting thread number %d.",
844                     __FILE__, __LINE__, threadStatus, j);
845             return;
846         }
847     }
848
849
850     for (j=0; j<UPRV_LENGTHOF(tests); j++) {
851         tests[j].join();
852         logln("Thread # %d is complete..", j);
853     }
854 }
855 #endif /* #if !UCONFIG_NO_FORMATTING */
856
857
858
859
860
861 //-------------------------------------------------------------------------------------------
862 //
863 // Collation threading test
864 //
865 //-------------------------------------------------------------------------------------------
866 #if !UCONFIG_NO_COLLATION
867
868 #define kCollatorThreadThreads   10  // # of threads to spawn
869 #define kCollatorThreadPatience kCollatorThreadThreads*30
870
871 struct Line {
872     UChar buff[25];
873     int32_t buflen;
874 } ;
875
876 static UBool
877 skipLineBecauseOfBug(const UChar *s, int32_t length) {
878     // TODO: Fix ICU ticket #8052
879     if(length >= 3 &&
880             (s[0] == 0xfb2 || s[0] == 0xfb3) &&
881             s[1] == 0x334 &&
882             (s[2] == 0xf73 || s[2] == 0xf75 || s[2] == 0xf81)) {
883         return TRUE;
884     }
885     return FALSE;
886 }
887
888 static UCollationResult
889 normalizeResult(int32_t result) {
890     return result<0 ? UCOL_LESS : result==0 ? UCOL_EQUAL : UCOL_GREATER;
891 }
892
893 class CollatorThreadTest : public SimpleThread
894 {
895 private:
896     const Collator *coll;
897     const Line *lines;
898     int32_t noLines;
899     UBool isAtLeastUCA62;
900 public:
901     CollatorThreadTest()  : SimpleThread(),
902         coll(NULL),
903         lines(NULL),
904         noLines(0),
905         isAtLeastUCA62(TRUE)
906     {
907     };
908     void setCollator(Collator *c, Line *l, int32_t nl, UBool atLeastUCA62)
909     {
910         coll = c;
911         lines = l;
912         noLines = nl;
913         isAtLeastUCA62 = atLeastUCA62;
914     }
915     virtual void run() {
916         uint8_t sk1[1024], sk2[1024];
917         uint8_t *oldSk = NULL, *newSk = sk1;
918         int32_t oldLen = 0;
919         int32_t prev = 0;
920         int32_t i = 0;
921
922         for(i = 0; i < noLines; i++) {
923             if(lines[i].buflen == 0) { continue; }
924
925             if(skipLineBecauseOfBug(lines[i].buff, lines[i].buflen)) { continue; }
926
927             int32_t resLen = coll->getSortKey(lines[i].buff, lines[i].buflen, newSk, 1024);
928
929             if(oldSk != NULL) {
930                 int32_t skres = strcmp((char *)oldSk, (char *)newSk);
931                 int32_t cmpres = coll->compare(lines[prev].buff, lines[prev].buflen, lines[i].buff, lines[i].buflen);
932                 int32_t cmpres2 = coll->compare(lines[i].buff, lines[i].buflen, lines[prev].buff, lines[prev].buflen);
933
934                 if(cmpres != -cmpres2) {
935                     IntlTest::gTest->errln(UnicodeString("Compare result not symmetrical on line ") + (i + 1));
936                     break;
937                 }
938
939                 if(cmpres != normalizeResult(skres)) {
940                     IntlTest::gTest->errln(UnicodeString("Difference between coll->compare and sortkey compare on line ") + (i + 1));
941                     break;
942                 }
943
944                 int32_t res = cmpres;
945                 if(res == 0 && !isAtLeastUCA62) {
946                     // Up to UCA 6.1, the collation test files use a custom tie-breaker,
947                     // comparing the raw input strings.
948                     res = u_strcmpCodePointOrder(lines[prev].buff, lines[i].buff);
949                     // Starting with UCA 6.2, the collation test files use the standard UCA tie-breaker,
950                     // comparing the NFD versions of the input strings,
951                     // which we do via setting strength=identical.
952                 }
953                 if(res > 0) {
954                     IntlTest::gTest->errln(UnicodeString("Line is not greater or equal than previous line, for line ") + (i + 1));
955                     break;
956                 }
957             }
958
959             oldSk = newSk;
960             oldLen = resLen;
961             (void)oldLen;   // Suppress set but not used warning.
962             prev = i;
963
964             newSk = (newSk == sk1)?sk2:sk1;
965         }
966     }
967 };
968
969 void MultithreadTest::TestCollators()
970 {
971
972     UErrorCode status = U_ZERO_ERROR;
973     FILE *testFile = NULL;
974     char testDataPath[1024];
975     strcpy(testDataPath, IntlTest::getSourceTestData(status));
976     if (U_FAILURE(status)) {
977         errln("ERROR: could not open test data %s", u_errorName(status));
978         return;
979     }
980     strcat(testDataPath, "CollationTest_");
981
982     const char* type = "NON_IGNORABLE";
983
984     const char *ext = ".txt";
985     if(testFile) {
986         fclose(testFile);
987     }
988     char buffer[1024];
989     strcpy(buffer, testDataPath);
990     strcat(buffer, type);
991     size_t bufLen = strlen(buffer);
992
993     // we try to open 3 files:
994     // path/CollationTest_type.txt
995     // path/CollationTest_type_SHORT.txt
996     // path/CollationTest_type_STUB.txt
997     // we are going to test with the first one that we manage to open.
998
999     strcpy(buffer+bufLen, ext);
1000
1001     testFile = fopen(buffer, "rb");
1002
1003     if(testFile == 0) {
1004         strcpy(buffer+bufLen, "_SHORT");
1005         strcat(buffer, ext);
1006         testFile = fopen(buffer, "rb");
1007
1008         if(testFile == 0) {
1009             strcpy(buffer+bufLen, "_STUB");
1010             strcat(buffer, ext);
1011             testFile = fopen(buffer, "rb");
1012
1013             if (testFile == 0) {
1014                 *(buffer+bufLen) = 0;
1015                 dataerrln("could not open any of the conformance test files, tried opening base %s", buffer);
1016                 return;
1017             } else {
1018                 infoln(
1019                     "INFO: Working with the stub file.\n"
1020                     "If you need the full conformance test, please\n"
1021                     "download the appropriate data files from:\n"
1022                     "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/");
1023             }
1024         }
1025     }
1026
1027     LocalArray<Line> lines(new Line[200000]);
1028     memset(lines.getAlias(), 0, sizeof(Line)*200000);
1029     int32_t lineNum = 0;
1030
1031     UChar bufferU[1024];
1032     uint32_t first = 0;
1033
1034     while (fgets(buffer, 1024, testFile) != NULL) {
1035         if(*buffer == 0 || buffer[0] == '#') {
1036             // Store empty and comment lines so that errors are reported
1037             // for the real test file lines.
1038             lines[lineNum].buflen = 0;
1039             lines[lineNum].buff[0] = 0;
1040         } else {
1041             int32_t buflen = u_parseString(buffer, bufferU, 1024, &first, &status);
1042             lines[lineNum].buflen = buflen;
1043             u_memcpy(lines[lineNum].buff, bufferU, buflen);
1044             lines[lineNum].buff[buflen] = 0;
1045         }
1046         lineNum++;
1047     }
1048     fclose(testFile);
1049     if(U_FAILURE(status)) {
1050       dataerrln("Couldn't read the test file!");
1051       return;
1052     }
1053
1054     UVersionInfo uniVersion;
1055     static const UVersionInfo v62 = { 6, 2, 0, 0 };
1056     u_getUnicodeVersion(uniVersion);
1057     UBool isAtLeastUCA62 = uprv_memcmp(uniVersion, v62, 4) >= 0;
1058
1059     LocalPointer<Collator> coll(Collator::createInstance(Locale::getRoot(), status));
1060     if(U_FAILURE(status)) {
1061         errcheckln(status, "Couldn't open UCA collator");
1062         return;
1063     }
1064     coll->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
1065     coll->setAttribute(UCOL_CASE_FIRST, UCOL_OFF, status);
1066     coll->setAttribute(UCOL_CASE_LEVEL, UCOL_OFF, status);
1067     coll->setAttribute(UCOL_STRENGTH, isAtLeastUCA62 ? UCOL_IDENTICAL : UCOL_TERTIARY, status);
1068     coll->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE, status);
1069
1070     int32_t spawnResult = 0;
1071     LocalArray<CollatorThreadTest> tests(new CollatorThreadTest[kCollatorThreadThreads]);
1072
1073     logln(UnicodeString("Spawning: ") + kCollatorThreadThreads + " threads * " + kFormatThreadIterations + " iterations each.");
1074     int32_t j = 0;
1075     for(j = 0; j < kCollatorThreadThreads; j++) {
1076         //logln("Setting collator %i", j);
1077         tests[j].setCollator(coll.getAlias(), lines.getAlias(), lineNum, isAtLeastUCA62);
1078     }
1079     for(j = 0; j < kCollatorThreadThreads; j++) {
1080         log("%i ", j);
1081         spawnResult = tests[j].start();
1082         if(spawnResult != 0) {
1083             errln("%s:%d THREAD INFO: thread %d failed to start with status %d", __FILE__, __LINE__, j, spawnResult);
1084             return;
1085         }
1086     }
1087     logln("Spawned all");
1088
1089     for(int32_t i=0;i<kCollatorThreadThreads;i++) {
1090         tests[i].join();
1091         //logln(UnicodeString("Test #") + i + " is complete.. ");
1092     }
1093 }
1094
1095 #endif /* #if !UCONFIG_NO_COLLATION */
1096
1097
1098
1099
1100 //-------------------------------------------------------------------------------------------
1101 //
1102 //   StringThreadTest2
1103 //
1104 //-------------------------------------------------------------------------------------------
1105
1106 const int kStringThreadIterations = 2500;// # of iterations per thread
1107 const int kStringThreadThreads    = 10;  // # of threads to spawn
1108
1109
1110 class StringThreadTest2 : public SimpleThread
1111 {
1112 public:
1113     int                 fNum;
1114     int                 fTraceInfo;
1115     static const UnicodeString *gSharedString;
1116
1117     StringThreadTest2() // constructor is NOT multithread safe.
1118         : SimpleThread(),
1119         fTraceInfo(0)
1120     {
1121     };
1122
1123
1124     virtual void run()
1125     {
1126         fTraceInfo    = 1;
1127         int loopCount = 0;
1128
1129         for (loopCount = 0; loopCount < kStringThreadIterations; loopCount++) {
1130             if (*gSharedString != "This is the original test string.") {
1131                 IntlTest::gTest->errln("%s:%d Original string is corrupt.", __FILE__, __LINE__);
1132                 break;
1133             }
1134             UnicodeString s1 = *gSharedString;
1135             s1 += "cat this";
1136             UnicodeString s2(s1);
1137             UnicodeString s3 = *gSharedString;
1138             s2 = s3;
1139             s3.truncate(12);
1140             s2.truncate(0);
1141         }
1142
1143         fTraceInfo = 2;
1144     }
1145
1146 };
1147
1148 const UnicodeString *StringThreadTest2::gSharedString = NULL;
1149
1150 // ** The actual test function.
1151
1152
1153 void MultithreadTest::TestString()
1154 {
1155     int     j;
1156     StringThreadTest2::gSharedString = new UnicodeString("This is the original test string.");
1157     StringThreadTest2  tests[kStringThreadThreads];
1158
1159     logln(UnicodeString("Spawning: ") + kStringThreadThreads + " threads * " + kStringThreadIterations + " iterations each.");
1160     for(j = 0; j < kStringThreadThreads; j++) {
1161         int32_t threadStatus = tests[j].start();
1162         if (threadStatus != 0) {
1163             errln("%s:%d System Error %d starting thread number %d.", __FILE__, __LINE__, threadStatus, j);
1164         }
1165     }
1166
1167     // Force a failure, to verify test is functioning and can report errors.
1168     // const_cast<UnicodeString *>(StringThreadTest2::gSharedString)->setCharAt(5, 'x');
1169
1170     for(j=0; j<kStringThreadThreads; j++) {
1171         tests[j].join();
1172         logln(UnicodeString("Test #") + j + " is complete.. ");
1173     }
1174
1175     delete StringThreadTest2::gSharedString;
1176     StringThreadTest2::gSharedString = NULL;
1177 }
1178
1179
1180 //
1181 // Test for ticket #10673, race in cache code in AnyTransliterator.
1182 // It's difficult to make the original unsafe code actually fail, but
1183 // this test will fairly reliably take the code path for races in
1184 // populating the cache.
1185 //
1186
1187 #if !UCONFIG_NO_TRANSLITERATION
1188 Transliterator *gSharedTranslit = NULL;
1189 class TxThread: public SimpleThread {
1190   public:
1191     TxThread() {};
1192     ~TxThread();
1193     void run();
1194 };
1195
1196 TxThread::~TxThread() {}
1197 void TxThread::run() {
1198     UnicodeString greekString("\\u03B4\\u03B9\\u03B1\\u03C6\\u03BF\\u03C1\\u03B5\\u03C4\\u03B9\\u03BA\\u03BF\\u03CD\\u03C2");
1199     greekString = greekString.unescape();
1200     gSharedTranslit->transliterate(greekString);
1201     if (greekString[0] != 0x64)      // 'd'. The whole transliterated string is "diaphoretikous" (accented u).
1202     {
1203         IntlTest::gTest->errln("%s:%d Transliteration failed.", __FILE__, __LINE__);
1204     }
1205 }
1206 #endif
1207
1208
1209 void MultithreadTest::TestAnyTranslit() {
1210 #if !UCONFIG_NO_TRANSLITERATION
1211     UErrorCode status = U_ZERO_ERROR;
1212     LocalPointer<Transliterator> tx(Transliterator::createInstance("Any-Latin", UTRANS_FORWARD, status));
1213     if (U_FAILURE(status)) {
1214         dataerrln("File %s, Line %d: Error, status = %s", __FILE__, __LINE__, u_errorName(status));
1215         return;
1216     }
1217     gSharedTranslit = tx.getAlias();
1218     TxThread  threads[4];
1219     int32_t i;
1220     for (i=0; i<UPRV_LENGTHOF(threads); i++) {
1221         threads[i].start();
1222     }
1223
1224     for (i=0; i<UPRV_LENGTHOF(threads); i++) {
1225         threads[i].join();
1226     }
1227     gSharedTranslit = NULL;
1228 #endif  // !UCONFIG_NO_TRANSLITERATION
1229 }
1230
1231
1232 //
1233 // Condition Variables Test
1234 //   Create a swarm of threads.
1235 //   Using a mutex and a condition variables each thread
1236 //     Increments a global count of started threads.
1237 //     Broadcasts that it has started.
1238 //     Waits on the condition that all threads have started.
1239 //     Increments a global count of finished threads.
1240 //     Waits on the condition that all threads have finished.
1241 //     Exits.
1242 //
1243
1244 class CondThread: public SimpleThread {
1245   public:
1246     CondThread() :fFinished(false)  {};
1247     ~CondThread() {};
1248     void run();
1249     bool  fFinished;
1250 };
1251
1252 static UMutex gCTMutex = U_MUTEX_INITIALIZER;
1253 static UConditionVar gCTConditionVar = U_CONDITION_INITIALIZER;
1254 int gConditionTestOne = 1;   // Value one. Non-const, extern linkage to inhibit
1255                              //   compiler assuming a known value.
1256 int gStartedThreads;
1257 int gFinishedThreads;
1258 static const int NUMTHREADS = 10;
1259
1260
1261 // Worker thread function.
1262 void CondThread::run() {
1263     umtx_lock(&gCTMutex);
1264     gStartedThreads += gConditionTestOne;
1265     umtx_condBroadcast(&gCTConditionVar);
1266
1267     while (gStartedThreads < NUMTHREADS) {
1268         if (gFinishedThreads != 0) {
1269             IntlTest::gTest->errln("File %s, Line %d: Error, gStartedThreads = %d, gFinishedThreads = %d",
1270                              __FILE__, __LINE__, gStartedThreads, gFinishedThreads);
1271         }
1272         umtx_condWait(&gCTConditionVar, &gCTMutex);
1273     }
1274
1275     gFinishedThreads += gConditionTestOne;
1276     fFinished = true;
1277     umtx_condBroadcast(&gCTConditionVar);
1278
1279     while (gFinishedThreads < NUMTHREADS) {
1280         umtx_condWait(&gCTConditionVar, &gCTMutex);
1281     }
1282     umtx_unlock(&gCTMutex);
1283 }
1284
1285 void MultithreadTest::TestConditionVariables() {
1286     gStartedThreads = 0;
1287     gFinishedThreads = 0;
1288     int i;
1289
1290     umtx_lock(&gCTMutex);
1291     CondThread *threads[NUMTHREADS];
1292     for (i=0; i<NUMTHREADS; ++i) {
1293         threads[i] = new CondThread;
1294         threads[i]->start();
1295     }
1296
1297     while (gStartedThreads < NUMTHREADS) {
1298         umtx_condWait(&gCTConditionVar, &gCTMutex);
1299     }
1300
1301     while (gFinishedThreads < NUMTHREADS) {
1302         umtx_condWait(&gCTConditionVar, &gCTMutex);
1303     }
1304
1305     umtx_unlock(&gCTMutex);
1306
1307     for (i=0; i<NUMTHREADS; ++i) {
1308         if (!threads[i]->fFinished) {
1309             errln("File %s, Line %d: Error, threads[%d]->fFinished == false", __FILE__, __LINE__, i);
1310         }
1311     }
1312
1313     for (i=0; i<NUMTHREADS; ++i) {
1314         threads[i]->join();
1315         delete threads[i];
1316     }
1317 }
1318
1319
1320 //
1321 // Unified Cache Test
1322 //
1323
1324 // Each thread fetches a pair of objects. There are 8 distinct pairs:
1325 // ("en_US", "bs"), ("en_GB", "ca"), ("fr_FR", "ca_AD") etc.
1326 // These pairs represent 8 distinct languages
1327
1328 // Note that only one value per language gets created in the cache.
1329 // In particular each cached value can have multiple keys.
1330 static const char *gCacheLocales[] = {
1331     "en_US", "en_GB", "fr_FR", "fr",
1332     "de", "sr_ME", "sr_BA", "sr_CS"};
1333 static const char *gCacheLocales2[] = {
1334     "bs", "ca", "ca_AD", "ca_ES",
1335     "en_US", "fi", "ff_CM", "ff_GN"};
1336
1337 static int32_t gObjectsCreated = 0;  // protected by gCTMutex
1338 static const int32_t CACHE_LOAD = 3;
1339
1340 class UCTMultiThreadItem : public SharedObject {
1341   public:
1342     char *value;
1343     UCTMultiThreadItem(const char *x) : value(NULL) {
1344         value = uprv_strdup(x);
1345     }
1346     virtual ~UCTMultiThreadItem() {
1347         uprv_free(value);
1348     }
1349 };
1350
1351 U_NAMESPACE_BEGIN
1352
1353 template<> U_EXPORT
1354 const UCTMultiThreadItem *LocaleCacheKey<UCTMultiThreadItem>::createObject(
1355         const void *context, UErrorCode &status) const {
1356     const UnifiedCache *cacheContext = (const UnifiedCache *) context;
1357
1358     if (uprv_strcmp(fLoc.getLanguage(), fLoc.getName()) != 0) {
1359         const UCTMultiThreadItem *result = NULL;
1360         if (cacheContext == NULL) {
1361             UnifiedCache::getByLocale(fLoc.getLanguage(), result, status);
1362             return result;
1363         }
1364         cacheContext->get(LocaleCacheKey<UCTMultiThreadItem>(fLoc.getLanguage()), result, status);
1365         return result;
1366     }
1367
1368     umtx_lock(&gCTMutex);
1369     bool firstObject = (gObjectsCreated == 0);
1370     if (firstObject) {
1371         // Force the first object creation that comes through to wait
1372         // until other have completed. Verifies that cache doesn't
1373         // deadlock when a creation is slow.
1374
1375         // Note that gObjectsCreated needs to be incremeneted from 0 to 1
1376         // early, to keep subsequent threads from entering this path.
1377         gObjectsCreated = 1;
1378         while (gObjectsCreated < 3) {
1379             umtx_condWait(&gCTConditionVar, &gCTMutex);
1380         }
1381     }
1382     umtx_unlock(&gCTMutex);
1383
1384     const UCTMultiThreadItem *result =
1385         new UCTMultiThreadItem(fLoc.getLanguage());
1386     if (result == NULL) {
1387         status = U_MEMORY_ALLOCATION_ERROR;
1388     } else {
1389         result->addRef();
1390     }
1391     
1392     // Log that we created an object. The first object was already counted,
1393     //    don't do it again.
1394     umtx_lock(&gCTMutex);
1395     if (!firstObject) {
1396         gObjectsCreated += 1;
1397     }
1398     umtx_condBroadcast(&gCTConditionVar);
1399     umtx_unlock(&gCTMutex);
1400
1401     return result;
1402 }
1403
1404 U_NAMESPACE_END
1405
1406 class UnifiedCacheThread: public SimpleThread {
1407   public:
1408     UnifiedCacheThread(
1409             const UnifiedCache *cache,
1410             const char *loc,
1411             const char *loc2) : fCache(cache), fLoc(loc), fLoc2(loc2) {};
1412     ~UnifiedCacheThread() {};
1413     void run();
1414     void exerciseByLocale(const Locale &);
1415     const UnifiedCache *fCache;
1416     Locale fLoc;
1417     Locale fLoc2;
1418 };
1419
1420 void UnifiedCacheThread::exerciseByLocale(const Locale &locale) {
1421     UErrorCode status = U_ZERO_ERROR;
1422     const UCTMultiThreadItem *origItem = NULL;
1423     fCache->get(
1424             LocaleCacheKey<UCTMultiThreadItem>(locale), fCache, origItem, status);
1425     U_ASSERT(U_SUCCESS(status));
1426     if (uprv_strcmp(locale.getLanguage(), origItem->value)) {
1427       IntlTest::gTest->errln(
1428               "%s:%d Expected %s, got %s", __FILE__, __LINE__,
1429               locale.getLanguage(),
1430               origItem->value);
1431     }
1432
1433     // Fetch the same item again many times. We should always get the same
1434     // pointer since this client is already holding onto it
1435     for (int32_t i = 0; i < 1000; ++i) {
1436         const UCTMultiThreadItem *item = NULL;
1437         fCache->get(
1438                 LocaleCacheKey<UCTMultiThreadItem>(locale), fCache, item, status);
1439         if (item != origItem) {
1440             IntlTest::gTest->errln(
1441                     "%s:%d Expected to get the same pointer",
1442                      __FILE__,
1443                      __LINE__);
1444         }
1445         if (item != NULL) {
1446             item->removeRef();
1447         }
1448     }
1449     origItem->removeRef();
1450 }
1451
1452 void UnifiedCacheThread::run() {
1453     // Run the exercise with 2 different locales so that we can exercise
1454     // eviction more. If each thread exerices just one locale, then
1455     // eviction can't start until the threads end.
1456     exerciseByLocale(fLoc);
1457     exerciseByLocale(fLoc2);
1458 }
1459
1460 void MultithreadTest::TestUnifiedCache() {
1461
1462     // Start with our own local cache so that we have complete control
1463     // and set the eviction policy to evict starting with 2 unused
1464     // values
1465     UErrorCode status = U_ZERO_ERROR;
1466     UnifiedCache::getInstance(status);
1467     UnifiedCache cache(status);
1468     cache.setEvictionPolicy(2, 0, status);
1469     U_ASSERT(U_SUCCESS(status));
1470
1471     gFinishedThreads = 0;
1472     gObjectsCreated = 0;
1473
1474     UnifiedCacheThread *threads[CACHE_LOAD][UPRV_LENGTHOF(gCacheLocales)];
1475     for (int32_t i=0; i<CACHE_LOAD; ++i) {
1476         for (int32_t j=0; j<UPRV_LENGTHOF(gCacheLocales); ++j) {
1477             // Each thread works with a pair of locales.
1478             threads[i][j] = new UnifiedCacheThread(
1479                     &cache, gCacheLocales[j], gCacheLocales2[j]);
1480             threads[i][j]->start();
1481         }
1482     }
1483
1484     for (int32_t i=0; i<CACHE_LOAD; ++i) {
1485         for (int32_t j=0; j<UPRV_LENGTHOF(gCacheLocales); ++j) {
1486             threads[i][j]->join();
1487         }
1488     }
1489     // Because of cache eviction, we can't assert exactly how many
1490     // distinct objects get created over the course of this run.
1491     // However we know that at least 8 objects get created because that
1492     // is how many distinct languages we have in our test.
1493     if (gObjectsCreated < 8) {
1494         errln("%s:%d Too few objects created.", __FILE__, __LINE__);
1495     }
1496     // We know that each thread cannot create more than 2 objects in
1497     // the cache, and there are UPRV_LENGTHOF(gCacheLocales) pairs of
1498     // objects fetched from the cache. If the threads run in series because
1499     // of eviction, at worst case each thread creates two objects.
1500     if (gObjectsCreated > 2 * CACHE_LOAD * UPRV_LENGTHOF(gCacheLocales)) {
1501         errln("%s:%d Too many objects created, got %d, expected %d", __FILE__, __LINE__, gObjectsCreated, 2 * CACHE_LOAD * UPRV_LENGTHOF(gCacheLocales));
1502
1503     }
1504
1505     assertEquals("unused values", 2, cache.unusedCount());
1506
1507     // clean up threads
1508     for (int32_t i=0; i<CACHE_LOAD; ++i) {
1509         for (int32_t j=0; j<UPRV_LENGTHOF(gCacheLocales); ++j) {
1510             delete threads[i][j];
1511         }
1512     }
1513 }
1514
1515 #if !UCONFIG_NO_TRANSLITERATION
1516 //
1517 //  BreakTransliterator Threading Test
1518 //     This is a test for bug #11603. Test verified to fail prior to fix.
1519 //
1520
1521 static const Transliterator *gSharedTransliterator;
1522 static const UnicodeString *gTranslitInput;
1523 static const UnicodeString *gTranslitExpected;
1524
1525 class BreakTranslitThread: public SimpleThread {
1526   public:
1527     BreakTranslitThread() {};
1528     ~BreakTranslitThread() {};
1529     void run();
1530 };
1531
1532 void BreakTranslitThread::run() {
1533     for (int i=0; i<10; i++) {
1534         icu::UnicodeString s(*gTranslitInput);
1535         gSharedTransliterator->transliterate(s);
1536         if (*gTranslitExpected != s) {
1537             IntlTest::gTest->errln("%s:%d Transliteration threading failure.", __FILE__, __LINE__);
1538             break;
1539         }
1540     }
1541 }
1542
1543 void MultithreadTest::TestBreakTranslit() {
1544     UErrorCode status = U_ZERO_ERROR;
1545     UnicodeString input(
1546         "\\u0E42\\u0E14\\u0E22\\u0E1E\\u0E37\\u0E49\\u0E19\\u0E10\\u0E32\\u0E19\\u0E41\\u0E25\\u0E49\\u0E27,");
1547     input = input.unescape();
1548     gTranslitInput = &input;
1549
1550     gSharedTransliterator = Transliterator::createInstance(
1551         UNICODE_STRING_SIMPLE("Any-Latin; Lower; NFD; [:Diacritic:]Remove; NFC; Latin-ASCII;"), UTRANS_FORWARD, status);
1552     if (!gSharedTransliterator) {
1553          return;
1554      }
1555     TSMTHREAD_ASSERT_SUCCESS(status); 
1556
1557     UnicodeString expected(*gTranslitInput);
1558     gSharedTransliterator->transliterate(expected);
1559     gTranslitExpected = &expected;
1560
1561     BreakTranslitThread threads[4];
1562     for (int i=0; i<UPRV_LENGTHOF(threads); ++i) {
1563         threads[i].start();
1564     }
1565     for (int i=0; i<UPRV_LENGTHOF(threads); ++i) {
1566         threads[i].join();
1567     }
1568
1569     delete gSharedTransliterator;
1570     gTranslitInput = NULL;
1571     gTranslitExpected = NULL;
1572 }
1573
1574 #endif /* !UCONFIG_NO_TRANSLITERATION */