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