]> git.saurik.com Git - apple/icu.git/blame - icuSources/test/intltest/tsmthred.cpp
ICU-59131.0.1.tar.gz
[apple/icu.git] / icuSources / test / intltest / tsmthred.cpp
CommitLineData
f3c0d7a5
A
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
b75a7d8f 3/********************************************************************
b331163b 4 * COPYRIGHT:
2ca993e8 5 * Copyright (c) 1999-2015, International Business Machines Corporation and
b75a7d8f
A
6 * others. All Rights Reserved.
7 ********************************************************************/
8
729e4ab9 9#include "simplethread.h"
46f4442e 10
374ca955
A
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"
729e4ab9 17#include "unicode/localpointer.h"
374ca955
A
18#include "unicode/resbund.h"
19#include "unicode/udata.h"
20#include "unicode/uloc.h"
21#include "unicode/locid.h"
22#include "putilimp.h"
51004dcb
A
23#include "intltest.h"
24#include "tsmthred.h"
25#include "unicode/ushape.h"
57a6839d 26#include "unicode/translit.h"
b331163b
A
27#include "sharedobject.h"
28#include "unifiedcache.h"
29#include "uassert.h"
4388f060 30
b75a7d8f 31
73c04bcf
A
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");}}
2ca993e8
A
34#define TSMTHREAD_ASSERT_SUCCESS(status) {if (U_FAILURE(status)) { \
35 errln("file: %s:%d status = %s\n", __FILE__, __LINE__, u_errorName(status));}}
b75a7d8f
A
36
37MultithreadTest::MultithreadTest()
38{
39}
40
41MultithreadTest::~MultithreadTest()
42{
43}
44
b75a7d8f
A
45#include <stdio.h>
46#include <string.h>
47#include <ctype.h> // tolower, toupper
48
49#include "unicode/putil.h"
50
729e4ab9 51// for mthreadtest
b75a7d8f
A
52#include "unicode/numfmt.h"
53#include "unicode/choicfmt.h"
54#include "unicode/msgfmt.h"
55#include "unicode/locid.h"
51004dcb 56#include "unicode/coll.h"
374ca955 57#include "unicode/calendar.h"
b75a7d8f
A
58#include "ucaconf.h"
59
374ca955 60
b331163b 61void MultithreadTest::runIndexedTest( int32_t index, UBool exec,
b75a7d8f
A
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;
374ca955 71
b75a7d8f
A
72 case 1:
73 name = "TestMutex";
74 if (exec)
75 TestMutex();
76 break;
374ca955 77
b75a7d8f
A
78 case 2:
79 name = "TestThreadedIntl";
80#if !UCONFIG_NO_FORMATTING
374ca955 81 if (exec) {
b75a7d8f 82 TestThreadedIntl();
374ca955 83 }
b75a7d8f
A
84#endif
85 break;
374ca955 86
b75a7d8f
A
87 case 3:
88 name = "TestCollators";
89#if !UCONFIG_NO_COLLATION
374ca955
A
90 if (exec) {
91 TestCollators();
92 }
b75a7d8f
A
93#endif /* #if !UCONFIG_NO_COLLATION */
94 break;
374ca955
A
95
96 case 4:
b331163b 97 name = "TestString";
374ca955
A
98 if (exec) {
99 TestString();
100 }
101 break;
102
57a6839d 103 case 5:
b331163b 104 name = "TestArabicShapingThreads";
51004dcb
A
105 if (exec) {
106 TestArabicShapingThreads();
107 }
108 break;
51004dcb 109
57a6839d
A
110 case 6:
111 name = "TestAnyTranslit";
112 if (exec) {
113 TestAnyTranslit();
114 }
115 break;
b331163b
A
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;
2ca993e8
A
129#if !UCONFIG_NO_TRANSLITERATION
130 case 9:
131 name = "TestBreakTranslit";
132 if (exec) {
133 TestBreakTranslit();
134 }
135 break;
136#endif
b75a7d8f
A
137 default:
138 name = "";
139 break; //needed to end loop
140 }
141}
142
143
374ca955
A
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
2ca993e8 149// set their chars. At the end we make sure they are all set.
374ca955
A
150//
151//-----------------------------------------------------------------------------------
b75a7d8f
A
152
153class TestThreadsThread : public SimpleThread
154{
155public:
156 TestThreadsThread(char* whatToChange) { fWhatToChange = whatToChange; }
2ca993e8 157 virtual void run() { Mutex m;
b331163b 158 *fWhatToChange = '*';
b75a7d8f
A
159 }
160private:
161 char *fWhatToChange;
51004dcb 162};
b331163b 163
b75a7d8f
A
164
165void MultithreadTest::TestThreads()
166{
2ca993e8 167 static const int32_t THREADTEST_NRTHREADS = 8;
b75a7d8f
A
168 char threadTestChars[THREADTEST_NRTHREADS + 1];
169 SimpleThread *threads[THREADTEST_NRTHREADS];
73c04bcf 170 int32_t numThreadsStarted = 0;
b75a7d8f
A
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 }
73c04bcf
A
186 else {
187 numThreadsStarted++;
188 }
b75a7d8f
A
189 logln(" Subthread started.");
190 }
191
2ca993e8
A
192 if (numThreadsStarted != THREADTEST_NRTHREADS) {
193 errln("Not all threads could be started for testing!");
73c04bcf
A
194 return;
195 }
b75a7d8f 196
2ca993e8
A
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);
b75a7d8f 202 }
b75a7d8f
A
203 delete threads[i];
204 }
205}
206
207
2ca993e8
A
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
219class TestArabicShapeThreads : public SimpleThread
51004dcb 220{
2ca993e8
A
221public:
222 TestArabicShapeThreads() {};
223 virtual void run() { doTailTest(); };
224private:
225 void doTailTest();
226};
51004dcb 227
b331163b 228
2ca993e8
A
229void 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;
51004dcb 236
2ca993e8
A
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;
51004dcb 251 }
51004dcb 252
2ca993e8
A
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 }
51004dcb 269 }
2ca993e8
A
270 return;
271}
272
51004dcb 273
2ca993e8
A
274void MultithreadTest::TestArabicShapingThreads()
275{
276 TestArabicShapeThreads threads[30];
51004dcb 277
2ca993e8 278 int32_t i;
b331163b 279
2ca993e8
A
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);
51004dcb 284 }
51004dcb
A
285 }
286
2ca993e8
A
287 for(i=0; i < UPRV_LENGTHOF(threads); i++) {
288 threads[i].join();
51004dcb 289 }
2ca993e8 290 logln("->TestArabicShapingThreads <- Got all threads! cya");
51004dcb
A
291}
292
b331163b 293
73c04bcf
A
294//-----------------------------------------------------------------------
295//
296// TestMutex - a simple (non-stress) test to verify that ICU mutexes
2ca993e8 297// and condition variables are functioning. Does not test the use of
73c04bcf
A
298// mutexes within ICU services, but rather that the
299// platform's mutex support is at least superficially there.
300//
301//----------------------------------------------------------------------
2ca993e8
A
302static UMutex gTestMutexA = U_MUTEX_INITIALIZER;
303static UConditionVar gThreadsCountChanged = U_CONDITION_INITIALIZER;
73c04bcf 304
b331163b 305static int gThreadsStarted = 0;
73c04bcf
A
306static int gThreadsInMiddle = 0;
307static int gThreadsDone = 0;
308
2ca993e8 309static const int TESTMUTEX_THREAD_COUNT = 40;
b75a7d8f 310
73c04bcf 311class TestMutexThread : public SimpleThread
b75a7d8f
A
312{
313public:
2ca993e8 314 virtual void run() {
73c04bcf 315 // This is the code that each of the spawned threads runs.
2ca993e8
A
316 // All threads move together throught the started - middle - done sequence together,
317 // waiting for all other threads to reach each point before advancing.
73c04bcf 318 umtx_lock(&gTestMutexA);
2ca993e8
A
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 }
73c04bcf 346 umtx_unlock(&gTestMutexA);
b75a7d8f 347 }
b75a7d8f
A
348};
349
350void MultithreadTest::TestMutex()
351{
73c04bcf
A
352 gThreadsStarted = 0;
353 gThreadsInMiddle = 0;
354 gThreadsDone = 0;
2ca993e8
A
355 int32_t i = 0;
356 TestMutexThread threads[TESTMUTEX_THREAD_COUNT];
73c04bcf 357 umtx_lock(&gTestMutexA);
73c04bcf 358 for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
2ca993e8
A
359 if (threads[i].start() != 0) {
360 errln("%s:%d Error starting thread %d", __FILE__, __LINE__, i);
b75a7d8f
A
361 return;
362 }
73c04bcf 363 }
73c04bcf 364
2ca993e8
A
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;
73c04bcf 370 }
73c04bcf 371
2ca993e8
A
372 while (gThreadsInMiddle < TESTMUTEX_THREAD_COUNT) {
373 if (gThreadsDone != 0) {
374 errln("%s:%d gThreadsDone=%d. Expected 0.", __FILE__, __LINE__, gThreadsStarted);
73c04bcf
A
375 return;
376 }
2ca993e8 377 umtx_condWait(&gThreadsCountChanged, &gTestMutexA);
b75a7d8f 378 }
b75a7d8f 379
2ca993e8
A
380 while (gThreadsDone < TESTMUTEX_THREAD_COUNT) {
381 umtx_condWait(&gThreadsCountChanged, &gTestMutexA);
382 }
383 umtx_unlock(&gTestMutexA);
73c04bcf
A
384
385 for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
2ca993e8 386 threads[i].join();
73c04bcf 387 }
73c04bcf 388}
b75a7d8f
A
389
390
374ca955 391//-------------------------------------------------------------------------------------------
b75a7d8f 392//
2ca993e8 393// TestMultithreadedIntl. Test ICU Formatting in a multi-threaded environment
b75a7d8f 394//
374ca955 395//-------------------------------------------------------------------------------------------
b75a7d8f
A
396
397
b75a7d8f
A
398// * Show exactly where the string's differences lie.
399UnicodeString 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
374ca955
A
427//-------------------------------------------------------------------------------------------
428//
429// FormatThreadTest - a thread that tests performing a number of numberformats.
430//
431//-------------------------------------------------------------------------------------------
b75a7d8f 432
57a6839d 433const int kFormatThreadIterations = 100; // # of iterations per thread
b331163b 434const int kFormatThreadThreads = 10; // # of threads to spawn
b75a7d8f
A
435
436#if !UCONFIG_NO_FORMATTING
437
b75a7d8f
A
438
439
440struct FormatThreadTestData
441{
442 double number;
443 UnicodeString string;
444 FormatThreadTestData(double a, const UnicodeString& b) : number(a),string(b) {}
445} ;
446
447
b75a7d8f
A
448// "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
449
57a6839d 450static void formatErrorMessage(UErrorCode &realStatus, const UnicodeString& pattern, const Locale& theLocale,
b75a7d8f
A
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
73c04bcf 457 UnicodeString errString1(u_errorName(inStatus0));
b75a7d8f
A
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);
b331163b 472
b75a7d8f
A
473 if (U_FAILURE(realStatus)) {
474 delete fmt;
475 return;
476 }
477
b331163b 478 FieldPosition ignore = 0;
b75a7d8f
A
479 fmt->format(myArgs,4,result,ignore,realStatus);
480
481 delete fmt;
73c04bcf 482}
b75a7d8f 483
57a6839d 484/**
b331163b
A
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 */
489class 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
500const ThreadSafeFormatSharedData *gSharedData = NULL;
501
502ThreadSafeFormatSharedData::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
516ThreadSafeFormatSharedData::~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.
57a6839d
A
526 */
527class ThreadSafeFormat {
528public:
529 /* give a unique offset to each thread */
b331163b
A
530 ThreadSafeFormat(UErrorCode &status);
531 UBool doStuff(int32_t offset, UnicodeString &appendErr, UErrorCode &status) const;
57a6839d 532private:
b331163b 533 LocalPointer<NumberFormat> fFormat; // formatter - en_US constructed currency
57a6839d
A
534};
535
57a6839d 536
b331163b
A
537ThreadSafeFormat::ThreadSafeFormat(UErrorCode &status) {
538 fFormat.adoptInstead(NumberFormat::createCurrencyInstance(Locale::getUS(), status));
57a6839d
A
539}
540
b331163b 541static const UChar kUSD[] = { 0x55, 0x53, 0x44, 0x00 };
57a6839d 542
b331163b 543UBool ThreadSafeFormat::doStuff(int32_t offset, UnicodeString &appendErr, UErrorCode &status) const {
57a6839d 544 UBool okay = TRUE;
57a6839d
A
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
b331163b 555 if(u_strcmp(gSharedData->fFormat->getCurrency(), kUSD)) {
57a6839d
A
556 appendErr.append("gFormat currency != ")
557 .append(kUSD)
558 .append(", =")
b331163b 559 .append(gSharedData->fFormat->getCurrency())
57a6839d
A
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) {
b331163b
A
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;
57a6839d
A
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}
374ca955
A
581
582UBool 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
b75a7d8f 589
2ca993e8 590class FormatThreadTest : public SimpleThread
b75a7d8f
A
591{
592public:
374ca955
A
593 int fNum;
594 int fTraceInfo;
595
b331163b 596 LocalPointer<ThreadSafeFormat> fTSF;
57a6839d 597
b75a7d8f 598 FormatThreadTest() // constructor is NOT multithread safe.
2ca993e8 599 : SimpleThread(),
374ca955
A
600 fNum(0),
601 fTraceInfo(0),
b331163b 602 fTSF(NULL),
b75a7d8f
A
603 fOffset(0)
604 // the locale to use
605 {
b331163b
A
606 UErrorCode status = U_ZERO_ERROR; // TODO: rearrange code to allow checking of status.
607 fTSF.adoptInstead(new ThreadSafeFormat(status));
b75a7d8f
A
608 static int32_t fgOffset = 0;
609 fgOffset += 3;
610 fOffset = fgOffset;
611 }
612
613
614 virtual void run()
615 {
374ca955 616 fTraceInfo = 1;
729e4ab9 617 LocalPointer<NumberFormat> percentFormatter;
374ca955
A
618 UErrorCode status = U_ZERO_ERROR;
619
620#if 0
b331163b 621 // debugging code,
374ca955
A
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
46f4442e 636#if 0
b331163b 637 // debugging code,
374ca955
A
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
b75a7d8f 666 // Keep this data here to avoid static initialization.
b331163b 667 FormatThreadTestData kNumberFormatTestData[] =
b75a7d8f
A
668 {
669 FormatThreadTestData((double)5.0, UnicodeString("5", "")),
374ca955
A
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", "")),
b75a7d8f 676 };
b331163b
A
677 int32_t kNumberFormatTestDataLength = UPRV_LENGTHOF(kNumberFormatTestData);
678
b75a7d8f 679 // Keep this data here to avoid static initialization.
b331163b 680 FormatThreadTestData kPercentFormatTestData[] =
b75a7d8f 681 {
46f4442e
A
682 FormatThreadTestData((double)5.0, CharsToUnicodeString("500\\u00a0%")),
683 FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")),
684 FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")),
b331163b 685 FormatThreadTestData(
46f4442e 686 16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP
b331163b 687 FormatThreadTestData(
46f4442e 688 81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")),
b75a7d8f 689 };
b331163b 690 int32_t kPercentFormatTestDataLength = UPRV_LENGTHOF(kPercentFormatTestData);
b75a7d8f 691 int32_t iteration;
b331163b 692
374ca955 693 status = U_ZERO_ERROR;
729e4ab9 694 LocalPointer<NumberFormat> formatter(NumberFormat::createInstance(Locale::getEnglish(),status));
374ca955 695 if(U_FAILURE(status)) {
2ca993e8
A
696 IntlTest::gTest->dataerrln("%s:%d Error %s on NumberFormat::createInstance().",
697 __FILE__, __LINE__, u_errorName(status));
374ca955 698 goto cleanupAndReturn;
b75a7d8f 699 }
b331163b 700
729e4ab9 701 percentFormatter.adoptInstead(NumberFormat::createPercentInstance(Locale::getFrench(),status));
374ca955 702 if(U_FAILURE(status)) {
2ca993e8
A
703 IntlTest::gTest->errln("%s:%d Error %s on NumberFormat::createPercentInstance().",
704 __FILE__, __LINE__, u_errorName(status));
374ca955 705 goto cleanupAndReturn;
b75a7d8f 706 }
b331163b 707
2ca993e8 708 for(iteration = 0;!IntlTest::gTest->getErrors() && iteration<kFormatThreadIterations;iteration++)
b75a7d8f 709 {
b331163b 710
b75a7d8f 711 int32_t whichLine = (iteration + fOffset)%kNumberFormatTestDataLength;
b331163b 712
b75a7d8f 713 UnicodeString output;
b331163b 714
b75a7d8f 715 formatter->format(kNumberFormatTestData[whichLine].number, output);
b331163b 716
374ca955 717 if(0 != output.compare(kNumberFormatTestData[whichLine].string)) {
2ca993e8 718 IntlTest::gTest->errln("format().. expected " + kNumberFormatTestData[whichLine].string
374ca955
A
719 + " got " + output);
720 goto cleanupAndReturn;
b75a7d8f 721 }
b331163b 722
b75a7d8f
A
723 // Now check percent.
724 output.remove();
725 whichLine = (iteration + fOffset)%kPercentFormatTestDataLength;
b331163b 726
b75a7d8f 727 percentFormatter->format(kPercentFormatTestData[whichLine].number, output);
b75a7d8f
A
728 if(0 != output.compare(kPercentFormatTestData[whichLine].string))
729 {
2ca993e8 730 IntlTest::gTest->errln("percent format().. \n" +
374ca955
A
731 showDifference(kPercentFormatTestData[whichLine].string,output));
732 goto cleanupAndReturn;
b75a7d8f 733 }
b331163b
A
734
735 // Test message error
374ca955 736 const int kNumberOfMessageTests = 3;
b75a7d8f
A
737 UErrorCode statusToCheck;
738 UnicodeString patternToCheck;
739 Locale messageLocale;
740 Locale countryToCheck;
741 double currencyToCheck;
b331163b 742
b75a7d8f 743 UnicodeString expected;
b331163b 744
b75a7d8f
A
745 // load the cases.
746 switch((iteration+fOffset) % kNumberOfMessageTests)
747 {
748 default:
749 case 0:
750 statusToCheck= U_FILE_ACCESS_ERROR;
374ca955
A
751 patternToCheck= "0:Someone from {2} is receiving a #{0}"
752 " error - {1}. Their telephone call is costing "
753 "{3,number,currency}."; // number,currency
b75a7d8f
A
754 messageLocale= Locale("en","US");
755 countryToCheck= Locale("","HR");
756 currencyToCheck= 8192.77;
374ca955
A
757 expected= "0:Someone from Croatia is receiving a #4 error - "
758 "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77.";
b75a7d8f
A
759 break;
760 case 1:
761 statusToCheck= U_INDEX_OUTOFBOUNDS_ERROR;
b331163b
A
762 patternToCheck= "1:A customer in {2} is receiving a #{0} error - {1}. "
763 "Their telephone call is costing {3,number,currency}."; // number,currency
374ca955 764 messageLocale= Locale("de","DE@currency=DEM");
b75a7d8f
A
765 countryToCheck= Locale("","BF");
766 currencyToCheck= 2.32;
46f4442e 767 expected= CharsToUnicodeString(
b331163b
A
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.");
374ca955 770 break;
b75a7d8f
A
771 case 2:
772 statusToCheck= U_MEMORY_ALLOCATION_ERROR;
374ca955
A
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
b75a7d8f
A
777 countryToCheck= Locale("","US"); // hmm
778 currencyToCheck= 40193.12;
374ca955
A
779 expected= CharsToUnicodeString(
780 "2:user in Vereinigte Staaten is receiving a #7 error"
781 " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent"
46f4442e 782 " \\u00f6S\\u00A040.193,12 on memory.");
b75a7d8f
A
783 break;
784 }
b331163b 785
b75a7d8f
A
786 UnicodeString result;
787 UErrorCode status = U_ZERO_ERROR;
374ca955
A
788 formatErrorMessage(status,patternToCheck,messageLocale,statusToCheck,
789 countryToCheck,currencyToCheck,result);
b75a7d8f
A
790 if(U_FAILURE(status))
791 {
73c04bcf 792 UnicodeString tmp(u_errorName(status));
2ca993e8 793 IntlTest::gTest->errln("Failure on message format, pattern=" + patternToCheck +
374ca955
A
794 ", error = " + tmp);
795 goto cleanupAndReturn;
b75a7d8f 796 }
b331163b 797
b75a7d8f
A
798 if(result != expected)
799 {
2ca993e8 800 IntlTest::gTest->errln("PatternFormat: \n" + showDifference(expected,result));
374ca955 801 goto cleanupAndReturn;
b75a7d8f 802 }
57a6839d
A
803 // test the Thread Safe Format
804 UnicodeString appendErr;
b331163b 805 if(!fTSF->doStuff(fNum, appendErr, status)) {
2ca993e8 806 IntlTest::gTest->errln(appendErr);
57a6839d
A
807 goto cleanupAndReturn;
808 }
374ca955 809 } /* end of for loop */
57a6839d
A
810
811
812
374ca955 813cleanupAndReturn:
374ca955 814 fTraceInfo = 2;
b75a7d8f 815 }
b331163b 816
b75a7d8f
A
817private:
818 int32_t fOffset; // where we are testing from.
819};
820
821// ** The actual test function.
822
823void MultithreadTest::TestThreadedIntl()
824{
374ca955 825 UnicodeString theErr;
374ca955 826
57a6839d
A
827 UErrorCode threadSafeErr = U_ZERO_ERROR;
828
b331163b 829 ThreadSafeFormatSharedData sharedData(threadSafeErr);
57a6839d
A
830 assertSuccess("initializing ThreadSafeFormat", threadSafeErr, TRUE);
831
374ca955
A
832 //
833 // Create and start the test threads
834 //
835 logln("Spawning: %d threads * %d iterations each.",
836 kFormatThreadThreads, kFormatThreadIterations);
2ca993e8
A
837 FormatThreadTest tests[kFormatThreadThreads];
838 int32_t j;
839 for(j = 0; j < UPRV_LENGTHOF(tests); j++) {
374ca955 840 tests[j].fNum = j;
b75a7d8f
A
841 int32_t threadStatus = tests[j].start();
842 if (threadStatus != 0) {
2ca993e8
A
843 errln("%s:%d System Error %d starting thread number %d.",
844 __FILE__, __LINE__, threadStatus, j);
729e4ab9 845 return;
b75a7d8f 846 }
2ca993e8 847 }
b75a7d8f 848
2ca993e8
A
849
850 for (j=0; j<UPRV_LENGTHOF(tests); j++) {
851 tests[j].join();
852 logln("Thread # %d is complete..", j);
853 }
374ca955
A
854}
855#endif /* #if !UCONFIG_NO_FORMATTING */
b75a7d8f 856
b75a7d8f 857
b75a7d8f 858
b75a7d8f 859
b75a7d8f 860
374ca955
A
861//-------------------------------------------------------------------------------------------
862//
863// Collation threading test
864//
865//-------------------------------------------------------------------------------------------
b75a7d8f
A
866#if !UCONFIG_NO_COLLATION
867
868#define kCollatorThreadThreads 10 // # of threads to spawn
73c04bcf 869#define kCollatorThreadPatience kCollatorThreadThreads*30
b75a7d8f
A
870
871struct Line {
374ca955
A
872 UChar buff[25];
873 int32_t buflen;
b75a7d8f
A
874} ;
875
51004dcb
A
876static UBool
877skipLineBecauseOfBug(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
888static UCollationResult
889normalizeResult(int32_t result) {
890 return result<0 ? UCOL_LESS : result==0 ? UCOL_EQUAL : UCOL_GREATER;
891}
892
2ca993e8 893class CollatorThreadTest : public SimpleThread
b75a7d8f 894{
b331163b 895private:
51004dcb 896 const Collator *coll;
374ca955
A
897 const Line *lines;
898 int32_t noLines;
51004dcb 899 UBool isAtLeastUCA62;
b75a7d8f 900public:
2ca993e8 901 CollatorThreadTest() : SimpleThread(),
374ca955
A
902 coll(NULL),
903 lines(NULL),
51004dcb
A
904 noLines(0),
905 isAtLeastUCA62(TRUE)
374ca955
A
906 {
907 };
51004dcb 908 void setCollator(Collator *c, Line *l, int32_t nl, UBool atLeastUCA62)
374ca955
A
909 {
910 coll = c;
911 lines = l;
912 noLines = nl;
51004dcb 913 isAtLeastUCA62 = atLeastUCA62;
374ca955
A
914 }
915 virtual void run() {
374ca955
A
916 uint8_t sk1[1024], sk2[1024];
917 uint8_t *oldSk = NULL, *newSk = sk1;
51004dcb
A
918 int32_t oldLen = 0;
919 int32_t prev = 0;
374ca955 920 int32_t i = 0;
729e4ab9 921
374ca955 922 for(i = 0; i < noLines; i++) {
51004dcb
A
923 if(lines[i].buflen == 0) { continue; }
924
925 if(skipLineBecauseOfBug(lines[i].buff, lines[i].buflen)) { continue; }
729e4ab9 926
51004dcb 927 int32_t resLen = coll->getSortKey(lines[i].buff, lines[i].buflen, newSk, 1024);
729e4ab9 928
374ca955 929 if(oldSk != NULL) {
51004dcb
A
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);
729e4ab9 933
374ca955 934 if(cmpres != -cmpres2) {
2ca993e8 935 IntlTest::gTest->errln(UnicodeString("Compare result not symmetrical on line ") + (i + 1));
374ca955
A
936 break;
937 }
729e4ab9 938
51004dcb 939 if(cmpres != normalizeResult(skres)) {
2ca993e8 940 IntlTest::gTest->errln(UnicodeString("Difference between coll->compare and sortkey compare on line ") + (i + 1));
374ca955
A
941 break;
942 }
729e4ab9 943
51004dcb
A
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 }
374ca955 953 if(res > 0) {
2ca993e8 954 IntlTest::gTest->errln(UnicodeString("Line is not greater or equal than previous line, for line ") + (i + 1));
374ca955 955 break;
374ca955
A
956 }
957 }
729e4ab9 958
374ca955
A
959 oldSk = newSk;
960 oldLen = resLen;
57a6839d 961 (void)oldLen; // Suppress set but not used warning.
51004dcb 962 prev = i;
729e4ab9 963
374ca955 964 newSk = (newSk == sk1)?sk2:sk1;
b75a7d8f 965 }
b75a7d8f 966 }
b75a7d8f
A
967};
968
969void MultithreadTest::TestCollators()
970{
971
374ca955
A
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_");
b75a7d8f 981
374ca955 982 const char* type = "NON_IGNORABLE";
b75a7d8f 983
374ca955
A
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);
b75a7d8f 992
374ca955
A
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.
b75a7d8f 998
374ca955 999 strcpy(buffer+bufLen, ext);
b75a7d8f 1000
b75a7d8f
A
1001 testFile = fopen(buffer, "rb");
1002
1003 if(testFile == 0) {
374ca955
A
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;
729e4ab9 1015 dataerrln("could not open any of the conformance test files, tried opening base %s", buffer);
b331163b 1016 return;
374ca955
A
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"
46f4442e 1022 "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/");
374ca955
A
1023 }
1024 }
b75a7d8f 1025 }
b75a7d8f 1026
51004dcb
A
1027 LocalArray<Line> lines(new Line[200000]);
1028 memset(lines.getAlias(), 0, sizeof(Line)*200000);
374ca955 1029 int32_t lineNum = 0;
b75a7d8f 1030
374ca955 1031 UChar bufferU[1024];
374ca955 1032 uint32_t first = 0;
b75a7d8f 1033
374ca955 1034 while (fgets(buffer, 1024, testFile) != NULL) {
51004dcb
A
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;
374ca955 1045 }
374ca955 1046 lineNum++;
b75a7d8f 1047 }
374ca955 1048 fclose(testFile);
73c04bcf 1049 if(U_FAILURE(status)) {
729e4ab9 1050 dataerrln("Couldn't read the test file!");
73c04bcf
A
1051 return;
1052 }
374ca955 1053
51004dcb
A
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));
374ca955 1060 if(U_FAILURE(status)) {
729e4ab9 1061 errcheckln(status, "Couldn't open UCA collator");
374ca955
A
1062 return;
1063 }
51004dcb
A
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);
374ca955 1069
374ca955 1070 int32_t spawnResult = 0;
729e4ab9 1071 LocalArray<CollatorThreadTest> tests(new CollatorThreadTest[kCollatorThreadThreads]);
374ca955 1072
b75a7d8f
A
1073 logln(UnicodeString("Spawning: ") + kCollatorThreadThreads + " threads * " + kFormatThreadIterations + " iterations each.");
1074 int32_t j = 0;
1075 for(j = 0; j < kCollatorThreadThreads; j++) {
374ca955 1076 //logln("Setting collator %i", j);
51004dcb 1077 tests[j].setCollator(coll.getAlias(), lines.getAlias(), lineNum, isAtLeastUCA62);
b75a7d8f
A
1078 }
1079 for(j = 0; j < kCollatorThreadThreads; j++) {
374ca955
A
1080 log("%i ", j);
1081 spawnResult = tests[j].start();
1082 if(spawnResult != 0) {
2ca993e8
A
1083 errln("%s:%d THREAD INFO: thread %d failed to start with status %d", __FILE__, __LINE__, j, spawnResult);
1084 return;
374ca955 1085 }
b75a7d8f
A
1086 }
1087 logln("Spawned all");
b75a7d8f 1088
2ca993e8
A
1089 for(int32_t i=0;i<kCollatorThreadThreads;i++) {
1090 tests[i].join();
1091 //logln(UnicodeString("Test #") + i + " is complete.. ");
b75a7d8f 1092 }
b75a7d8f
A
1093}
1094
1095#endif /* #if !UCONFIG_NO_COLLATION */
1096
374ca955
A
1097
1098
1099
1100//-------------------------------------------------------------------------------------------
1101//
b331163b 1102// StringThreadTest2
374ca955
A
1103//
1104//-------------------------------------------------------------------------------------------
1105
1106const int kStringThreadIterations = 2500;// # of iterations per thread
1107const int kStringThreadThreads = 10; // # of threads to spawn
374ca955
A
1108
1109
2ca993e8 1110class StringThreadTest2 : public SimpleThread
374ca955
A
1111{
1112public:
1113 int fNum;
1114 int fTraceInfo;
2ca993e8 1115 static const UnicodeString *gSharedString;
374ca955 1116
2ca993e8
A
1117 StringThreadTest2() // constructor is NOT multithread safe.
1118 : SimpleThread(),
1119 fTraceInfo(0)
374ca955
A
1120 {
1121 };
1122
1123
1124 virtual void run()
1125 {
1126 fTraceInfo = 1;
1127 int loopCount = 0;
1128
1129 for (loopCount = 0; loopCount < kStringThreadIterations; loopCount++) {
2ca993e8
A
1130 if (*gSharedString != "This is the original test string.") {
1131 IntlTest::gTest->errln("%s:%d Original string is corrupt.", __FILE__, __LINE__);
374ca955
A
1132 break;
1133 }
2ca993e8 1134 UnicodeString s1 = *gSharedString;
374ca955
A
1135 s1 += "cat this";
1136 UnicodeString s2(s1);
2ca993e8 1137 UnicodeString s3 = *gSharedString;
374ca955
A
1138 s2 = s3;
1139 s3.truncate(12);
1140 s2.truncate(0);
1141 }
1142
374ca955
A
1143 fTraceInfo = 2;
1144 }
b331163b 1145
374ca955
A
1146};
1147
2ca993e8
A
1148const UnicodeString *StringThreadTest2::gSharedString = NULL;
1149
374ca955
A
1150// ** The actual test function.
1151
2ca993e8 1152
374ca955
A
1153void MultithreadTest::TestString()
1154{
374ca955 1155 int j;
2ca993e8
A
1156 StringThreadTest2::gSharedString = new UnicodeString("This is the original test string.");
1157 StringThreadTest2 tests[kStringThreadThreads];
b331163b 1158
374ca955
A
1159 logln(UnicodeString("Spawning: ") + kStringThreadThreads + " threads * " + kStringThreadIterations + " iterations each.");
1160 for(j = 0; j < kStringThreadThreads; j++) {
2ca993e8 1161 int32_t threadStatus = tests[j].start();
374ca955 1162 if (threadStatus != 0) {
2ca993e8 1163 errln("%s:%d System Error %d starting thread number %d.", __FILE__, __LINE__, threadStatus, j);
374ca955
A
1164 }
1165 }
1166
2ca993e8
A
1167 // Force a failure, to verify test is functioning and can report errors.
1168 // const_cast<UnicodeString *>(StringThreadTest2::gSharedString)->setCharAt(5, 'x');
b331163b 1169
2ca993e8
A
1170 for(j=0; j<kStringThreadThreads; j++) {
1171 tests[j].join();
1172 logln(UnicodeString("Test #") + j + " is complete.. ");
374ca955
A
1173 }
1174
2ca993e8
A
1175 delete StringThreadTest2::gSharedString;
1176 StringThreadTest2::gSharedString = NULL;
374ca955
A
1177}
1178
57a6839d 1179
2ca993e8 1180//
57a6839d
A
1181// Test for ticket #10673, race in cache code in AnyTransliterator.
1182// It's difficult to make the original unsafe code actually fail, but
b331163b 1183// this test will fairly reliably take the code path for races in
57a6839d 1184// populating the cache.
2ca993e8 1185//
57a6839d
A
1186
1187#if !UCONFIG_NO_TRANSLITERATION
2ca993e8 1188Transliterator *gSharedTranslit = NULL;
57a6839d 1189class TxThread: public SimpleThread {
57a6839d 1190 public:
2ca993e8 1191 TxThread() {};
57a6839d
A
1192 ~TxThread();
1193 void run();
1194};
1195
1196TxThread::~TxThread() {}
1197void TxThread::run() {
1198 UnicodeString greekString("\\u03B4\\u03B9\\u03B1\\u03C6\\u03BF\\u03C1\\u03B5\\u03C4\\u03B9\\u03BA\\u03BF\\u03CD\\u03C2");
1199 greekString = greekString.unescape();
2ca993e8
A
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 }
57a6839d
A
1205}
1206#endif
b331163b 1207
57a6839d
A
1208
1209void 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 }
2ca993e8
A
1217 gSharedTranslit = tx.getAlias();
1218 TxThread threads[4];
57a6839d 1219 int32_t i;
2ca993e8
A
1220 for (i=0; i<UPRV_LENGTHOF(threads); i++) {
1221 threads[i].start();
57a6839d 1222 }
57a6839d 1223
2ca993e8
A
1224 for (i=0; i<UPRV_LENGTHOF(threads); i++) {
1225 threads[i].join();
57a6839d 1226 }
2ca993e8 1227 gSharedTranslit = NULL;
57a6839d
A
1228#endif // !UCONFIG_NO_TRANSLITERATION
1229}
1230
b331163b 1231
2ca993e8 1232//
b331163b
A
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.
2ca993e8 1242//
b331163b
A
1243
1244class CondThread: public SimpleThread {
1245 public:
1246 CondThread() :fFinished(false) {};
1247 ~CondThread() {};
1248 void run();
1249 bool fFinished;
1250};
1251
1252static UMutex gCTMutex = U_MUTEX_INITIALIZER;
1253static UConditionVar gCTConditionVar = U_CONDITION_INITIALIZER;
1254int gConditionTestOne = 1; // Value one. Non-const, extern linkage to inhibit
1255 // compiler assuming a known value.
1256int gStartedThreads;
1257int gFinishedThreads;
1258static const int NUMTHREADS = 10;
1259
b331163b
A
1260
1261// Worker thread function.
1262void CondThread::run() {
1263 umtx_lock(&gCTMutex);
1264 gStartedThreads += gConditionTestOne;
1265 umtx_condBroadcast(&gCTConditionVar);
1266
1267 while (gStartedThreads < NUMTHREADS) {
1268 if (gFinishedThreads != 0) {
2ca993e8 1269 IntlTest::gTest->errln("File %s, Line %d: Error, gStartedThreads = %d, gFinishedThreads = %d",
b331163b
A
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
1285void MultithreadTest::TestConditionVariables() {
b331163b
A
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 }
2ca993e8
A
1311 }
1312
1313 for (i=0; i<NUMTHREADS; ++i) {
1314 threads[i]->join();
b331163b
A
1315 delete threads[i];
1316 }
1317}
1318
2ca993e8
A
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.
1330static const char *gCacheLocales[] = {
1331 "en_US", "en_GB", "fr_FR", "fr",
1332 "de", "sr_ME", "sr_BA", "sr_CS"};
1333static const char *gCacheLocales2[] = {
1334 "bs", "ca", "ca_AD", "ca_ES",
1335 "en_US", "fi", "ff_CM", "ff_GN"};
1336
1337static int32_t gObjectsCreated = 0; // protected by gCTMutex
b331163b
A
1338static const int32_t CACHE_LOAD = 3;
1339
1340class 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
1351U_NAMESPACE_BEGIN
1352
1353template<> U_EXPORT
1354const UCTMultiThreadItem *LocaleCacheKey<UCTMultiThreadItem>::createObject(
2ca993e8
A
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
b331163b 1368 umtx_lock(&gCTMutex);
2ca993e8
A
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 }
b331163b
A
1381 }
1382 umtx_unlock(&gCTMutex);
1383
2ca993e8
A
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.
b331163b 1394 umtx_lock(&gCTMutex);
2ca993e8
A
1395 if (!firstObject) {
1396 gObjectsCreated += 1;
1397 }
1398 umtx_condBroadcast(&gCTConditionVar);
b331163b 1399 umtx_unlock(&gCTMutex);
2ca993e8 1400
b331163b
A
1401 return result;
1402}
1403
1404U_NAMESPACE_END
1405
1406class UnifiedCacheThread: public SimpleThread {
1407 public:
2ca993e8
A
1408 UnifiedCacheThread(
1409 const UnifiedCache *cache,
1410 const char *loc,
1411 const char *loc2) : fCache(cache), fLoc(loc), fLoc2(loc2) {};
b331163b
A
1412 ~UnifiedCacheThread() {};
1413 void run();
2ca993e8
A
1414 void exerciseByLocale(const Locale &);
1415 const UnifiedCache *fCache;
1416 Locale fLoc;
1417 Locale fLoc2;
b331163b
A
1418};
1419
2ca993e8 1420void UnifiedCacheThread::exerciseByLocale(const Locale &locale) {
b331163b 1421 UErrorCode status = U_ZERO_ERROR;
2ca993e8
A
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 }
b331163b 1448 }
2ca993e8
A
1449 origItem->removeRef();
1450}
b331163b 1451
2ca993e8
A
1452void 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);
b331163b
A
1458}
1459
1460void MultithreadTest::TestUnifiedCache() {
2ca993e8
A
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
b331163b 1465 UErrorCode status = U_ZERO_ERROR;
2ca993e8
A
1466 UnifiedCache::getInstance(status);
1467 UnifiedCache cache(status);
1468 cache.setEvictionPolicy(2, 0, status);
1469 U_ASSERT(U_SUCCESS(status));
1470
b331163b
A
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) {
2ca993e8
A
1477 // Each thread works with a pair of locales.
1478 threads[i][j] = new UnifiedCacheThread(
1479 &cache, gCacheLocales[j], gCacheLocales2[j]);
b331163b
A
1480 threads[i][j]->start();
1481 }
1482 }
2ca993e8
A
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 }
b331163b 1488 }
2ca993e8
A
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());
b331163b
A
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
2ca993e8
A
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
1521static const Transliterator *gSharedTransliterator;
1522static const UnicodeString *gTranslitInput;
1523static const UnicodeString *gTranslitExpected;
1524
1525class BreakTranslitThread: public SimpleThread {
1526 public:
1527 BreakTranslitThread() {};
1528 ~BreakTranslitThread() {};
1529 void run();
1530};
1531
1532void 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
1543void 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 */