1 /********************************************************************
3 * Copyright (c) 1999-2015, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
7 #include "simplethread.h"
9 #include "unicode/utypes.h"
10 #include "unicode/ustring.h"
15 #include "unicode/localpointer.h"
16 #include "unicode/resbund.h"
17 #include "unicode/udata.h"
18 #include "unicode/uloc.h"
19 #include "unicode/locid.h"
23 #include "unicode/ushape.h"
24 #include "unicode/translit.h"
25 #include "sharedobject.h"
26 #include "unifiedcache.h"
30 #define TSMTHREAD_FAIL(msg) errln("%s at file %s, line %d", msg, __FILE__, __LINE__)
31 #define TSMTHREAD_ASSERT(expr) {if (!(expr)) {TSMTHREAD_FAIL("Fail");}}
32 #define TSMTHREAD_ASSERT_SUCCESS(status) {if (U_FAILURE(status)) { \
33 errln("file: %s:%d status = %s\n", __FILE__, __LINE__, u_errorName(status));}}
35 MultithreadTest::MultithreadTest()
39 MultithreadTest::~MultithreadTest()
45 #include <ctype.h> // tolower, toupper
47 #include "unicode/putil.h"
50 #include "unicode/numfmt.h"
51 #include "unicode/choicfmt.h"
52 #include "unicode/msgfmt.h"
53 #include "unicode/locid.h"
54 #include "unicode/coll.h"
55 #include "unicode/calendar.h"
59 void MultithreadTest::runIndexedTest( int32_t index
, UBool exec
,
60 const char* &name
, char* /*par*/ ) {
62 logln("TestSuite MultithreadTest: ");
77 name
= "TestThreadedIntl";
78 #if !UCONFIG_NO_FORMATTING
86 name
= "TestCollators";
87 #if !UCONFIG_NO_COLLATION
91 #endif /* #if !UCONFIG_NO_COLLATION */
102 name
= "TestArabicShapingThreads";
104 TestArabicShapingThreads();
109 name
= "TestAnyTranslit";
116 name
= "TestConditionVariables";
118 TestConditionVariables();
122 name
= "TestUnifiedCache";
127 #if !UCONFIG_NO_TRANSLITERATION
129 name
= "TestBreakTranslit";
137 break; //needed to end loop
142 //-----------------------------------------------------------------------------------
144 // TestThreads -- see if threads really work at all.
146 // Set up N threads pointing at N chars. When they are started, they will
147 // set their chars. At the end we make sure they are all set.
149 //-----------------------------------------------------------------------------------
151 class TestThreadsThread
: public SimpleThread
154 TestThreadsThread(char* whatToChange
) { fWhatToChange
= whatToChange
; }
155 virtual void run() { Mutex m
;
156 *fWhatToChange
= '*';
163 void MultithreadTest::TestThreads()
165 static const int32_t THREADTEST_NRTHREADS
= 8;
166 char threadTestChars
[THREADTEST_NRTHREADS
+ 1];
167 SimpleThread
*threads
[THREADTEST_NRTHREADS
];
168 int32_t numThreadsStarted
= 0;
171 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
173 threadTestChars
[i
] = ' ';
174 threads
[i
] = new TestThreadsThread(&threadTestChars
[i
]);
176 threadTestChars
[THREADTEST_NRTHREADS
] = '\0';
178 logln("->" + UnicodeString(threadTestChars
) + "<- Firing off threads.. ");
179 for(i
=0;i
<THREADTEST_NRTHREADS
;i
++)
181 if (threads
[i
]->start() != 0) {
182 errln("Error starting thread %d", i
);
187 logln(" Subthread started.");
190 if (numThreadsStarted
!= THREADTEST_NRTHREADS
) {
191 errln("Not all threads could be started for testing!");
195 logln("Waiting for threads to be set..");
196 for(i
=0; i
<THREADTEST_NRTHREADS
; i
++) {
198 if (threadTestChars
[i
] != '*') {
199 errln("%s:%d Thread %d failed.", __FILE__
, __LINE__
, i
);
206 //-----------------------------------------------------------------------------------
208 // TestArabicShapeThreads -- see if calls to u_shapeArabic in many threads works successfully
210 // Set up N threads pointing at N chars. When they are started, they will make calls to doTailTest which tests
211 // u_shapeArabic, if the calls are successful it will the set * chars.
212 // At the end we make sure all threads managed to run u_shapeArabic successfully.
213 // This is a unit test for ticket 9473
215 //-----------------------------------------------------------------------------------
217 class TestArabicShapeThreads
: public SimpleThread
220 TestArabicShapeThreads() {};
221 virtual void run() { doTailTest(); };
227 void TestArabicShapeThreads::doTailTest(void) {
228 static const UChar src
[] = { 0x0020, 0x0633, 0 };
229 static const UChar dst_old
[] = { 0xFEB1, 0x200B,0 };
230 static const UChar dst_new
[] = { 0xFEB1, 0xFE73,0 };
231 UChar dst
[3] = { 0x0000, 0x0000,0 };
235 for (int32_t loopCount
= 0; loopCount
< 100; loopCount
++) {
236 status
= U_ZERO_ERROR
;
237 length
= u_shapeArabic(src
, -1, dst
, UPRV_LENGTHOF(dst
),
238 U_SHAPE_LETTERS_SHAPE
|U_SHAPE_SEEN_TWOCELL_NEAR
, &status
);
239 if(U_FAILURE(status
)) {
240 IntlTest::gTest
->errln("Fail: status %s\n", u_errorName(status
));
242 } else if(length
!=2) {
243 IntlTest::gTest
->errln("Fail: len %d expected 3\n", length
);
245 } else if(u_strncmp(dst
,dst_old
,UPRV_LENGTHOF(dst
))) {
246 IntlTest::gTest
->errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
247 dst
[0],dst
[1],dst_old
[0],dst_old
[1]);
253 status
= U_ZERO_ERROR
;
254 length
= u_shapeArabic(src
, -1, dst
, UPRV_LENGTHOF(dst
),
255 U_SHAPE_LETTERS_SHAPE
|U_SHAPE_SEEN_TWOCELL_NEAR
|U_SHAPE_TAIL_NEW_UNICODE
, &status
);
256 if(U_FAILURE(status
)) {
257 IntlTest::gTest
->errln("Fail: status %s\n", u_errorName(status
));
259 } else if(length
!=2) {
260 IntlTest::gTest
->errln("Fail: len %d expected 3\n", length
);
262 } else if(u_strncmp(dst
,dst_new
,UPRV_LENGTHOF(dst
))) {
263 IntlTest::gTest
->errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n",
264 dst
[0],dst
[1],dst_new
[0],dst_new
[1]);
272 void MultithreadTest::TestArabicShapingThreads()
274 TestArabicShapeThreads threads
[30];
278 logln("-> do TestArabicShapingThreads <- Firing off threads.. ");
279 for(i
=0; i
< UPRV_LENGTHOF(threads
); i
++) {
280 if (threads
[i
].start() != 0) {
281 errln("Error starting thread %d", i
);
285 for(i
=0; i
< UPRV_LENGTHOF(threads
); i
++) {
288 logln("->TestArabicShapingThreads <- Got all threads! cya");
292 //-----------------------------------------------------------------------
294 // TestMutex - a simple (non-stress) test to verify that ICU mutexes
295 // and condition variables are functioning. Does not test the use of
296 // mutexes within ICU services, but rather that the
297 // platform's mutex support is at least superficially there.
299 //----------------------------------------------------------------------
300 static UMutex gTestMutexA
= U_MUTEX_INITIALIZER
;
301 static UConditionVar gThreadsCountChanged
= U_CONDITION_INITIALIZER
;
303 static int gThreadsStarted
= 0;
304 static int gThreadsInMiddle
= 0;
305 static int gThreadsDone
= 0;
307 static const int TESTMUTEX_THREAD_COUNT
= 40;
309 class TestMutexThread
: public SimpleThread
313 // This is the code that each of the spawned threads runs.
314 // All threads move together throught the started - middle - done sequence together,
315 // waiting for all other threads to reach each point before advancing.
316 umtx_lock(&gTestMutexA
);
317 gThreadsStarted
+= 1;
318 umtx_condBroadcast(&gThreadsCountChanged
);
319 while (gThreadsStarted
< TESTMUTEX_THREAD_COUNT
) {
320 if (gThreadsInMiddle
!= 0) {
321 IntlTest::gTest
->errln(
322 "%s:%d gThreadsInMiddle = %d. Expected 0.", __FILE__
, __LINE__
, gThreadsInMiddle
);
325 umtx_condWait(&gThreadsCountChanged
, &gTestMutexA
);
328 gThreadsInMiddle
+= 1;
329 umtx_condBroadcast(&gThreadsCountChanged
);
330 while (gThreadsInMiddle
< TESTMUTEX_THREAD_COUNT
) {
331 if (gThreadsDone
!= 0) {
332 IntlTest::gTest
->errln(
333 "%s:%d gThreadsDone = %d. Expected 0.", __FILE__
, __LINE__
, gThreadsDone
);
336 umtx_condWait(&gThreadsCountChanged
, &gTestMutexA
);
340 umtx_condBroadcast(&gThreadsCountChanged
);
341 while (gThreadsDone
< TESTMUTEX_THREAD_COUNT
) {
342 umtx_condWait(&gThreadsCountChanged
, &gTestMutexA
);
344 umtx_unlock(&gTestMutexA
);
348 void MultithreadTest::TestMutex()
351 gThreadsInMiddle
= 0;
354 TestMutexThread threads
[TESTMUTEX_THREAD_COUNT
];
355 umtx_lock(&gTestMutexA
);
356 for (i
=0; i
<TESTMUTEX_THREAD_COUNT
; i
++) {
357 if (threads
[i
].start() != 0) {
358 errln("%s:%d Error starting thread %d", __FILE__
, __LINE__
, i
);
363 // Because we are holding gTestMutexA, all of the threads should be blocked
364 // at the start of their run() function.
365 if (gThreadsStarted
!= 0) {
366 errln("%s:%d gThreadsStarted=%d. Expected 0.", __FILE__
, __LINE__
, gThreadsStarted
);
370 while (gThreadsInMiddle
< TESTMUTEX_THREAD_COUNT
) {
371 if (gThreadsDone
!= 0) {
372 errln("%s:%d gThreadsDone=%d. Expected 0.", __FILE__
, __LINE__
, gThreadsStarted
);
375 umtx_condWait(&gThreadsCountChanged
, &gTestMutexA
);
378 while (gThreadsDone
< TESTMUTEX_THREAD_COUNT
) {
379 umtx_condWait(&gThreadsCountChanged
, &gTestMutexA
);
381 umtx_unlock(&gTestMutexA
);
383 for (i
=0; i
<TESTMUTEX_THREAD_COUNT
; i
++) {
389 //-------------------------------------------------------------------------------------------
391 // TestMultithreadedIntl. Test ICU Formatting in a multi-threaded environment
393 //-------------------------------------------------------------------------------------------
396 // * Show exactly where the string's differences lie.
397 UnicodeString
showDifference(const UnicodeString
& expected
, const UnicodeString
& result
)
400 res
= expected
+ "<Expected\n";
401 if(expected
.length() != result
.length())
402 res
+= " [ Different lengths ] \n";
405 for(int32_t i
=0;i
<expected
.length();i
++)
407 if(expected
[i
] == result
[i
])
416 res
+= "<Differences";
419 res
+= result
+ "<Result\n";
425 //-------------------------------------------------------------------------------------------
427 // FormatThreadTest - a thread that tests performing a number of numberformats.
429 //-------------------------------------------------------------------------------------------
431 const int kFormatThreadIterations
= 100; // # of iterations per thread
432 const int kFormatThreadThreads
= 10; // # of threads to spawn
434 #if !UCONFIG_NO_FORMATTING
438 struct FormatThreadTestData
441 UnicodeString string
;
442 FormatThreadTestData(double a
, const UnicodeString
& b
) : number(a
),string(b
) {}
446 // "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
448 static void formatErrorMessage(UErrorCode
&realStatus
, const UnicodeString
& pattern
, const Locale
& theLocale
,
449 UErrorCode inStatus0
, /* statusString 1 */ const Locale
&inCountry2
, double currency3
, // these numbers are the message arguments.
450 UnicodeString
&result
)
452 if(U_FAILURE(realStatus
))
453 return; // you messed up
455 UnicodeString
errString1(u_errorName(inStatus0
));
457 UnicodeString countryName2
;
458 inCountry2
.getDisplayCountry(theLocale
,countryName2
);
460 Formattable myArgs
[] = {
461 Formattable((int32_t)inStatus0
), // inStatus0 {0}
462 Formattable(errString1
), // statusString1 {1}
463 Formattable(countryName2
), // inCountry2 {2}
464 Formattable(currency3
)// currency3 {3,number,currency}
467 MessageFormat
*fmt
= new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus
);
468 fmt
->setLocale(theLocale
);
469 fmt
->applyPattern(pattern
, realStatus
);
471 if (U_FAILURE(realStatus
)) {
476 FieldPosition ignore
= 0;
477 fmt
->format(myArgs
,4,result
,ignore
,realStatus
);
483 * Shared formatters & data used by instances of ThreadSafeFormat.
484 * Exactly one instance of this class is created, and it is then shared concurrently
485 * by the multiple instances of ThreadSafeFormat.
487 class ThreadSafeFormatSharedData
{
489 ThreadSafeFormatSharedData(UErrorCode
&status
);
490 ~ThreadSafeFormatSharedData();
491 LocalPointer
<NumberFormat
> fFormat
;
492 Formattable fYDDThing
;
493 Formattable fBBDThing
;
494 UnicodeString fYDDStr
;
495 UnicodeString fBBDStr
;
498 const ThreadSafeFormatSharedData
*gSharedData
= NULL
;
500 ThreadSafeFormatSharedData::ThreadSafeFormatSharedData(UErrorCode
&status
) {
501 fFormat
.adoptInstead(NumberFormat::createCurrencyInstance(Locale::getUS(), status
));
502 static const UChar kYDD
[] = { 0x59, 0x44, 0x44, 0x00 };
503 static const UChar kBBD
[] = { 0x42, 0x42, 0x44, 0x00 };
504 fYDDThing
.adoptObject(new CurrencyAmount(123.456, kYDD
, status
));
505 fBBDThing
.adoptObject(new CurrencyAmount(987.654, kBBD
, status
));
506 if (U_FAILURE(status
)) {
509 fFormat
->format(fYDDThing
, fYDDStr
, NULL
, status
);
510 fFormat
->format(fBBDThing
, fBBDStr
, NULL
, status
);
514 ThreadSafeFormatSharedData::~ThreadSafeFormatSharedData() {
519 * Class for thread-safe testing of format.
520 * Instances of this class appear as members of class FormatThreadTest.
521 * Multiple instances of FormatThreadTest coexist.
522 * ThreadSafeFormat::doStuff() is called concurrently to test the thread safety of
523 * various shared format operations.
525 class ThreadSafeFormat
{
527 /* give a unique offset to each thread */
528 ThreadSafeFormat(UErrorCode
&status
);
529 UBool
doStuff(int32_t offset
, UnicodeString
&appendErr
, UErrorCode
&status
) const;
531 LocalPointer
<NumberFormat
> fFormat
; // formatter - en_US constructed currency
535 ThreadSafeFormat::ThreadSafeFormat(UErrorCode
&status
) {
536 fFormat
.adoptInstead(NumberFormat::createCurrencyInstance(Locale::getUS(), status
));
539 static const UChar kUSD
[] = { 0x55, 0x53, 0x44, 0x00 };
541 UBool
ThreadSafeFormat::doStuff(int32_t offset
, UnicodeString
&appendErr
, UErrorCode
&status
) const {
544 if(u_strcmp(fFormat
->getCurrency(), kUSD
)) {
545 appendErr
.append("fFormat currency != ")
548 .append(fFormat
->getCurrency())
553 if(u_strcmp(gSharedData
->fFormat
->getCurrency(), kUSD
)) {
554 appendErr
.append("gFormat currency != ")
557 .append(gSharedData
->fFormat
->getCurrency())
562 const UnicodeString
*o
=NULL
;
564 const NumberFormat
*nf
= NULL
; // only operate on it as const.
566 case 0: f
= gSharedData
->fYDDThing
; o
= &gSharedData
->fYDDStr
; nf
= gSharedData
->fFormat
.getAlias(); break;
567 case 1: f
= gSharedData
->fBBDThing
; o
= &gSharedData
->fBBDStr
; nf
= gSharedData
->fFormat
.getAlias(); break;
568 case 2: f
= gSharedData
->fYDDThing
; o
= &gSharedData
->fYDDStr
; nf
= fFormat
.getAlias(); break;
569 case 3: f
= gSharedData
->fBBDThing
; o
= &gSharedData
->fBBDStr
; nf
= fFormat
.getAlias(); break;
571 nf
->format(f
, str
, NULL
, status
);
574 appendErr
.append(showDifference(*o
, str
));
580 UBool U_CALLCONV
isAcceptable(void *, const char *, const char *, const UDataInfo
*) {
584 //static UMTX debugMutex = NULL;
585 //static UMTX gDebugMutex;
588 class FormatThreadTest
: public SimpleThread
594 LocalPointer
<ThreadSafeFormat
> fTSF
;
596 FormatThreadTest() // constructor is NOT multithread safe.
604 UErrorCode status
= U_ZERO_ERROR
; // TODO: rearrange code to allow checking of status.
605 fTSF
.adoptInstead(new ThreadSafeFormat(status
));
606 static int32_t fgOffset
= 0;
615 LocalPointer
<NumberFormat
> percentFormatter
;
616 UErrorCode status
= U_ZERO_ERROR
;
620 for (int i
=0; i
<4000; i
++) {
621 status
= U_ZERO_ERROR
;
622 UDataMemory
*data1
= udata_openChoice(0, "res", "en_US", isAcceptable
, 0, &status
);
623 UDataMemory
*data2
= udata_openChoice(0, "res", "fr", isAcceptable
, 0, &status
);
626 if (U_FAILURE(status
)) {
627 error("udata_openChoice failed.\n");
637 for (m
=0; m
<4000; m
++) {
638 status
= U_ZERO_ERROR
;
639 UResourceBundle
*res
= NULL
;
640 const char *localeName
= NULL
;
642 Locale loc
= Locale::getEnglish();
644 localeName
= loc
.getName();
645 // localeName = "en";
647 // ResourceBundle bund = ResourceBundle(0, loc, status);
648 //umtx_lock(&gDebugMutex);
649 res
= ures_open(NULL
, localeName
, &status
);
650 //umtx_unlock(&gDebugMutex);
652 //umtx_lock(&gDebugMutex);
654 //umtx_unlock(&gDebugMutex);
656 if (U_FAILURE(status
)) {
657 error("Resource bundle construction failed.\n");
664 // Keep this data here to avoid static initialization.
665 FormatThreadTestData kNumberFormatTestData
[] =
667 FormatThreadTestData((double)5.0, UnicodeString("5", "")),
668 FormatThreadTestData( 6.0, UnicodeString("6", "")),
669 FormatThreadTestData( 20.0, UnicodeString("20", "")),
670 FormatThreadTestData( 8.0, UnicodeString("8", "")),
671 FormatThreadTestData( 8.3, UnicodeString("8.3", "")),
672 FormatThreadTestData( 12345, UnicodeString("12,345", "")),
673 FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")),
675 int32_t kNumberFormatTestDataLength
= UPRV_LENGTHOF(kNumberFormatTestData
);
677 // Keep this data here to avoid static initialization.
678 FormatThreadTestData kPercentFormatTestData
[] =
680 FormatThreadTestData((double)5.0, CharsToUnicodeString("500\\u00a0%")),
681 FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")),
682 FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")),
683 FormatThreadTestData(
684 16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP
685 FormatThreadTestData(
686 81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")),
688 int32_t kPercentFormatTestDataLength
= UPRV_LENGTHOF(kPercentFormatTestData
);
691 status
= U_ZERO_ERROR
;
692 LocalPointer
<NumberFormat
> formatter(NumberFormat::createInstance(Locale::getEnglish(),status
));
693 if(U_FAILURE(status
)) {
694 IntlTest::gTest
->dataerrln("%s:%d Error %s on NumberFormat::createInstance().",
695 __FILE__
, __LINE__
, u_errorName(status
));
696 goto cleanupAndReturn
;
699 percentFormatter
.adoptInstead(NumberFormat::createPercentInstance(Locale::getFrench(),status
));
700 if(U_FAILURE(status
)) {
701 IntlTest::gTest
->errln("%s:%d Error %s on NumberFormat::createPercentInstance().",
702 __FILE__
, __LINE__
, u_errorName(status
));
703 goto cleanupAndReturn
;
706 for(iteration
= 0;!IntlTest::gTest
->getErrors() && iteration
<kFormatThreadIterations
;iteration
++)
709 int32_t whichLine
= (iteration
+ fOffset
)%kNumberFormatTestDataLength
;
711 UnicodeString output
;
713 formatter
->format(kNumberFormatTestData
[whichLine
].number
, output
);
715 if(0 != output
.compare(kNumberFormatTestData
[whichLine
].string
)) {
716 IntlTest::gTest
->errln("format().. expected " + kNumberFormatTestData
[whichLine
].string
718 goto cleanupAndReturn
;
721 // Now check percent.
723 whichLine
= (iteration
+ fOffset
)%kPercentFormatTestDataLength
;
725 percentFormatter
->format(kPercentFormatTestData
[whichLine
].number
, output
);
726 if(0 != output
.compare(kPercentFormatTestData
[whichLine
].string
))
728 IntlTest::gTest
->errln("percent format().. \n" +
729 showDifference(kPercentFormatTestData
[whichLine
].string
,output
));
730 goto cleanupAndReturn
;
733 // Test message error
734 const int kNumberOfMessageTests
= 3;
735 UErrorCode statusToCheck
;
736 UnicodeString patternToCheck
;
737 Locale messageLocale
;
738 Locale countryToCheck
;
739 double currencyToCheck
;
741 UnicodeString expected
;
744 switch((iteration
+fOffset
) % kNumberOfMessageTests
)
748 statusToCheck
= U_FILE_ACCESS_ERROR
;
749 patternToCheck
= "0:Someone from {2} is receiving a #{0}"
750 " error - {1}. Their telephone call is costing "
751 "{3,number,currency}."; // number,currency
752 messageLocale
= Locale("en","US");
753 countryToCheck
= Locale("","HR");
754 currencyToCheck
= 8192.77;
755 expected
= "0:Someone from Croatia is receiving a #4 error - "
756 "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77.";
759 statusToCheck
= U_INDEX_OUTOFBOUNDS_ERROR
;
760 patternToCheck
= "1:A customer in {2} is receiving a #{0} error - {1}. "
761 "Their telephone call is costing {3,number,currency}."; // number,currency
762 messageLocale
= Locale("de","DE@currency=DEM");
763 countryToCheck
= Locale("","BF");
764 currencyToCheck
= 2.32;
765 expected
= CharsToUnicodeString(
766 "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. "
767 "Their telephone call is costing 2,32\\u00A0DM.");
770 statusToCheck
= U_MEMORY_ALLOCATION_ERROR
;
771 patternToCheck
= "2:user in {2} is receiving a #{0} error - {1}. "
772 "They insist they just spent {3,number,currency} "
773 "on memory."; // number,currency
774 messageLocale
= Locale("de","AT@currency=ATS"); // Austrian German
775 countryToCheck
= Locale("","US"); // hmm
776 currencyToCheck
= 40193.12;
777 expected
= CharsToUnicodeString(
778 "2:user in Vereinigte Staaten is receiving a #7 error"
779 " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent"
780 " \\u00f6S\\u00A040.193,12 on memory.");
784 UnicodeString result
;
785 UErrorCode status
= U_ZERO_ERROR
;
786 formatErrorMessage(status
,patternToCheck
,messageLocale
,statusToCheck
,
787 countryToCheck
,currencyToCheck
,result
);
788 if(U_FAILURE(status
))
790 UnicodeString
tmp(u_errorName(status
));
791 IntlTest::gTest
->errln("Failure on message format, pattern=" + patternToCheck
+
793 goto cleanupAndReturn
;
796 if(result
!= expected
)
798 IntlTest::gTest
->errln("PatternFormat: \n" + showDifference(expected
,result
));
799 goto cleanupAndReturn
;
801 // test the Thread Safe Format
802 UnicodeString appendErr
;
803 if(!fTSF
->doStuff(fNum
, appendErr
, status
)) {
804 IntlTest::gTest
->errln(appendErr
);
805 goto cleanupAndReturn
;
807 } /* end of for loop */
816 int32_t fOffset
; // where we are testing from.
819 // ** The actual test function.
821 void MultithreadTest::TestThreadedIntl()
823 UnicodeString theErr
;
825 UErrorCode threadSafeErr
= U_ZERO_ERROR
;
827 ThreadSafeFormatSharedData
sharedData(threadSafeErr
);
828 assertSuccess("initializing ThreadSafeFormat", threadSafeErr
, TRUE
);
831 // Create and start the test threads
833 logln("Spawning: %d threads * %d iterations each.",
834 kFormatThreadThreads
, kFormatThreadIterations
);
835 FormatThreadTest tests
[kFormatThreadThreads
];
837 for(j
= 0; j
< UPRV_LENGTHOF(tests
); j
++) {
839 int32_t threadStatus
= tests
[j
].start();
840 if (threadStatus
!= 0) {
841 errln("%s:%d System Error %d starting thread number %d.",
842 __FILE__
, __LINE__
, threadStatus
, j
);
848 for (j
=0; j
<UPRV_LENGTHOF(tests
); j
++) {
850 logln("Thread # %d is complete..", j
);
853 #endif /* #if !UCONFIG_NO_FORMATTING */
859 //-------------------------------------------------------------------------------------------
861 // Collation threading test
863 //-------------------------------------------------------------------------------------------
864 #if !UCONFIG_NO_COLLATION
866 #define kCollatorThreadThreads 10 // # of threads to spawn
867 #define kCollatorThreadPatience kCollatorThreadThreads*30
875 skipLineBecauseOfBug(const UChar
*s
, int32_t length
) {
876 // TODO: Fix ICU ticket #8052
878 (s
[0] == 0xfb2 || s
[0] == 0xfb3) &&
880 (s
[2] == 0xf73 || s
[2] == 0xf75 || s
[2] == 0xf81)) {
886 static UCollationResult
887 normalizeResult(int32_t result
) {
888 return result
<0 ? UCOL_LESS
: result
==0 ? UCOL_EQUAL
: UCOL_GREATER
;
891 class CollatorThreadTest
: public SimpleThread
894 const Collator
*coll
;
897 UBool isAtLeastUCA62
;
899 CollatorThreadTest() : SimpleThread(),
906 void setCollator(Collator
*c
, Line
*l
, int32_t nl
, UBool atLeastUCA62
)
911 isAtLeastUCA62
= atLeastUCA62
;
914 uint8_t sk1
[1024], sk2
[1024];
915 uint8_t *oldSk
= NULL
, *newSk
= sk1
;
920 for(i
= 0; i
< noLines
; i
++) {
921 if(lines
[i
].buflen
== 0) { continue; }
923 if(skipLineBecauseOfBug(lines
[i
].buff
, lines
[i
].buflen
)) { continue; }
925 int32_t resLen
= coll
->getSortKey(lines
[i
].buff
, lines
[i
].buflen
, newSk
, 1024);
928 int32_t skres
= strcmp((char *)oldSk
, (char *)newSk
);
929 int32_t cmpres
= coll
->compare(lines
[prev
].buff
, lines
[prev
].buflen
, lines
[i
].buff
, lines
[i
].buflen
);
930 int32_t cmpres2
= coll
->compare(lines
[i
].buff
, lines
[i
].buflen
, lines
[prev
].buff
, lines
[prev
].buflen
);
932 if(cmpres
!= -cmpres2
) {
933 IntlTest::gTest
->errln(UnicodeString("Compare result not symmetrical on line ") + (i
+ 1));
937 if(cmpres
!= normalizeResult(skres
)) {
938 IntlTest::gTest
->errln(UnicodeString("Difference between coll->compare and sortkey compare on line ") + (i
+ 1));
942 int32_t res
= cmpres
;
943 if(res
== 0 && !isAtLeastUCA62
) {
944 // Up to UCA 6.1, the collation test files use a custom tie-breaker,
945 // comparing the raw input strings.
946 res
= u_strcmpCodePointOrder(lines
[prev
].buff
, lines
[i
].buff
);
947 // Starting with UCA 6.2, the collation test files use the standard UCA tie-breaker,
948 // comparing the NFD versions of the input strings,
949 // which we do via setting strength=identical.
952 IntlTest::gTest
->errln(UnicodeString("Line is not greater or equal than previous line, for line ") + (i
+ 1));
959 (void)oldLen
; // Suppress set but not used warning.
962 newSk
= (newSk
== sk1
)?sk2
:sk1
;
967 void MultithreadTest::TestCollators()
970 UErrorCode status
= U_ZERO_ERROR
;
971 FILE *testFile
= NULL
;
972 char testDataPath
[1024];
973 strcpy(testDataPath
, IntlTest::getSourceTestData(status
));
974 if (U_FAILURE(status
)) {
975 errln("ERROR: could not open test data %s", u_errorName(status
));
978 strcat(testDataPath
, "CollationTest_");
980 const char* type
= "NON_IGNORABLE";
982 const char *ext
= ".txt";
987 strcpy(buffer
, testDataPath
);
988 strcat(buffer
, type
);
989 size_t bufLen
= strlen(buffer
);
991 // we try to open 3 files:
992 // path/CollationTest_type.txt
993 // path/CollationTest_type_SHORT.txt
994 // path/CollationTest_type_STUB.txt
995 // we are going to test with the first one that we manage to open.
997 strcpy(buffer
+bufLen
, ext
);
999 testFile
= fopen(buffer
, "rb");
1002 strcpy(buffer
+bufLen
, "_SHORT");
1003 strcat(buffer
, ext
);
1004 testFile
= fopen(buffer
, "rb");
1007 strcpy(buffer
+bufLen
, "_STUB");
1008 strcat(buffer
, ext
);
1009 testFile
= fopen(buffer
, "rb");
1011 if (testFile
== 0) {
1012 *(buffer
+bufLen
) = 0;
1013 dataerrln("could not open any of the conformance test files, tried opening base %s", buffer
);
1017 "INFO: Working with the stub file.\n"
1018 "If you need the full conformance test, please\n"
1019 "download the appropriate data files from:\n"
1020 "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/");
1025 LocalArray
<Line
> lines(new Line
[200000]);
1026 memset(lines
.getAlias(), 0, sizeof(Line
)*200000);
1027 int32_t lineNum
= 0;
1029 UChar bufferU
[1024];
1032 while (fgets(buffer
, 1024, testFile
) != NULL
) {
1033 if(*buffer
== 0 || buffer
[0] == '#') {
1034 // Store empty and comment lines so that errors are reported
1035 // for the real test file lines.
1036 lines
[lineNum
].buflen
= 0;
1037 lines
[lineNum
].buff
[0] = 0;
1039 int32_t buflen
= u_parseString(buffer
, bufferU
, 1024, &first
, &status
);
1040 lines
[lineNum
].buflen
= buflen
;
1041 u_memcpy(lines
[lineNum
].buff
, bufferU
, buflen
);
1042 lines
[lineNum
].buff
[buflen
] = 0;
1047 if(U_FAILURE(status
)) {
1048 dataerrln("Couldn't read the test file!");
1052 UVersionInfo uniVersion
;
1053 static const UVersionInfo v62
= { 6, 2, 0, 0 };
1054 u_getUnicodeVersion(uniVersion
);
1055 UBool isAtLeastUCA62
= uprv_memcmp(uniVersion
, v62
, 4) >= 0;
1057 LocalPointer
<Collator
> coll(Collator::createInstance(Locale::getRoot(), status
));
1058 if(U_FAILURE(status
)) {
1059 errcheckln(status
, "Couldn't open UCA collator");
1062 coll
->setAttribute(UCOL_NORMALIZATION_MODE
, UCOL_ON
, status
);
1063 coll
->setAttribute(UCOL_CASE_FIRST
, UCOL_OFF
, status
);
1064 coll
->setAttribute(UCOL_CASE_LEVEL
, UCOL_OFF
, status
);
1065 coll
->setAttribute(UCOL_STRENGTH
, isAtLeastUCA62
? UCOL_IDENTICAL
: UCOL_TERTIARY
, status
);
1066 coll
->setAttribute(UCOL_ALTERNATE_HANDLING
, UCOL_NON_IGNORABLE
, status
);
1068 int32_t spawnResult
= 0;
1069 LocalArray
<CollatorThreadTest
> tests(new CollatorThreadTest
[kCollatorThreadThreads
]);
1071 logln(UnicodeString("Spawning: ") + kCollatorThreadThreads
+ " threads * " + kFormatThreadIterations
+ " iterations each.");
1073 for(j
= 0; j
< kCollatorThreadThreads
; j
++) {
1074 //logln("Setting collator %i", j);
1075 tests
[j
].setCollator(coll
.getAlias(), lines
.getAlias(), lineNum
, isAtLeastUCA62
);
1077 for(j
= 0; j
< kCollatorThreadThreads
; j
++) {
1079 spawnResult
= tests
[j
].start();
1080 if(spawnResult
!= 0) {
1081 errln("%s:%d THREAD INFO: thread %d failed to start with status %d", __FILE__
, __LINE__
, j
, spawnResult
);
1085 logln("Spawned all");
1087 for(int32_t i
=0;i
<kCollatorThreadThreads
;i
++) {
1089 //logln(UnicodeString("Test #") + i + " is complete.. ");
1093 #endif /* #if !UCONFIG_NO_COLLATION */
1098 //-------------------------------------------------------------------------------------------
1100 // StringThreadTest2
1102 //-------------------------------------------------------------------------------------------
1104 const int kStringThreadIterations
= 2500;// # of iterations per thread
1105 const int kStringThreadThreads
= 10; // # of threads to spawn
1108 class StringThreadTest2
: public SimpleThread
1113 static const UnicodeString
*gSharedString
;
1115 StringThreadTest2() // constructor is NOT multithread safe.
1127 for (loopCount
= 0; loopCount
< kStringThreadIterations
; loopCount
++) {
1128 if (*gSharedString
!= "This is the original test string.") {
1129 IntlTest::gTest
->errln("%s:%d Original string is corrupt.", __FILE__
, __LINE__
);
1132 UnicodeString s1
= *gSharedString
;
1134 UnicodeString
s2(s1
);
1135 UnicodeString s3
= *gSharedString
;
1146 const UnicodeString
*StringThreadTest2::gSharedString
= NULL
;
1148 // ** The actual test function.
1151 void MultithreadTest::TestString()
1154 StringThreadTest2::gSharedString
= new UnicodeString("This is the original test string.");
1155 StringThreadTest2 tests
[kStringThreadThreads
];
1157 logln(UnicodeString("Spawning: ") + kStringThreadThreads
+ " threads * " + kStringThreadIterations
+ " iterations each.");
1158 for(j
= 0; j
< kStringThreadThreads
; j
++) {
1159 int32_t threadStatus
= tests
[j
].start();
1160 if (threadStatus
!= 0) {
1161 errln("%s:%d System Error %d starting thread number %d.", __FILE__
, __LINE__
, threadStatus
, j
);
1165 // Force a failure, to verify test is functioning and can report errors.
1166 // const_cast<UnicodeString *>(StringThreadTest2::gSharedString)->setCharAt(5, 'x');
1168 for(j
=0; j
<kStringThreadThreads
; j
++) {
1170 logln(UnicodeString("Test #") + j
+ " is complete.. ");
1173 delete StringThreadTest2::gSharedString
;
1174 StringThreadTest2::gSharedString
= NULL
;
1179 // Test for ticket #10673, race in cache code in AnyTransliterator.
1180 // It's difficult to make the original unsafe code actually fail, but
1181 // this test will fairly reliably take the code path for races in
1182 // populating the cache.
1185 #if !UCONFIG_NO_TRANSLITERATION
1186 Transliterator
*gSharedTranslit
= NULL
;
1187 class TxThread
: public SimpleThread
{
1194 TxThread::~TxThread() {}
1195 void TxThread::run() {
1196 UnicodeString
greekString("\\u03B4\\u03B9\\u03B1\\u03C6\\u03BF\\u03C1\\u03B5\\u03C4\\u03B9\\u03BA\\u03BF\\u03CD\\u03C2");
1197 greekString
= greekString
.unescape();
1198 gSharedTranslit
->transliterate(greekString
);
1199 if (greekString
[0] != 0x64) // 'd'. The whole transliterated string is "diaphoretikous" (accented u).
1201 IntlTest::gTest
->errln("%s:%d Transliteration failed.", __FILE__
, __LINE__
);
1207 void MultithreadTest::TestAnyTranslit() {
1208 #if !UCONFIG_NO_TRANSLITERATION
1209 UErrorCode status
= U_ZERO_ERROR
;
1210 LocalPointer
<Transliterator
> tx(Transliterator::createInstance("Any-Latin", UTRANS_FORWARD
, status
));
1211 if (U_FAILURE(status
)) {
1212 dataerrln("File %s, Line %d: Error, status = %s", __FILE__
, __LINE__
, u_errorName(status
));
1215 gSharedTranslit
= tx
.getAlias();
1216 TxThread threads
[4];
1218 for (i
=0; i
<UPRV_LENGTHOF(threads
); i
++) {
1222 for (i
=0; i
<UPRV_LENGTHOF(threads
); i
++) {
1225 gSharedTranslit
= NULL
;
1226 #endif // !UCONFIG_NO_TRANSLITERATION
1231 // Condition Variables Test
1232 // Create a swarm of threads.
1233 // Using a mutex and a condition variables each thread
1234 // Increments a global count of started threads.
1235 // Broadcasts that it has started.
1236 // Waits on the condition that all threads have started.
1237 // Increments a global count of finished threads.
1238 // Waits on the condition that all threads have finished.
1242 class CondThread
: public SimpleThread
{
1244 CondThread() :fFinished(false) {};
1250 static UMutex gCTMutex
= U_MUTEX_INITIALIZER
;
1251 static UConditionVar gCTConditionVar
= U_CONDITION_INITIALIZER
;
1252 int gConditionTestOne
= 1; // Value one. Non-const, extern linkage to inhibit
1253 // compiler assuming a known value.
1254 int gStartedThreads
;
1255 int gFinishedThreads
;
1256 static const int NUMTHREADS
= 10;
1259 // Worker thread function.
1260 void CondThread::run() {
1261 umtx_lock(&gCTMutex
);
1262 gStartedThreads
+= gConditionTestOne
;
1263 umtx_condBroadcast(&gCTConditionVar
);
1265 while (gStartedThreads
< NUMTHREADS
) {
1266 if (gFinishedThreads
!= 0) {
1267 IntlTest::gTest
->errln("File %s, Line %d: Error, gStartedThreads = %d, gFinishedThreads = %d",
1268 __FILE__
, __LINE__
, gStartedThreads
, gFinishedThreads
);
1270 umtx_condWait(&gCTConditionVar
, &gCTMutex
);
1273 gFinishedThreads
+= gConditionTestOne
;
1275 umtx_condBroadcast(&gCTConditionVar
);
1277 while (gFinishedThreads
< NUMTHREADS
) {
1278 umtx_condWait(&gCTConditionVar
, &gCTMutex
);
1280 umtx_unlock(&gCTMutex
);
1283 void MultithreadTest::TestConditionVariables() {
1284 gStartedThreads
= 0;
1285 gFinishedThreads
= 0;
1288 umtx_lock(&gCTMutex
);
1289 CondThread
*threads
[NUMTHREADS
];
1290 for (i
=0; i
<NUMTHREADS
; ++i
) {
1291 threads
[i
] = new CondThread
;
1292 threads
[i
]->start();
1295 while (gStartedThreads
< NUMTHREADS
) {
1296 umtx_condWait(&gCTConditionVar
, &gCTMutex
);
1299 while (gFinishedThreads
< NUMTHREADS
) {
1300 umtx_condWait(&gCTConditionVar
, &gCTMutex
);
1303 umtx_unlock(&gCTMutex
);
1305 for (i
=0; i
<NUMTHREADS
; ++i
) {
1306 if (!threads
[i
]->fFinished
) {
1307 errln("File %s, Line %d: Error, threads[%d]->fFinished == false", __FILE__
, __LINE__
, i
);
1311 for (i
=0; i
<NUMTHREADS
; ++i
) {
1319 // Unified Cache Test
1322 // Each thread fetches a pair of objects. There are 8 distinct pairs:
1323 // ("en_US", "bs"), ("en_GB", "ca"), ("fr_FR", "ca_AD") etc.
1324 // These pairs represent 8 distinct languages
1326 // Note that only one value per language gets created in the cache.
1327 // In particular each cached value can have multiple keys.
1328 static const char *gCacheLocales
[] = {
1329 "en_US", "en_GB", "fr_FR", "fr",
1330 "de", "sr_ME", "sr_BA", "sr_CS"};
1331 static const char *gCacheLocales2
[] = {
1332 "bs", "ca", "ca_AD", "ca_ES",
1333 "en_US", "fi", "ff_CM", "ff_GN"};
1335 static int32_t gObjectsCreated
= 0; // protected by gCTMutex
1336 static const int32_t CACHE_LOAD
= 3;
1338 class UCTMultiThreadItem
: public SharedObject
{
1341 UCTMultiThreadItem(const char *x
) : value(NULL
) {
1342 value
= uprv_strdup(x
);
1344 virtual ~UCTMultiThreadItem() {
1352 const UCTMultiThreadItem
*LocaleCacheKey
<UCTMultiThreadItem
>::createObject(
1353 const void *context
, UErrorCode
&status
) const {
1354 const UnifiedCache
*cacheContext
= (const UnifiedCache
*) context
;
1356 if (uprv_strcmp(fLoc
.getLanguage(), fLoc
.getName()) != 0) {
1357 const UCTMultiThreadItem
*result
= NULL
;
1358 if (cacheContext
== NULL
) {
1359 UnifiedCache::getByLocale(fLoc
.getLanguage(), result
, status
);
1362 cacheContext
->get(LocaleCacheKey
<UCTMultiThreadItem
>(fLoc
.getLanguage()), result
, status
);
1366 umtx_lock(&gCTMutex
);
1367 bool firstObject
= (gObjectsCreated
== 0);
1369 // Force the first object creation that comes through to wait
1370 // until other have completed. Verifies that cache doesn't
1371 // deadlock when a creation is slow.
1373 // Note that gObjectsCreated needs to be incremeneted from 0 to 1
1374 // early, to keep subsequent threads from entering this path.
1375 gObjectsCreated
= 1;
1376 while (gObjectsCreated
< 3) {
1377 umtx_condWait(&gCTConditionVar
, &gCTMutex
);
1380 umtx_unlock(&gCTMutex
);
1382 const UCTMultiThreadItem
*result
=
1383 new UCTMultiThreadItem(fLoc
.getLanguage());
1384 if (result
== NULL
) {
1385 status
= U_MEMORY_ALLOCATION_ERROR
;
1390 // Log that we created an object. The first object was already counted,
1391 // don't do it again.
1392 umtx_lock(&gCTMutex
);
1394 gObjectsCreated
+= 1;
1396 umtx_condBroadcast(&gCTConditionVar
);
1397 umtx_unlock(&gCTMutex
);
1404 class UnifiedCacheThread
: public SimpleThread
{
1407 const UnifiedCache
*cache
,
1409 const char *loc2
) : fCache(cache
), fLoc(loc
), fLoc2(loc2
) {};
1410 ~UnifiedCacheThread() {};
1412 void exerciseByLocale(const Locale
&);
1413 const UnifiedCache
*fCache
;
1418 void UnifiedCacheThread::exerciseByLocale(const Locale
&locale
) {
1419 UErrorCode status
= U_ZERO_ERROR
;
1420 const UCTMultiThreadItem
*origItem
= NULL
;
1422 LocaleCacheKey
<UCTMultiThreadItem
>(locale
), fCache
, origItem
, status
);
1423 U_ASSERT(U_SUCCESS(status
));
1424 if (uprv_strcmp(locale
.getLanguage(), origItem
->value
)) {
1425 IntlTest::gTest
->errln(
1426 "%s:%d Expected %s, got %s", __FILE__
, __LINE__
,
1427 locale
.getLanguage(),
1431 // Fetch the same item again many times. We should always get the same
1432 // pointer since this client is already holding onto it
1433 for (int32_t i
= 0; i
< 1000; ++i
) {
1434 const UCTMultiThreadItem
*item
= NULL
;
1436 LocaleCacheKey
<UCTMultiThreadItem
>(locale
), fCache
, item
, status
);
1437 if (item
!= origItem
) {
1438 IntlTest::gTest
->errln(
1439 "%s:%d Expected to get the same pointer",
1447 origItem
->removeRef();
1450 void UnifiedCacheThread::run() {
1451 // Run the exercise with 2 different locales so that we can exercise
1452 // eviction more. If each thread exerices just one locale, then
1453 // eviction can't start until the threads end.
1454 exerciseByLocale(fLoc
);
1455 exerciseByLocale(fLoc2
);
1458 void MultithreadTest::TestUnifiedCache() {
1460 // Start with our own local cache so that we have complete control
1461 // and set the eviction policy to evict starting with 2 unused
1463 UErrorCode status
= U_ZERO_ERROR
;
1464 UnifiedCache::getInstance(status
);
1465 UnifiedCache
cache(status
);
1466 cache
.setEvictionPolicy(2, 0, status
);
1467 U_ASSERT(U_SUCCESS(status
));
1469 gFinishedThreads
= 0;
1470 gObjectsCreated
= 0;
1472 UnifiedCacheThread
*threads
[CACHE_LOAD
][UPRV_LENGTHOF(gCacheLocales
)];
1473 for (int32_t i
=0; i
<CACHE_LOAD
; ++i
) {
1474 for (int32_t j
=0; j
<UPRV_LENGTHOF(gCacheLocales
); ++j
) {
1475 // Each thread works with a pair of locales.
1476 threads
[i
][j
] = new UnifiedCacheThread(
1477 &cache
, gCacheLocales
[j
], gCacheLocales2
[j
]);
1478 threads
[i
][j
]->start();
1482 for (int32_t i
=0; i
<CACHE_LOAD
; ++i
) {
1483 for (int32_t j
=0; j
<UPRV_LENGTHOF(gCacheLocales
); ++j
) {
1484 threads
[i
][j
]->join();
1487 // Because of cache eviction, we can't assert exactly how many
1488 // distinct objects get created over the course of this run.
1489 // However we know that at least 8 objects get created because that
1490 // is how many distinct languages we have in our test.
1491 if (gObjectsCreated
< 8) {
1492 errln("%s:%d Too few objects created.", __FILE__
, __LINE__
);
1494 // We know that each thread cannot create more than 2 objects in
1495 // the cache, and there are UPRV_LENGTHOF(gCacheLocales) pairs of
1496 // objects fetched from the cache. If the threads run in series because
1497 // of eviction, at worst case each thread creates two objects.
1498 if (gObjectsCreated
> 2 * CACHE_LOAD
* UPRV_LENGTHOF(gCacheLocales
)) {
1499 errln("%s:%d Too many objects created, got %d, expected %d", __FILE__
, __LINE__
, gObjectsCreated
, 2 * CACHE_LOAD
* UPRV_LENGTHOF(gCacheLocales
));
1503 assertEquals("unused values", 2, cache
.unusedCount());
1506 for (int32_t i
=0; i
<CACHE_LOAD
; ++i
) {
1507 for (int32_t j
=0; j
<UPRV_LENGTHOF(gCacheLocales
); ++j
) {
1508 delete threads
[i
][j
];
1513 #if !UCONFIG_NO_TRANSLITERATION
1515 // BreakTransliterator Threading Test
1516 // This is a test for bug #11603. Test verified to fail prior to fix.
1519 static const Transliterator
*gSharedTransliterator
;
1520 static const UnicodeString
*gTranslitInput
;
1521 static const UnicodeString
*gTranslitExpected
;
1523 class BreakTranslitThread
: public SimpleThread
{
1525 BreakTranslitThread() {};
1526 ~BreakTranslitThread() {};
1530 void BreakTranslitThread::run() {
1531 for (int i
=0; i
<10; i
++) {
1532 icu::UnicodeString
s(*gTranslitInput
);
1533 gSharedTransliterator
->transliterate(s
);
1534 if (*gTranslitExpected
!= s
) {
1535 IntlTest::gTest
->errln("%s:%d Transliteration threading failure.", __FILE__
, __LINE__
);
1541 void MultithreadTest::TestBreakTranslit() {
1542 UErrorCode status
= U_ZERO_ERROR
;
1543 UnicodeString
input(
1544 "\\u0E42\\u0E14\\u0E22\\u0E1E\\u0E37\\u0E49\\u0E19\\u0E10\\u0E32\\u0E19\\u0E41\\u0E25\\u0E49\\u0E27,");
1545 input
= input
.unescape();
1546 gTranslitInput
= &input
;
1548 gSharedTransliterator
= Transliterator::createInstance(
1549 UNICODE_STRING_SIMPLE("Any-Latin; Lower; NFD; [:Diacritic:]Remove; NFC; Latin-ASCII;"), UTRANS_FORWARD
, status
);
1550 if (!gSharedTransliterator
) {
1553 TSMTHREAD_ASSERT_SUCCESS(status
);
1555 UnicodeString
expected(*gTranslitInput
);
1556 gSharedTransliterator
->transliterate(expected
);
1557 gTranslitExpected
= &expected
;
1559 BreakTranslitThread threads
[4];
1560 for (int i
=0; i
<UPRV_LENGTHOF(threads
); ++i
) {
1563 for (int i
=0; i
<UPRV_LENGTHOF(threads
); ++i
) {
1567 delete gSharedTransliterator
;
1568 gTranslitInput
= NULL
;
1569 gTranslitExpected
= NULL
;
1572 #endif /* !UCONFIG_NO_TRANSLITERATION */