]> git.saurik.com Git - apple/icu.git/blame - icuSources/test/intltest/tsmthred.cpp
ICU-3.13.tar.gz
[apple/icu.git] / icuSources / test / intltest / tsmthred.cpp
CommitLineData
b75a7d8f
A
1/********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1999-2003, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
6
7#if defined(hpux)
8# ifndef _INCLUDE_POSIX_SOURCE
9# define _INCLUDE_POSIX_SOURCE
10# endif
11#endif
12
13#include <unicode/umachine.h>
14
15// Just turn off threads on cygwin, so that we can test
16// the other stuff. This needs to be investigated further.
17#if defined(U_CYGWIN)
18#define ICU_USE_THREADS 0
19#endif
20
21#if !defined(WIN32) && !defined(XP_MAC) && !defined(U_RHAPSODY)
22#define POSIX 1
23#endif
24
25#if defined(POSIX) || defined(U_SOLARIS) || defined(AIX) || defined(HPUX)
26
27#define HAVE_IMP
28
29#if (ICU_USE_THREADS == 1)
30#include <pthread.h>
31#endif
32
33#if defined(__hpux) && defined(HPUX_CMA)
34# if defined(read) // read being defined as cma_read causes trouble with iostream::read
35# undef read
36# endif
37#endif
38
39/* Define __EXTENSIONS__ for Solaris and old friends in strict mode. */
40#ifndef __EXTENSIONS__
41#define __EXTENSIONS__
42#endif
43
44#include <signal.h>
45
46/* Define _XPG4_2 for Solaris and friends. */
47#ifndef _XPG4_2
48#define _XPG4_2
49#endif
50
51/* Define __USE_XOPEN_EXTENDED for Linux and glibc. */
52#ifndef __USE_XOPEN_EXTENDED
53#define __USE_XOPEN_EXTENDED
54#endif
55
56/* Define _INCLUDE_XOPEN_SOURCE_EXTENDED for HP/UX (11?). */
57#ifndef _INCLUDE_XOPEN_SOURCE_EXTENDED
58#define _INCLUDE_XOPEN_SOURCE_EXTENDED
59#endif
60
61#include <unistd.h>
62
63#endif
64/* HPUX */
65#ifdef sleep
66#undef sleep
67#endif
68
69#include "unicode/utypes.h"
70
71/* APP_NO_THREADS is an old symbol. We'll honour it if present. */
72#ifdef APP_NO_THREADS
73# define ICU_USE_THREADS 0
74#endif
75
76/* Default: use threads. */
77#ifndef ICU_USE_THREADS
78# define ICU_USE_THREADS 1
79#endif
80
81#include "tsmthred.h"
82
83
84MultithreadTest::MultithreadTest()
85{
86}
87
88MultithreadTest::~MultithreadTest()
89{
90}
91
92
93
94#if (ICU_USE_THREADS==0)
95void MultithreadTest::runIndexedTest( int32_t index, UBool exec,
96 const char* &name, char* par ) {
97 if (exec) logln("TestSuite MultithreadTest: ");
98
99 if(index == 0)
100 name = "NO_THREADED_TESTS";
101 else
102 name = "";
103
104 if(exec) { logln("MultithreadTest - test DISABLED. ICU_USE_THREADS set to 0, check your configuration if this is a problem..");
105 }
106}
107#else
108
109
110
111// Note: A LOT OF THE FUNCTIONS IN THIS FILE SHOULD LIVE ELSEWHERE!!!!!
112// Note: A LOT OF THE FUNCTIONS IN THIS FILE SHOULD LIVE ELSEWHERE!!!!!
113// -srl
114
115#include <stdio.h>
116#include <string.h>
117#include <ctype.h> // tolower, toupper
118
119#include "unicode/putil.h"
120
121/* for mthreadtest*/
122#include "unicode/numfmt.h"
123#include "unicode/choicfmt.h"
124#include "unicode/msgfmt.h"
125#include "unicode/locid.h"
126#include "unicode/ucol.h"
127#include "ucaconf.h"
128
129#ifdef WIN32
130#define HAVE_IMP
131
132# define VC_EXTRALEAN
133# define WIN32_LEAN_AND_MEAN
134# define NOGDI
135# define NOUSER
136# define NOSERVICE
137# define NOIME
138# define NOMCX
139#include <windows.h>
140#include <process.h>
141
142struct Win32ThreadImplementation
143{
144 unsigned long fHandle;
145};
146
147extern "C" void __cdecl SimpleThreadProc(void *arg)
148{
149 ((SimpleThread*)arg)->run();
150}
151
152SimpleThread::SimpleThread()
153:fImplementation(0)
154{
155 Win32ThreadImplementation *imp = new Win32ThreadImplementation;
156 imp->fHandle = 0;
157
158 fImplementation = imp;
159}
160
161SimpleThread::~SimpleThread()
162{
163 delete (Win32ThreadImplementation*)fImplementation;
164}
165
166int32_t SimpleThread::start()
167{
168 Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation;
169 if(imp->fHandle != NULL) {
170 // The thread appears to have already been started.
171 // This is probably an error on the part of our caller.
172 return -1;
173 }
174
175 imp->fHandle = _beginthread( SimpleThreadProc, 0 /*stack size*/ , (void *)this );
176 if (imp->fHandle == -1) {
177 // An error occured
178 int err = errno;
179 if (err == 0) {
180 err = -1;
181 }
182 return err;
183 }
184 return 0;
185}
186
187void SimpleThread::sleep(int32_t millis)
188{
189 ::Sleep(millis);
190}
191
192#elif defined XP_MAC
193
194// since the Mac has no preemptive threading (at least on MacOS 8), only
195// cooperative threading, threads are a no-op. We have no yield() calls
196// anywhere in the ICU, so we are guaranteed to be thread-safe.
197
198#define HAVE_IMP
199
200SimpleThread::SimpleThread()
201{}
202
203SimpleThread::~SimpleThread()
204{}
205
206int32_t
207SimpleThread::start()
208{ return 0; }
209
210void
211SimpleThread::run()
212{}
213
214void
215SimpleThread::sleep(int32_t millis)
216{}
217#endif
218
219
220#if defined(POSIX)||defined(U_SOLARIS)||defined(AIX)||defined(HPUX)
221#define HAVE_IMP
222
223struct PosixThreadImplementation
224{
225 pthread_t fThread;
226};
227
228extern "C" void* SimpleThreadProc(void *arg)
229{
230 ((SimpleThread*)arg)->run();
231 return 0;
232}
233
234SimpleThread::SimpleThread() :fImplementation(0)
235{
236 PosixThreadImplementation *imp = new PosixThreadImplementation;
237 fImplementation = imp;
238}
239
240SimpleThread::~SimpleThread()
241{
242 delete (PosixThreadImplementation*)fImplementation;
243}
244
245int32_t SimpleThread::start()
246{
247 PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation;
248
249 int32_t rc;
250
251 pthread_attr_t attr;
252
253#ifdef HPUX_CMA
254 rc = pthread_attr_create(&attr);
255 rc = pthread_create(&(imp->fThread),attr,&SimpleThreadProc,(void*)this);
256 pthread_attr_delete(&attr);
257#else
258 rc = pthread_attr_init(&attr);
259 rc = pthread_create(&(imp->fThread),&attr,&SimpleThreadProc,(void*)this);
260 pthread_attr_destroy(&attr);
261#endif
262 return rc;
263
264}
265
266void SimpleThread::sleep(int32_t millis)
267{
268#ifdef U_SOLARIS
269 sigignore(SIGALRM);
270#endif
271
272#ifdef HPUX_CMA
273 cma_sleep(millis/100);
274#elif defined(HPUX) || defined(OS390)
275 millis *= 1000;
276 while(millis >= 1000000) {
277 usleep(999999);
278 millis -= 1000000;
279 }
280 if(millis > 0) {
281 usleep(millis);
282 }
283#else
284 usleep(millis * 1000);
285#endif
286}
287
288#endif
289// end POSIX
290
291
292#ifndef HAVE_IMP
293#error No implementation for threads! Cannot test.
2940 = 216; //die
295#endif
296
297
298// *************** end fluff ******************
299
300/* now begins the real test. */
301void MultithreadTest::runIndexedTest( int32_t index, UBool exec,
302 const char* &name, char* /*par*/ ) {
303 if (exec)
304 logln("TestSuite MultithreadTest: ");
305 switch (index) {
306 case 0:
307 name = "TestThreads";
308 if (exec)
309 TestThreads();
310 break;
311 case 1:
312 name = "TestMutex";
313 if (exec)
314 TestMutex();
315 break;
316 case 2:
317 name = "TestThreadedIntl";
318#if !UCONFIG_NO_FORMATTING
319 if (exec)
320 TestThreadedIntl();
321#endif
322 break;
323 case 3:
324 name = "TestCollators";
325#if !UCONFIG_NO_COLLATION
326 if (exec)
327 TestCollators();
328#endif /* #if !UCONFIG_NO_COLLATION */
329 break;
330 default:
331 name = "";
332 break; //needed to end loop
333 }
334}
335
336
337/*
338 TestThreads -- see if threads really work at all.
339
340 Set up N threads pointing at N chars. When they are started, they will
341 each sleep 1 second and then set their chars. At the end we make sure they
342 are all set.
343 */
344
345#define THREADTEST_NRTHREADS 8
346
347class TestThreadsThread : public SimpleThread
348{
349public:
350 TestThreadsThread(char* whatToChange) { fWhatToChange = whatToChange; }
351 virtual void run() { SimpleThread::sleep(1000);
352 Mutex m;
353 *fWhatToChange = '*';
354 }
355private:
356 char *fWhatToChange;
357};
358
359void MultithreadTest::TestThreads()
360{
361 char threadTestChars[THREADTEST_NRTHREADS + 1];
362 SimpleThread *threads[THREADTEST_NRTHREADS];
363
364 int32_t i;
365 for(i=0;i<THREADTEST_NRTHREADS;i++)
366 {
367 threadTestChars[i] = ' ';
368 threads[i] = new TestThreadsThread(&threadTestChars[i]);
369 }
370 threadTestChars[THREADTEST_NRTHREADS] = '\0';
371
372 logln("->" + UnicodeString(threadTestChars) + "<- Firing off threads.. ");
373 for(i=0;i<THREADTEST_NRTHREADS;i++)
374 {
375 if (threads[i]->start() != 0) {
376 errln("Error starting thread %d", i);
377 }
378 SimpleThread::sleep(200);
379 logln(" Subthread started.");
380 }
381
382 logln("Waiting for threads to be set..");
383
384 int32_t patience = 40; // seconds to wait
385
386 while(patience--)
387 {
388 int32_t count = 0;
389 umtx_lock(NULL);
390 for(i=0;i<THREADTEST_NRTHREADS;i++)
391 {
392 if(threadTestChars[i] == '*')
393 {
394 count++;
395 }
396 }
397 umtx_unlock(NULL);
398
399 if(count == THREADTEST_NRTHREADS)
400 {
401 logln("->" + UnicodeString(threadTestChars) + "<- Got all threads! cya");
402 for(i=0;i<THREADTEST_NRTHREADS;i++)
403 {
404 delete threads[i];
405 }
406 return;
407 }
408
409 logln("->" + UnicodeString(threadTestChars) + "<- Waiting..");
410 SimpleThread::sleep(500);
411 }
412
413 errln("->" + UnicodeString(threadTestChars) + "<- PATIENCE EXCEEDED!! Still missing some.");
414 for(i=0;i<THREADTEST_NRTHREADS;i++)
415 {
416 delete threads[i];
417 }
418}
419
420
421class TestMutexThread1 : public SimpleThread
422{
423public:
424 TestMutexThread1() : fDone(FALSE) {}
425 virtual void run()
426 {
427 Mutex m; // grab the lock first thing
428 SimpleThread::sleep(900); // then wait
429 fDone = TRUE; // finally, set our flag
430 }
431public:
432 UBool fDone;
433};
434
435class TestMutexThread2 : public SimpleThread
436{
437public:
438 TestMutexThread2(TestMutexThread1& r) : fOtherThread(r), fDone(FALSE), fErr(FALSE) {}
439 virtual void run()
440 {
441 SimpleThread::sleep(500); // wait, make sure they aquire the lock
442 fElapsed = uprv_getUTCtime();
443 {
444 Mutex m; // wait here
445
446 fElapsed = uprv_getUTCtime() - fElapsed;
447
448 if(fOtherThread.fDone == FALSE)
449 fErr = TRUE; // they didnt get to it yet
450
451 fDone = TRUE; // we're done.
452 }
453 }
454public:
455 TestMutexThread1 & fOtherThread;
456 UBool fDone, fErr;
457 int32_t fElapsed;
458private:
459 /**
460 * The assignment operator has no real implementation.
461 * It is provided to make the compiler happy. Do not call.
462 */
463 TestMutexThread2& operator=(const TestMutexThread2&) { return *this; }
464};
465
466void MultithreadTest::TestMutex()
467{
468 /* this test uses printf so that we don't hang by calling UnicodeString inside of a mutex. */
469 //logln("Bye.");
470 // printf("Warning: MultiThreadTest::Testmutex() disabled.\n");
471 // return;
472
473 if(verbose)
474 printf("Before mutex.\n");
475 {
476 Mutex m;
477 if(verbose)
478 printf(" Exited 2nd mutex\n");
479 }
480 if(verbose)
481 printf("exited 1st mutex. Now testing with threads:");
482
483 TestMutexThread1 thread1;
484 TestMutexThread2 thread2(thread1);
485 if (thread2.start() != 0 ||
486 thread1.start() != 0 ) {
487 errln("Error starting threads.");
488 }
489
490 for(int32_t patience = 12; patience > 0;patience--)
491 {
492 // TODO: Possible memory coherence issue in looking at fDone values
493 // that are set in another thread without the mutex here.
494 if(thread1.fDone && verbose)
495 printf("Thread1 done\n");
496
497 if(thread1.fDone && thread2.fDone)
498 {
499 if(thread2.fErr)
500 errln("Thread 2 says: thread1 didn't run before I aquired the mutex.");
501 logln("took %lu seconds for thread2 to aquire the mutex.", thread2.fElapsed);
502 return;
503 }
504 SimpleThread::sleep(1000);
505 }
506 if(verbose)
507 printf("patience exceeded. [WARNING mutex may still be acquired.] ");
508}
509
510// ***********
511// *********** TestMultithreadedIntl. Test the ICU in a multithreaded way.
512
513
514
515
516// ** First, some utility classes.
517
518//
519///* Here is an idea which needs more work
520// TestATest simply runs another Intltest subset against itself.
521// The correct subset of intltest that should be run in this way should be identified.
522// */
523//
524//class TestATest : public SimpleThread
525//{
526//public:
527// TestATest(IntlTest &t) : fTest(t), fDone(FALSE) {}
528// virtual void run()
529// {
530// fTest.runTest(NULL,"TestNumberSpelloutFormat");
531// fErrs = fTest.getErrors();
532// fDone = TRUE;
533// }
534//public:
535// IntlTest &fTest;
536// UBool fDone;
537// int32_t fErrs;
538//};
539//
540//
541//#include "itutil.h"
542////#include "tscoll.h"
543////#include "ittxtbd.h"
544//#include "itformat.h"
545////#include "itcwrap.h"
546//
547///* main code was:
548// IntlTestFormat formatTest;
549//// IntlTestCollator collatorTest;
550//
551// #define NUMTESTS 2
552// TestATest tests[NUMTESTS] = { TestATest(formatTest), TestATest(formatTest) };
553// char testName[NUMTESTS][20] = { "formatTest", "formatTest2" };
554//*/
555
556
557#include <string.h>
558
559// * Show exactly where the string's differences lie.
560UnicodeString showDifference(const UnicodeString& expected, const UnicodeString& result)
561{
562 UnicodeString res;
563 res = expected + "<Expected\n";
564 if(expected.length() != result.length())
565 res += " [ Different lengths ] \n";
566 else
567 {
568 for(int32_t i=0;i<expected.length();i++)
569 {
570 if(expected[i] == result[i])
571 {
572 res += " ";
573 }
574 else
575 {
576 res += "|";
577 }
578 }
579 res += "<Differences";
580 res += "\n";
581 }
582 res += result + "<Result\n";
583
584 return res;
585}
586
587
588// ** ThreadWithStatus - a thread that we can check the status and error condition of
589
590
591class ThreadWithStatus : public SimpleThread
592{
593public:
594 UBool getDone() { return fDone; }
595 UBool getError() { return (fErrors > 0); }
596 UBool getError(UnicodeString& fillinError) { fillinError = fErrorString; return (fErrors > 0); }
597 virtual ~ThreadWithStatus(){}
598protected:
599 ThreadWithStatus() : fDone(FALSE), fErrors(0) {}
600 void done() { fDone = TRUE; }
601 void error(const UnicodeString &error) { fErrors++; fErrorString = error; done(); }
602 void error() { error("An error occured."); }
603private:
604 UBool fDone;
605 int32_t fErrors;
606 UnicodeString fErrorString;
607};
608
609#define kFormatThreadIterations 20 // # of iterations per thread
610#define kFormatThreadThreads 10 // # of threads to spawn
611#define kFormatThreadPatience 60 // time in seconds to wait for all threads
612
613#if !UCONFIG_NO_FORMATTING
614
615// ** FormatThreadTest - a thread that tests performing a number of numberformats.
616
617
618struct FormatThreadTestData
619{
620 double number;
621 UnicodeString string;
622 FormatThreadTestData(double a, const UnicodeString& b) : number(a),string(b) {}
623} ;
624
625
626void errorToString(UErrorCode theStatus, UnicodeString &string)
627{
628 string=u_errorName(theStatus);
629}
630
631// "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
632
633void formatErrorMessage(UErrorCode &realStatus, const UnicodeString& pattern, const Locale& theLocale,
634 UErrorCode inStatus0, /* statusString 1 */ const Locale &inCountry2, double currency3, // these numbers are the message arguments.
635 UnicodeString &result)
636{
637 if(U_FAILURE(realStatus))
638 return; // you messed up
639
640 UnicodeString errString1;
641 errorToString(inStatus0, errString1);
642
643 UnicodeString countryName2;
644 inCountry2.getDisplayCountry(theLocale,countryName2);
645
646 Formattable myArgs[] = {
647 Formattable((int32_t)inStatus0), // inStatus0 {0}
648 Formattable(errString1), // statusString1 {1}
649 Formattable(countryName2), // inCountry2 {2}
650 Formattable(currency3)// currency3 {3,number,currency}
651 };
652
653 MessageFormat *fmt = new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus);
654 fmt->setLocale(theLocale);
655 fmt->applyPattern(pattern, realStatus);
656
657 if (U_FAILURE(realStatus)) {
658 delete fmt;
659 return;
660 }
661
662 FieldPosition ignore = 0;
663 fmt->format(myArgs,4,result,ignore,realStatus);
664
665 delete fmt;
666};
667
668static UMTX ftMutex;
669
670class FormatThreadTest : public ThreadWithStatus
671{
672public:
673 FormatThreadTest() // constructor is NOT multithread safe.
674 : ThreadWithStatus(),
675 fOffset(0)
676 // the locale to use
677 {
678 static int32_t fgOffset = 0;
679 fgOffset += 3;
680 fOffset = fgOffset;
681 }
682
683
684 virtual void run()
685 {
686 // Keep this data here to avoid static initialization.
687 FormatThreadTestData kNumberFormatTestData[] =
688 {
689 FormatThreadTestData((double)5.0, UnicodeString("5", "")),
690 FormatThreadTestData( 6.0, UnicodeString("6", "")),
691 FormatThreadTestData( 20.0, UnicodeString("20", "")),
692 FormatThreadTestData( 8.0, UnicodeString("8", "")),
693 FormatThreadTestData( 8.3, UnicodeString("8.3", "")),
694 FormatThreadTestData( 12345, UnicodeString("12,345", "")),
695 FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")),
696 };
697 int32_t kNumberFormatTestDataLength = (int32_t)(sizeof(kNumberFormatTestData) / sizeof(kNumberFormatTestData[0]));
698
699 // Keep this data here to avoid static initialization.
700 FormatThreadTestData kPercentFormatTestData[] =
701 {
702 FormatThreadTestData((double)5.0, UnicodeString("500%", "")),
703 FormatThreadTestData( 1.0, UnicodeString("100%", "")),
704 FormatThreadTestData( 0.26, UnicodeString("26%", "")),
705 FormatThreadTestData( 16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499%") ), // U+00a0 = NBSP
706 FormatThreadTestData( 81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023%" )),
707 };
708 int32_t kPercentFormatTestDataLength = (int32_t)(sizeof(kPercentFormatTestData) / sizeof(kPercentFormatTestData[0]));
709 int32_t iteration;
710
711 UErrorCode status = U_ZERO_ERROR;
712 NumberFormat *formatter = NumberFormat::createInstance(Locale::getEnglish(),status);
713
714 if(U_FAILURE(status))
715 {
716 Mutex m(&ftMutex);
717 error("Error on NumberFormat::createInstance()");
718 return;
719 }
720
721 NumberFormat *percentFormatter = NumberFormat::createPercentInstance(Locale::getFrench(),status);
722
723 if(U_FAILURE(status))
724 {
725 {
726 Mutex m(&ftMutex);
727 error("Error on NumberFormat::createPercentInstance()");
728 }
729 delete formatter;
730 return;
731 }
732
733 for(iteration = 0;!getError() && iteration<kFormatThreadIterations;iteration++)
734 {
735
736 int32_t whichLine = (iteration + fOffset)%kNumberFormatTestDataLength;
737
738 UnicodeString output;
739
740 formatter->format(kNumberFormatTestData[whichLine].number, output);
741
742 if(0 != output.compare(kNumberFormatTestData[whichLine].string))
743 {
744 Mutex m(&ftMutex);
745 error("format().. expected " + kNumberFormatTestData[whichLine].string + " got " + output);
746 continue; // will break
747 }
748
749 // Now check percent.
750 output.remove();
751 whichLine = (iteration + fOffset)%kPercentFormatTestDataLength;
752
753 percentFormatter->format(kPercentFormatTestData[whichLine].number, output);
754
755 if(0 != output.compare(kPercentFormatTestData[whichLine].string))
756 {
757 Mutex m(&ftMutex);
758 error("percent format().. \n" + showDifference(kPercentFormatTestData[whichLine].string,output));
759 continue;
760 }
761
762 // Test message error
763#define kNumberOfMessageTests 3
764 UErrorCode statusToCheck;
765 UnicodeString patternToCheck;
766 Locale messageLocale;
767 Locale countryToCheck;
768 double currencyToCheck;
769
770 UnicodeString expected;
771
772 // load the cases.
773 switch((iteration+fOffset) % kNumberOfMessageTests)
774 {
775 default:
776 case 0:
777 statusToCheck= U_FILE_ACCESS_ERROR;
778 patternToCheck= "0:Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}."; // number,currency
779 messageLocale= Locale("en","US");
780 countryToCheck= Locale("","HR");
781 currencyToCheck= 8192.77;
782 expected= "0:Someone from Croatia is receiving a #4 error - U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77.";
783 break;
784 case 1:
785 statusToCheck= U_INDEX_OUTOFBOUNDS_ERROR;
786 patternToCheck= "1:A customer in {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}."; // number,currency
787 messageLocale= Locale("de","DE_PREEURO");
788 countryToCheck= Locale("","BF");
789 currencyToCheck= 2.32;
790 expected= "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing $2.32.";
791 case 2:
792 statusToCheck= U_MEMORY_ALLOCATION_ERROR;
793 patternToCheck= "2:user in {2} is receiving a #{0} error - {1}. They insist they just spent {3,number,currency} on memory."; // number,currency
794 messageLocale= Locale("de","AT_PREEURO"); // Austrian German
795 countryToCheck= Locale("","US"); // hmm
796 currencyToCheck= 40193.12;
797 expected= CharsToUnicodeString("2:user in Vereinigte Staaten is receiving a #7 error - U_MEMORY_ALLOCATION_ERROR. They insist they just spent \\u00f6S 40.193,12 on memory.");
798 break;
799 }
800
801 UnicodeString result;
802 UErrorCode status = U_ZERO_ERROR;
803 formatErrorMessage(status,patternToCheck,messageLocale,statusToCheck,countryToCheck,currencyToCheck,result);
804 if(U_FAILURE(status))
805 {
806 UnicodeString tmp;
807 errorToString(status,tmp);
808 Mutex m(&ftMutex);
809 error("Failure on message format, pattern=" + patternToCheck +", error = " + tmp);
810 continue;
811 }
812
813 if(result != expected)
814 {
815 Mutex m(&ftMutex);
816 error("PatternFormat: \n" + showDifference(expected,result));
817 continue;
818 }
819 }
820
821 delete formatter;
822 delete percentFormatter;
823 Mutex m(&ftMutex);
824 done();
825 }
826
827private:
828 int32_t fOffset; // where we are testing from.
829};
830
831// ** The actual test function.
832
833void MultithreadTest::TestThreadedIntl()
834{
835 umtx_init(&ftMutex);
836
837 FormatThreadTest tests[kFormatThreadThreads];
838
839 logln(UnicodeString("Spawning: ") + kFormatThreadThreads + " threads * " + kFormatThreadIterations + " iterations each.");
840 for(int32_t j = 0; j < kFormatThreadThreads; j++) {
841 int32_t threadStatus = tests[j].start();
842 if (threadStatus != 0) {
843 errln("System Error %d starting thread number %d.", threadStatus, j);
844 return;
845 }
846 }
847
848 int32_t patience;
849 for(patience = kFormatThreadPatience;patience > 0; patience --)
850 {
851 logln("Waiting...");
852
853 int32_t i;
854 int32_t terrs = 0;
855 int32_t completed =0;
856
857 for(i=0;i<kFormatThreadThreads;i++) {
858 umtx_lock(&ftMutex);
859 UBool threadIsDone = tests[i].getDone();
860 umtx_unlock(&ftMutex);
861 if(threadIsDone)
862 {
863 completed++;
864
865 logln(UnicodeString("Test #") + i + " is complete.. ");
866
867 UnicodeString theErr;
868 if(tests[i].getError(theErr))
869 {
870 terrs++;
871 errln(UnicodeString("#") + i + ": " + theErr);
872 }
873 // print out the error, too, if any.
874 }
875 }
876
877 if(completed == kFormatThreadThreads)
878 {
879 logln("Done!");
880
881 if(terrs)
882 {
883 errln("There were errors.");
884 }
885
886 break;
887 }
888
889 SimpleThread::sleep(900);
890 }
891
892 if (patience <= 0) {
893 errln("patience exceeded. ");
894 }
895 umtx_destroy(&ftMutex);
896 return;
897}
898
899#endif /* #if !UCONFIG_NO_FORMATTING */
900
901#if !UCONFIG_NO_COLLATION
902
903#define kCollatorThreadThreads 10 // # of threads to spawn
904#define kCollatorThreadPatience kCollatorThreadThreads*100
905
906struct Line {
907 UChar buff[25];
908 int32_t buflen;
909} ;
910
911class CollatorThreadTest : public ThreadWithStatus
912{
913private:
914 const UCollator *coll;
915 const Line *lines;
916 int32_t noLines;
917public:
918 CollatorThreadTest() : ThreadWithStatus(),
919 coll(NULL),
920 lines(NULL),
921 noLines(0)
922 {
923 };
924 void setCollator(UCollator *c, Line *l, int32_t nl)
925 {
926 coll = c;
927 lines = l;
928 noLines = nl;
929 }
930 virtual void run() {
931 //sleep(10000);
932 int32_t line = 0;
933
934 uint8_t sk1[1024], sk2[1024];
935 uint8_t *oldSk = NULL, *newSk = sk1;
936 int32_t resLen = 0, oldLen = 0;
937 int32_t i = 0;
938
939 for(i = 0; i < noLines; i++) {
940 resLen = ucol_getSortKey(coll, lines[i].buff, lines[i].buflen, newSk, 1024);
941
942 int32_t res = 0, cmpres = 0, cmpres2 = 0;
943
944 if(oldSk != NULL) {
945 res = strcmp((char *)oldSk, (char *)newSk);
946 cmpres = ucol_strcoll(coll, lines[i-1].buff, lines[i-1].buflen, lines[i].buff, lines[i].buflen);
947 cmpres2 = ucol_strcoll(coll, lines[i].buff, lines[i].buflen, lines[i-1].buff, lines[i-1].buflen);
948 //cmpres = res;
949 //cmpres2 = -cmpres;
950
951 if(cmpres != -cmpres2) {
952 error("Compare result not symmetrical on line "+ line);
953 }
954
955 if(((res&0x80000000) != (cmpres&0x80000000)) || (res == 0 && cmpres != 0) || (res != 0 && cmpres == 0)) {
956 error(UnicodeString("Difference between ucol_strcoll and sortkey compare on line ")+ UnicodeString(line));
957 }
958
959 if(res > 0) {
960 error(UnicodeString("Line %i is not greater or equal than previous line ")+ UnicodeString(i));
961 break;
962 } else if(res == 0) { /* equal */
963 res = u_strcmpCodePointOrder(lines[i-1].buff, lines[i].buff);
964 if (res == 0) {
965 error(UnicodeString("Probable error in test file on line %i (comparing identical strings)")+ UnicodeString(i));
966 break;
967 } else if (res > 0) {
968 error(UnicodeString("Sortkeys are identical, but code point comapare gives >0 on line ")+ UnicodeString(i));
969 }
970 }
971 }
972
973 oldSk = newSk;
974 oldLen = resLen;
975
976 newSk = (newSk == sk1)?sk2:sk1;
977 }
978
979 Mutex m;
980 done();
981 }
982};
983
984void MultithreadTest::TestCollators()
985{
986
987 UErrorCode status = U_ZERO_ERROR;
988 FILE *testFile = NULL;
989 char testDataPath[1024];
990 uprv_strcpy(testDataPath, IntlTest::loadTestData(status));
991 char* index = 0;
992 if (U_FAILURE(status)) {
993 errln("ERROR: could not open test data %s", u_errorName(status));
994 return;
995 }
996 index=strrchr(testDataPath,(char)U_FILE_SEP_CHAR);
997
998 if((unsigned int)(index-testDataPath) != (strlen(testDataPath)-1)){
999 *(index+1)=0;
1000 }
1001 uprv_strcat(testDataPath,".."U_FILE_SEP_STRING);
1002 uprv_strcat(testDataPath, "CollationTest_");
1003
1004 const char* type = "NON_IGNORABLE";
1005
1006 const char *ext = ".txt";
1007 if(testFile) {
1008 fclose(testFile);
1009 }
1010 char buffer[1024];
1011 uprv_strcpy(buffer, testDataPath);
1012 uprv_strcat(buffer, type);
1013 int32_t bufLen = uprv_strlen(buffer);
1014
1015 // we try to open 3 files:
1016 // path/CollationTest_type.txt
1017 // path/CollationTest_type_SHORT.txt
1018 // path/CollationTest_type_STUB.txt
1019 // we are going to test with the first one that we manage to open.
1020
1021 uprv_strcpy(buffer+bufLen, ext);
1022
1023 testFile = fopen(buffer, "rb");
1024
1025 if(testFile == 0) {
1026 uprv_strcpy(buffer+bufLen, "_SHORT");
1027 uprv_strcat(buffer, ext);
1028 testFile = fopen(buffer, "rb");
1029
1030 if(testFile == 0) {
1031 uprv_strcpy(buffer+bufLen, "_STUB");
1032 uprv_strcat(buffer, ext);
1033 testFile = fopen(buffer, "rb");
1034
1035 if (testFile == 0) {
1036 *(buffer+bufLen) = 0;
1037 errln("ERROR: could not open any of the conformance test files, tried opening base %s", buffer);
1038 return;
1039 } else {
1040 infoln(
1041 "INFO: Working with the stub file.\n"
1042 "If you need the full conformance test, please\n"
1043 "download the appropriate data files from:\n"
1044 "http://oss.software.ibm.com/cvs/icu4j/unicodetools/com/ibm/text/data/");
1045 }
1046 }
1047 }
1048
1049 Line *lines = new Line[65000];
1050 uprv_memset(lines, 0, sizeof(Line)*65000);
1051 int32_t lineNum = 0;
1052
1053 UChar bufferU[1024];
1054 int32_t buflen = 0;
1055 uint32_t first = 0;
1056 uint32_t offset = 0;
1057
1058 while (fgets(buffer, 1024, testFile) != NULL) {
1059 offset = 0;
1060 if(*buffer == 0 || buffer[0] == '#') {
1061 continue;
1062 }
1063 offset = u_parseString(buffer, bufferU, 1024, &first, &status);
1064 buflen = offset;
1065 bufferU[offset++] = 0;
1066 lines[lineNum].buflen = buflen;
1067 //lines[lineNum].buff = new UChar[buflen+1];
1068 u_memcpy(lines[lineNum].buff, bufferU, buflen);
1069 lineNum++;
1070 }
1071 fclose(testFile);
1072
1073
1074
1075 UCollator *coll = ucol_open("root", &status);
1076 if(U_FAILURE(status)) {
1077 errln("Couldn't open UCA collator");
1078 return;
1079 }
1080 ucol_setAttribute(coll, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
1081 ucol_setAttribute(coll, UCOL_CASE_FIRST, UCOL_OFF, &status);
1082 ucol_setAttribute(coll, UCOL_CASE_LEVEL, UCOL_OFF, &status);
1083 ucol_setAttribute(coll, UCOL_STRENGTH, UCOL_TERTIARY, &status);
1084 ucol_setAttribute(coll, UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE, &status);
1085
1086 int32_t noSpawned = 0;
1087 int32_t spawnResult = 0;
1088 CollatorThreadTest *tests;
1089 tests = new CollatorThreadTest[kCollatorThreadThreads];
1090
1091 logln(UnicodeString("Spawning: ") + kCollatorThreadThreads + " threads * " + kFormatThreadIterations + " iterations each.");
1092 int32_t j = 0;
1093 for(j = 0; j < kCollatorThreadThreads; j++) {
1094 //logln("Setting collator %i", j);
1095 tests[j].setCollator(coll, lines, lineNum);
1096 }
1097 for(j = 0; j < kCollatorThreadThreads; j++) {
1098 log("%i ", j);
1099 spawnResult = tests[j].start();
1100 if(spawnResult != 0) {
1101 infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned);
1102 break;
1103 }
1104 noSpawned++;
1105 }
1106 logln("Spawned all");
1107
1108 //for(int32_t patience = kCollatorThreadPatience;patience > 0; patience --)
1109 for(;;)
1110 {
1111 logln("Waiting...");
1112
1113 int32_t i;
1114 int32_t terrs = 0;
1115 int32_t completed =0;
1116
1117 for(i=0;i<kCollatorThreadThreads;i++)
1118 {
1119 umtx_lock(NULL);
1120 UBool threadIsDone = tests[i].getDone();
1121 umtx_unlock(NULL);
1122 if(threadIsDone)
1123 {
1124 completed++;
1125
1126 //logln(UnicodeString("Test #") + i + " is complete.. ");
1127
1128 UnicodeString theErr;
1129 if(tests[i].getError(theErr))
1130 {
1131 terrs++;
1132 errln(UnicodeString("#") + i + ": " + theErr);
1133 }
1134 // print out the error, too, if any.
1135 }
1136 }
1137 logln("Completed %i tests", completed);
1138
1139 if(completed == noSpawned)
1140 {
1141 logln("Done! All %i tests are finished", noSpawned);
1142
1143 if(terrs)
1144 {
1145 errln("There were errors.");
1146 }
1147 ucol_close(coll);
1148 delete[] tests;
1149 //for(i = 0; i < lineNum; i++) {
1150 //delete[] lines[i].buff;
1151 //}
1152 delete[] lines;
1153
1154 return;
1155 }
1156
1157 SimpleThread::sleep(900);
1158 }
1159 errln("patience exceeded. ");
1160 ucol_close(coll);
1161}
1162
1163#endif /* #if !UCONFIG_NO_COLLATION */
1164
1165#endif // ICU_USE_THREADS
1166