2000-01-15 02:00:06 +00:00
/********************************************************************
* COPYRIGHT :
2003-06-03 20:58:22 +00:00
* Copyright ( c ) 1999 - 2003 , International Business Machines Corporation and
2000-01-15 02:00:06 +00:00
* others . All Rights Reserved .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-06-01 18:27:44 +00:00
# if defined(hpux)
# ifndef _INCLUDE_POSIX_SOURCE
# define _INCLUDE_POSIX_SOURCE
# endif
# endif
2000-05-12 01:15:50 +00:00
# include <unicode/umachine.h>
2003-08-10 23:57:35 +00:00
# include "unicode/utypes.h"
# include "umutex.h"
2000-05-12 01:15:50 +00:00
2002-07-19 23:25:41 +00:00
// Just turn off threads on cygwin, so that we can test
// the other stuff. This needs to be investigated further.
# if defined(U_CYGWIN)
# define ICU_USE_THREADS 0
# endif
2002-01-24 07:51:02 +00:00
# if !defined(WIN32) && !defined(XP_MAC) && !defined(U_RHAPSODY)
2000-01-27 00:00:04 +00:00
# define POSIX 1
# endif
2000-08-11 17:40:12 +00:00
# if defined(POSIX) || defined(U_SOLARIS) || defined(AIX) || defined(HPUX)
2000-01-27 00:00:04 +00:00
# define HAVE_IMP
2000-10-04 18:30:18 +00:00
# if (ICU_USE_THREADS == 1)
2000-01-27 00:00:04 +00:00
# include <pthread.h>
2000-10-04 18:30:18 +00:00
# endif
2000-05-31 22:18:22 +00:00
# if defined(__hpux) && defined(HPUX_CMA)
# if defined(read) // read being defined as cma_read causes trouble with iostream::read
# undef read
# endif
# endif
2001-11-27 19:44:51 +00:00
/* Define __EXTENSIONS__ for Solaris and old friends in strict mode. */
# ifndef __EXTENSIONS__
# define __EXTENSIONS__
# endif
# include <signal.h>
2000-05-12 01:15:50 +00:00
/* Define _XPG4_2 for Solaris and friends. */
# ifndef _XPG4_2
# define _XPG4_2
# endif
/* Define __USE_XOPEN_EXTENDED for Linux and glibc. */
# ifndef __USE_XOPEN_EXTENDED
2000-05-31 22:18:22 +00:00
# define __USE_XOPEN_EXTENDED
2000-05-12 01:15:50 +00:00
# endif
2000-11-22 01:54:24 +00:00
/* Define _INCLUDE_XOPEN_SOURCE_EXTENDED for HP/UX (11?). */
# ifndef _INCLUDE_XOPEN_SOURCE_EXTENDED
# define _INCLUDE_XOPEN_SOURCE_EXTENDED
# endif
2000-05-12 01:15:50 +00:00
# include <unistd.h>
2000-01-27 00:00:04 +00:00
# endif
/* HPUX */
# ifdef sleep
# undef sleep
# endif
1999-12-09 23:11:48 +00:00
# include "tsmthred.h"
MultithreadTest : : MultithreadTest ( )
{
}
MultithreadTest : : ~ MultithreadTest ( )
{
}
# if (ICU_USE_THREADS==0)
2000-05-18 22:08:39 +00:00
void MultithreadTest : : runIndexedTest ( int32_t index , UBool exec ,
2000-08-14 21:42:36 +00:00
const char * & name , char * par ) {
1999-12-09 23:11:48 +00:00
if ( exec ) logln ( " TestSuite MultithreadTest: " ) ;
if ( index = = 0 )
name = " NO_THREADED_TESTS " ;
else
name = " " ;
if ( exec ) { logln ( " MultithreadTest - test DISABLED. ICU_USE_THREADS set to 0, check your configuration if this is a problem.. " ) ;
}
}
# else
1999-08-16 21:50:52 +00:00
// Note: A LOT OF THE FUNCTIONS IN THIS FILE SHOULD LIVE ELSEWHERE!!!!!
// Note: A LOT OF THE FUNCTIONS IN THIS FILE SHOULD LIVE ELSEWHERE!!!!!
// -srl
# include <stdio.h>
# include <string.h>
# include <ctype.h> // tolower, toupper
1999-12-28 23:57:50 +00:00
# include "unicode/putil.h"
1999-08-16 21:50:52 +00:00
/* for mthreadtest*/
1999-12-28 23:57:50 +00:00
# include "unicode/numfmt.h"
# include "unicode/choicfmt.h"
# include "unicode/msgfmt.h"
# include "unicode/locid.h"
2003-03-27 18:24:28 +00:00
# include "unicode/ucol.h"
# include "ucaconf.h"
1999-08-16 21:50:52 +00:00
# ifdef WIN32
# define HAVE_IMP
2002-03-28 18:26:25 +00:00
# define VC_EXTRALEAN
# define WIN32_LEAN_AND_MEAN
# define NOGDI
# define NOUSER
# define NOSERVICE
# define NOIME
# define NOMCX
1999-08-16 21:50:52 +00:00
# include <windows.h>
2003-06-05 18:15:20 +00:00
# include <process.h>
1999-08-16 21:50:52 +00:00
struct Win32ThreadImplementation
{
2003-06-05 18:15:20 +00:00
unsigned long fHandle ;
1999-08-16 21:50:52 +00:00
} ;
2003-06-05 18:15:20 +00:00
extern " C " void __cdecl SimpleThreadProc ( void * arg )
1999-08-16 21:50:52 +00:00
{
( ( SimpleThread * ) arg ) - > run ( ) ;
}
SimpleThread : : SimpleThread ( )
: fImplementation ( 0 )
{
Win32ThreadImplementation * imp = new Win32ThreadImplementation ;
imp - > fHandle = 0 ;
fImplementation = imp ;
}
SimpleThread : : ~ SimpleThread ( )
{
delete ( Win32ThreadImplementation * ) fImplementation ;
}
2003-03-29 08:46:15 +00:00
int32_t SimpleThread : : start ( )
1999-08-16 21:50:52 +00:00
{
Win32ThreadImplementation * imp = ( Win32ThreadImplementation * ) fImplementation ;
2003-06-05 18:15:20 +00:00
if ( imp - > fHandle ! = NULL ) {
// The thread appears to have already been started.
// This is probably an error on the part of our caller.
return - 1 ;
}
1999-08-16 21:50:52 +00:00
2003-06-10 21:31:38 +00:00
imp - > fHandle = _beginthread ( SimpleThreadProc , 0 /*stack size*/ , ( void * ) this ) ;
2003-06-05 18:15:20 +00:00
if ( imp - > fHandle = = - 1 ) {
// An error occured
int err = errno ;
if ( err = = 0 ) {
err = - 1 ;
}
return err ;
2003-03-29 08:46:15 +00:00
}
2003-06-05 18:15:20 +00:00
return 0 ;
1999-08-16 21:50:52 +00:00
}
void SimpleThread : : sleep ( int32_t millis )
{
: : Sleep ( millis ) ;
}
# elif defined XP_MAC
// since the Mac has no preemptive threading (at least on MacOS 8), only
// cooperative threading, threads are a no-op. We have no yield() calls
// anywhere in the ICU, so we are guaranteed to be thread-safe.
# define HAVE_IMP
SimpleThread : : SimpleThread ( )
{ }
SimpleThread : : ~ SimpleThread ( )
{ }
2003-03-29 08:46:15 +00:00
int32_t
1999-08-16 21:50:52 +00:00
SimpleThread : : start ( )
2003-03-29 08:46:15 +00:00
{ return 0 ; }
1999-08-16 21:50:52 +00:00
void
SimpleThread : : run ( )
{ }
void
SimpleThread : : sleep ( int32_t millis )
{ }
# endif
1999-12-09 23:11:48 +00:00
2000-06-30 21:35:03 +00:00
# if defined(POSIX)||defined(U_SOLARIS)||defined(AIX)||defined(HPUX)
1999-08-16 21:50:52 +00:00
# define HAVE_IMP
struct PosixThreadImplementation
{
pthread_t fThread ;
} ;
extern " C " void * SimpleThreadProc ( void * arg )
{
( ( SimpleThread * ) arg ) - > run ( ) ;
return 0 ;
}
SimpleThread : : SimpleThread ( ) : fImplementation ( 0 )
{
PosixThreadImplementation * imp = new PosixThreadImplementation ;
fImplementation = imp ;
}
SimpleThread : : ~ SimpleThread ( )
{
delete ( PosixThreadImplementation * ) fImplementation ;
}
2003-03-29 08:46:15 +00:00
int32_t SimpleThread : : start ( )
1999-08-16 21:50:52 +00:00
{
PosixThreadImplementation * imp = ( PosixThreadImplementation * ) fImplementation ;
int32_t rc ;
pthread_attr_t attr ;
2000-01-22 02:54:48 +00:00
# ifdef HPUX_CMA
2000-08-14 21:42:36 +00:00
rc = pthread_attr_create ( & attr ) ;
1999-08-16 21:50:52 +00:00
rc = pthread_create ( & ( imp - > fThread ) , attr , & SimpleThreadProc , ( void * ) this ) ;
pthread_attr_delete ( & attr ) ;
# else
2000-08-14 21:42:36 +00:00
rc = pthread_attr_init ( & attr ) ;
1999-08-16 21:50:52 +00:00
rc = pthread_create ( & ( imp - > fThread ) , & attr , & SimpleThreadProc , ( void * ) this ) ;
pthread_attr_destroy ( & attr ) ;
# endif
2003-03-29 08:46:15 +00:00
return rc ;
1999-08-16 21:50:52 +00:00
}
void SimpleThread : : sleep ( int32_t millis )
{
2000-06-30 21:35:03 +00:00
# ifdef U_SOLARIS
2000-11-22 01:54:24 +00:00
sigignore ( SIGALRM ) ;
1999-08-16 21:50:52 +00:00
# endif
2000-01-22 02:54:48 +00:00
# ifdef HPUX_CMA
2000-11-22 01:54:24 +00:00
cma_sleep ( millis / 100 ) ;
# elif defined(HPUX) || defined(OS390)
millis * = 1000 ;
while ( millis > = 1000000 ) {
usleep ( 999999 ) ;
millis - = 1000000 ;
}
if ( millis > 0 ) {
usleep ( millis ) ;
}
2000-01-27 21:01:18 +00:00
# else
2000-11-22 01:54:24 +00:00
usleep ( millis * 1000 ) ;
1999-08-16 21:50:52 +00:00
# endif
}
# endif
// end POSIX
# ifndef HAVE_IMP
# error No implementation for threads! Cannot test.
0 = 216 ; //die
# endif
// *************** end fluff ******************
/* now begins the real test. */
2000-05-18 22:08:39 +00:00
void MultithreadTest : : runIndexedTest ( int32_t index , UBool exec ,
2000-08-23 19:11:16 +00:00
const char * & name , char * /*par*/ ) {
2000-11-22 01:54:24 +00:00
if ( exec )
logln ( " TestSuite MultithreadTest: " ) ;
switch ( index ) {
case 0 :
name = " TestThreads " ;
if ( exec )
TestThreads ( ) ;
break ;
case 1 :
name = " TestMutex " ;
if ( exec )
TestMutex ( ) ;
break ;
case 2 :
name = " TestThreadedIntl " ;
2002-09-21 00:43:14 +00:00
# if !UCONFIG_NO_FORMATTING
2000-11-22 01:54:24 +00:00
if ( exec )
TestThreadedIntl ( ) ;
2002-09-21 00:43:14 +00:00
# endif
2000-11-22 01:54:24 +00:00
break ;
2003-03-27 18:24:28 +00:00
case 3 :
name = " TestCollators " ;
2003-03-31 23:10:33 +00:00
# if !UCONFIG_NO_COLLATION
2003-03-27 18:24:28 +00:00
if ( exec )
TestCollators ( ) ;
2003-03-31 23:10:33 +00:00
# endif /* #if !UCONFIG_NO_COLLATION */
2003-03-27 18:24:28 +00:00
break ;
2000-11-22 01:54:24 +00:00
default :
name = " " ;
break ; //needed to end loop
}
1999-08-16 21:50:52 +00:00
}
/*
TestThreads - - see if threads really work at all .
Set up N threads pointing at N chars . When they are started , they will
2000-01-27 17:57:14 +00:00
each sleep 1 second and then set their chars . At the end we make sure they
1999-08-16 21:50:52 +00:00
are all set .
*/
# define THREADTEST_NRTHREADS 8
class TestThreadsThread : public SimpleThread
{
public :
TestThreadsThread ( char * whatToChange ) { fWhatToChange = whatToChange ; }
2003-06-07 00:03:51 +00:00
virtual void run ( ) { SimpleThread : : sleep ( 1000 ) ;
Mutex m ;
* fWhatToChange = ' * ' ;
}
1999-08-16 21:50:52 +00:00
private :
char * fWhatToChange ;
} ;
void MultithreadTest : : TestThreads ( )
{
char threadTestChars [ THREADTEST_NRTHREADS + 1 ] ;
SimpleThread * threads [ THREADTEST_NRTHREADS ] ;
int32_t i ;
for ( i = 0 ; i < THREADTEST_NRTHREADS ; i + + )
{
threadTestChars [ i ] = ' ' ;
threads [ i ] = new TestThreadsThread ( & threadTestChars [ i ] ) ;
}
threadTestChars [ THREADTEST_NRTHREADS ] = ' \0 ' ;
logln ( " -> " + UnicodeString ( threadTestChars ) + " <- Firing off threads.. " ) ;
for ( i = 0 ; i < THREADTEST_NRTHREADS ; i + + )
{
2003-06-05 18:15:20 +00:00
if ( threads [ i ] - > start ( ) ! = 0 ) {
errln ( " Error starting thread %d " , i ) ;
}
1999-08-16 21:50:52 +00:00
SimpleThread : : sleep ( 200 ) ;
logln ( " Subthread started. " ) ;
}
logln ( " Waiting for threads to be set.. " ) ;
int32_t patience = 40 ; // seconds to wait
while ( patience - - )
{
int32_t count = 0 ;
2003-06-03 23:59:29 +00:00
umtx_lock ( NULL ) ;
1999-08-16 21:50:52 +00:00
for ( i = 0 ; i < THREADTEST_NRTHREADS ; i + + )
{
if ( threadTestChars [ i ] = = ' * ' )
{
count + + ;
}
}
2003-06-03 23:59:29 +00:00
umtx_unlock ( NULL ) ;
1999-08-16 21:50:52 +00:00
if ( count = = THREADTEST_NRTHREADS )
{
logln ( " -> " + UnicodeString ( threadTestChars ) + " <- Got all threads! cya " ) ;
2000-06-29 19:42:17 +00:00
for ( i = 0 ; i < THREADTEST_NRTHREADS ; i + + )
{
delete threads [ i ] ;
}
1999-08-16 21:50:52 +00:00
return ;
}
logln ( " -> " + UnicodeString ( threadTestChars ) + " <- Waiting.. " ) ;
SimpleThread : : sleep ( 500 ) ;
}
errln ( " -> " + UnicodeString ( threadTestChars ) + " <- PATIENCE EXCEEDED!! Still missing some. " ) ;
2000-06-29 19:42:17 +00:00
for ( i = 0 ; i < THREADTEST_NRTHREADS ; i + + )
{
delete threads [ i ] ;
}
1999-08-16 21:50:52 +00:00
}
class TestMutexThread1 : public SimpleThread
{
public :
TestMutexThread1 ( ) : fDone ( FALSE ) { }
virtual void run ( )
{
Mutex m ; // grab the lock first thing
2000-01-27 17:57:14 +00:00
SimpleThread : : sleep ( 900 ) ; // then wait
1999-08-16 21:50:52 +00:00
fDone = TRUE ; // finally, set our flag
}
public :
2000-05-18 22:08:39 +00:00
UBool fDone ;
1999-08-16 21:50:52 +00:00
} ;
class TestMutexThread2 : public SimpleThread
{
public :
TestMutexThread2 ( TestMutexThread1 & r ) : fOtherThread ( r ) , fDone ( FALSE ) , fErr ( FALSE ) { }
virtual void run ( )
{
2000-01-27 17:57:14 +00:00
SimpleThread : : sleep ( 500 ) ; // wait, make sure they aquire the lock
1999-12-28 23:57:50 +00:00
fElapsed = uprv_getUTCtime ( ) ;
1999-08-16 21:50:52 +00:00
{
Mutex m ; // wait here
1999-12-28 23:57:50 +00:00
fElapsed = uprv_getUTCtime ( ) - fElapsed ;
1999-08-16 21:50:52 +00:00
if ( fOtherThread . fDone = = FALSE )
fErr = TRUE ; // they didnt get to it yet
fDone = TRUE ; // we're done.
}
}
public :
TestMutexThread1 & fOtherThread ;
2000-05-18 22:08:39 +00:00
UBool fDone , fErr ;
1999-08-16 21:50:52 +00:00
int32_t fElapsed ;
2000-08-23 19:11:16 +00:00
private :
/**
* The assignment operator has no real implementation .
* It is provided to make the compiler happy . Do not call .
*/
TestMutexThread2 & operator = ( const TestMutexThread2 & ) { return * this ; }
1999-08-16 21:50:52 +00:00
} ;
void MultithreadTest : : TestMutex ( )
{
2000-11-22 01:54:24 +00:00
/* this test uses printf so that we don't hang by calling UnicodeString inside of a mutex. */
//logln("Bye.");
// printf("Warning: MultiThreadTest::Testmutex() disabled.\n");
// return;
1999-08-16 21:50:52 +00:00
if ( verbose )
2001-03-26 23:46:57 +00:00
printf ( " Before mutex. \n " ) ;
1999-08-16 21:50:52 +00:00
{
2000-11-22 01:54:24 +00:00
Mutex m ;
if ( verbose )
2001-03-26 23:46:57 +00:00
printf ( " Exited 2nd mutex \n " ) ;
2000-11-22 01:54:24 +00:00
}
if ( verbose )
2001-03-26 23:46:57 +00:00
printf ( " exited 1st mutex. Now testing with threads: " ) ;
2000-11-22 01:54:24 +00:00
TestMutexThread1 thread1 ;
TestMutexThread2 thread2 ( thread1 ) ;
2003-06-05 18:15:20 +00:00
if ( thread2 . start ( ) ! = 0 | |
thread1 . start ( ) ! = 0 ) {
errln ( " Error starting threads. " ) ;
}
2000-11-22 01:54:24 +00:00
for ( int32_t patience = 12 ; patience > 0 ; patience - - )
{
2003-06-03 23:59:29 +00:00
// TODO: Possible memory coherence issue in looking at fDone values
// that are set in another thread without the mutex here.
2000-11-22 01:54:24 +00:00
if ( thread1 . fDone & & verbose )
2001-03-26 23:46:57 +00:00
printf ( " Thread1 done \n " ) ;
2000-11-22 01:54:24 +00:00
if ( thread1 . fDone & & thread2 . fDone )
1999-08-16 21:50:52 +00:00
{
2000-11-22 01:54:24 +00:00
if ( thread2 . fErr )
errln ( " Thread 2 says: thread1 didn't run before I aquired the mutex. " ) ;
2001-03-26 23:46:57 +00:00
logln ( " took %lu seconds for thread2 to aquire the mutex. " , thread2 . fElapsed ) ;
2000-11-22 01:54:24 +00:00
return ;
1999-08-16 21:50:52 +00:00
}
2000-11-22 01:54:24 +00:00
SimpleThread : : sleep ( 1000 ) ;
1999-08-16 21:50:52 +00:00
}
2000-11-22 01:54:24 +00:00
if ( verbose )
printf ( " patience exceeded. [WARNING mutex may still be acquired.] " ) ;
1999-08-16 21:50:52 +00:00
}
// ***********
// *********** TestMultithreadedIntl. Test the ICU in a multithreaded way.
// ** First, some utility classes.
//
///* Here is an idea which needs more work
// TestATest simply runs another Intltest subset against itself.
// The correct subset of intltest that should be run in this way should be identified.
// */
//
//class TestATest : public SimpleThread
//{
//public:
// TestATest(IntlTest &t) : fTest(t), fDone(FALSE) {}
// virtual void run()
// {
// fTest.runTest(NULL,"TestNumberSpelloutFormat");
// fErrs = fTest.getErrors();
// fDone = TRUE;
// }
//public:
// IntlTest &fTest;
2000-05-18 22:08:39 +00:00
// UBool fDone;
1999-08-16 21:50:52 +00:00
// int32_t fErrs;
//};
//
//
//#include "itutil.h"
////#include "tscoll.h"
////#include "ittxtbd.h"
//#include "itformat.h"
////#include "itcwrap.h"
//
///* main code was:
// IntlTestFormat formatTest;
//// IntlTestCollator collatorTest;
//
// #define NUMTESTS 2
// TestATest tests[NUMTESTS] = { TestATest(formatTest), TestATest(formatTest) };
// char testName[NUMTESTS][20] = { "formatTest", "formatTest2" };
//*/
# include <string.h>
// * Show exactly where the string's differences lie.
UnicodeString showDifference ( const UnicodeString & expected , const UnicodeString & result )
{
UnicodeString res ;
res = expected + " <Expected \n " ;
1999-12-08 02:11:04 +00:00
if ( expected . length ( ) ! = result . length ( ) )
1999-08-16 21:50:52 +00:00
res + = " [ Different lengths ] \n " ;
else
{
1999-12-08 02:11:04 +00:00
for ( int32_t i = 0 ; i < expected . length ( ) ; i + + )
1999-08-16 21:50:52 +00:00
{
if ( expected [ i ] = = result [ i ] )
{
res + = " " ;
}
else
{
res + = " | " ;
}
}
res + = " <Differences " ;
res + = " \n " ;
}
res + = result + " <Result \n " ;
return res ;
}
// ** ThreadWithStatus - a thread that we can check the status and error condition of
class ThreadWithStatus : public SimpleThread
{
public :
2000-05-18 22:08:39 +00:00
UBool getDone ( ) { return fDone ; }
UBool getError ( ) { return ( fErrors > 0 ) ; }
UBool getError ( UnicodeString & fillinError ) { fillinError = fErrorString ; return ( fErrors > 0 ) ; }
1999-08-16 21:50:52 +00:00
virtual ~ ThreadWithStatus ( ) { }
protected :
ThreadWithStatus ( ) : fDone ( FALSE ) , fErrors ( 0 ) { }
void done ( ) { fDone = TRUE ; }
void error ( const UnicodeString & error ) { fErrors + + ; fErrorString = error ; done ( ) ; }
void error ( ) { error ( " An error occured. " ) ; }
private :
2000-05-18 22:08:39 +00:00
UBool fDone ;
1999-08-16 21:50:52 +00:00
int32_t fErrors ;
UnicodeString fErrorString ;
} ;
2003-05-30 00:38:47 +00:00
# define kFormatThreadIterations 20 // # of iterations per thread
# define kFormatThreadThreads 10 // # of threads to spawn
# define kFormatThreadPatience 60 // time in seconds to wait for all threads
2002-09-21 00:43:14 +00:00
# if !UCONFIG_NO_FORMATTING
1999-08-16 21:50:52 +00:00
// ** FormatThreadTest - a thread that tests performing a number of numberformats.
struct FormatThreadTestData
{
double number ;
UnicodeString string ;
FormatThreadTestData ( double a , const UnicodeString & b ) : number ( a ) , string ( b ) { }
} ;
void errorToString ( UErrorCode theStatus , UnicodeString & string )
{
1999-12-08 23:31:17 +00:00
string = u_errorName ( theStatus ) ;
1999-08-16 21:50:52 +00:00
}
// "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
void formatErrorMessage ( UErrorCode & realStatus , const UnicodeString & pattern , const Locale & theLocale ,
UErrorCode inStatus0 , /* statusString 1 */ const Locale & inCountry2 , double currency3 , // these numbers are the message arguments.
UnicodeString & result )
{
1999-10-18 22:48:32 +00:00
if ( U_FAILURE ( realStatus ) )
1999-08-16 21:50:52 +00:00
return ; // you messed up
UnicodeString errString1 ;
errorToString ( inStatus0 , errString1 ) ;
UnicodeString countryName2 ;
inCountry2 . getDisplayCountry ( theLocale , countryName2 ) ;
Formattable myArgs [ ] = {
Formattable ( ( int32_t ) inStatus0 ) , // inStatus0 {0}
Formattable ( errString1 ) , // statusString1 {1}
Formattable ( countryName2 ) , // inCountry2 {2}
Formattable ( currency3 ) // currency3 {3,number,currency}
} ;
MessageFormat * fmt = new MessageFormat ( " MessageFormat's API is broken!!!!!!!!!!! " , realStatus ) ;
fmt - > setLocale ( theLocale ) ;
fmt - > applyPattern ( pattern , realStatus ) ;
1999-10-18 22:48:32 +00:00
if ( U_FAILURE ( realStatus ) ) {
1999-08-16 21:50:52 +00:00
delete fmt ;
return ;
}
FieldPosition ignore = 0 ;
fmt - > format ( myArgs , 4 , result , ignore , realStatus ) ;
delete fmt ;
} ;
2003-06-07 00:03:51 +00:00
static UMTX ftMutex ;
1999-08-16 21:50:52 +00:00
class FormatThreadTest : public ThreadWithStatus
{
public :
FormatThreadTest ( ) // constructor is NOT multithread safe.
2001-07-03 19:47:22 +00:00
: ThreadWithStatus ( ) ,
fOffset ( 0 )
1999-08-16 21:50:52 +00:00
// the locale to use
{
static int32_t fgOffset = 0 ;
2001-07-03 19:47:22 +00:00
fgOffset + = 3 ;
fOffset = fgOffset ;
1999-08-16 21:50:52 +00:00
}
2003-06-07 00:03:51 +00:00
1999-08-16 21:50:52 +00:00
virtual void run ( )
{
2001-07-03 19:47:22 +00:00
// Keep this data here to avoid static initialization.
FormatThreadTestData kNumberFormatTestData [ ] =
{
FormatThreadTestData ( ( double ) 5.0 , UnicodeString ( " 5 " , " " ) ) ,
FormatThreadTestData ( 6.0 , UnicodeString ( " 6 " , " " ) ) ,
FormatThreadTestData ( 20.0 , UnicodeString ( " 20 " , " " ) ) ,
FormatThreadTestData ( 8.0 , UnicodeString ( " 8 " , " " ) ) ,
FormatThreadTestData ( 8.3 , UnicodeString ( " 8.3 " , " " ) ) ,
FormatThreadTestData ( 12345 , UnicodeString ( " 12,345 " , " " ) ) ,
FormatThreadTestData ( 81890.23 , UnicodeString ( " 81,890.23 " , " " ) ) ,
} ;
int32_t kNumberFormatTestDataLength = ( int32_t ) ( sizeof ( kNumberFormatTestData ) / sizeof ( kNumberFormatTestData [ 0 ] ) ) ;
// Keep this data here to avoid static initialization.
FormatThreadTestData kPercentFormatTestData [ ] =
{
FormatThreadTestData ( ( double ) 5.0 , UnicodeString ( " 500% " , " " ) ) ,
FormatThreadTestData ( 1.0 , UnicodeString ( " 100% " , " " ) ) ,
FormatThreadTestData ( 0.26 , UnicodeString ( " 26% " , " " ) ) ,
FormatThreadTestData ( 16384.99 , CharsToUnicodeString ( " 1 \\ u00a0638 \\ u00a0499% " ) ) , // U+00a0 = NBSP
FormatThreadTestData ( 81890.23 , CharsToUnicodeString ( " 8 \\ u00a0189 \\ u00a0023% " ) ) ,
} ;
int32_t kPercentFormatTestDataLength = ( int32_t ) ( sizeof ( kPercentFormatTestData ) / sizeof ( kPercentFormatTestData [ 0 ] ) ) ;
1999-08-16 21:50:52 +00:00
int32_t iteration ;
1999-10-07 00:07:53 +00:00
UErrorCode status = U_ZERO_ERROR ;
2002-08-21 00:16:30 +00:00
NumberFormat * formatter = NumberFormat : : createInstance ( Locale : : getEnglish ( ) , status ) ;
1999-08-16 21:50:52 +00:00
1999-10-18 22:48:32 +00:00
if ( U_FAILURE ( status ) )
1999-08-16 21:50:52 +00:00
{
2003-06-07 00:03:51 +00:00
Mutex m ( & ftMutex ) ;
1999-08-16 21:50:52 +00:00
error ( " Error on NumberFormat::createInstance() " ) ;
return ;
}
2002-08-21 00:16:30 +00:00
NumberFormat * percentFormatter = NumberFormat : : createPercentInstance ( Locale : : getFrench ( ) , status ) ;
1999-08-16 21:50:52 +00:00
1999-10-18 22:48:32 +00:00
if ( U_FAILURE ( status ) )
1999-08-16 21:50:52 +00:00
{
2003-06-03 23:59:29 +00:00
{
2003-06-07 00:03:51 +00:00
Mutex m ( & ftMutex ) ;
2003-06-03 23:59:29 +00:00
error ( " Error on NumberFormat::createPercentInstance() " ) ;
}
1999-08-16 21:50:52 +00:00
delete formatter ;
return ;
}
for ( iteration = 0 ; ! getError ( ) & & iteration < kFormatThreadIterations ; iteration + + )
{
2003-06-07 00:03:51 +00:00
1999-08-16 21:50:52 +00:00
int32_t whichLine = ( iteration + fOffset ) % kNumberFormatTestDataLength ;
UnicodeString output ;
formatter - > format ( kNumberFormatTestData [ whichLine ] . number , output ) ;
if ( 0 ! = output . compare ( kNumberFormatTestData [ whichLine ] . string ) )
{
2003-06-07 00:03:51 +00:00
Mutex m ( & ftMutex ) ;
1999-08-16 21:50:52 +00:00
error ( " format().. expected " + kNumberFormatTestData [ whichLine ] . string + " got " + output ) ;
continue ; // will break
}
// Now check percent.
output . remove ( ) ;
whichLine = ( iteration + fOffset ) % kPercentFormatTestDataLength ;
percentFormatter - > format ( kPercentFormatTestData [ whichLine ] . number , output ) ;
if ( 0 ! = output . compare ( kPercentFormatTestData [ whichLine ] . string ) )
{
2003-06-07 00:03:51 +00:00
Mutex m ( & ftMutex ) ;
1999-08-16 21:50:52 +00:00
error ( " percent format().. \n " + showDifference ( kPercentFormatTestData [ whichLine ] . string , output ) ) ;
continue ;
}
// Test message error
# define kNumberOfMessageTests 3
2003-06-03 23:59:29 +00:00
UErrorCode statusToCheck ;
1999-08-16 21:50:52 +00:00
UnicodeString patternToCheck ;
Locale messageLocale ;
Locale countryToCheck ;
double currencyToCheck ;
UnicodeString expected ;
// load the cases.
switch ( ( iteration + fOffset ) % kNumberOfMessageTests )
{
default :
case 0 :
1999-10-07 00:07:53 +00:00
statusToCheck = U_FILE_ACCESS_ERROR ;
1999-08-16 21:50:52 +00:00
patternToCheck = " 0:Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}. " ; // number,currency
messageLocale = Locale ( " en " , " US " ) ;
countryToCheck = Locale ( " " , " HR " ) ;
currencyToCheck = 8192.77 ;
1999-10-07 00:07:53 +00:00
expected = " 0:Someone from Croatia is receiving a #4 error - U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77. " ;
1999-08-16 21:50:52 +00:00
break ;
case 1 :
1999-10-07 00:07:53 +00:00
statusToCheck = U_INDEX_OUTOFBOUNDS_ERROR ;
1999-08-16 21:50:52 +00:00
patternToCheck = " 1:A customer in {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}. " ; // number,currency
2001-10-12 19:30:13 +00:00
messageLocale = Locale ( " de " , " DE_PREEURO " ) ;
1999-08-16 21:50:52 +00:00
countryToCheck = Locale ( " " , " BF " ) ;
currencyToCheck = 2.32 ;
1999-10-07 00:07:53 +00:00
expected = " 1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing $2.32. " ;
1999-08-16 21:50:52 +00:00
case 2 :
1999-10-07 00:07:53 +00:00
statusToCheck = U_MEMORY_ALLOCATION_ERROR ;
1999-08-16 21:50:52 +00:00
patternToCheck = " 2:user in {2} is receiving a #{0} error - {1}. They insist they just spent {3,number,currency} on memory. " ; // number,currency
2001-10-12 19:30:13 +00:00
messageLocale = Locale ( " de " , " AT_PREEURO " ) ; // Austrian German
1999-08-16 21:50:52 +00:00
countryToCheck = Locale ( " " , " US " ) ; // hmm
currencyToCheck = 40193.12 ;
2000-03-22 23:17:42 +00:00
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. " ) ;
1999-08-16 21:50:52 +00:00
break ;
}
UnicodeString result ;
1999-10-07 00:07:53 +00:00
UErrorCode status = U_ZERO_ERROR ;
1999-08-16 21:50:52 +00:00
formatErrorMessage ( status , patternToCheck , messageLocale , statusToCheck , countryToCheck , currencyToCheck , result ) ;
1999-10-18 22:48:32 +00:00
if ( U_FAILURE ( status ) )
1999-08-16 21:50:52 +00:00
{
UnicodeString tmp ;
errorToString ( status , tmp ) ;
2003-06-07 00:03:51 +00:00
Mutex m ( & ftMutex ) ;
1999-08-16 21:50:52 +00:00
error ( " Failure on message format, pattern= " + patternToCheck + " , error = " + tmp ) ;
continue ;
}
if ( result ! = expected )
{
2003-06-07 00:03:51 +00:00
Mutex m ( & ftMutex ) ;
1999-08-16 21:50:52 +00:00
error ( " PatternFormat: \n " + showDifference ( expected , result ) ) ;
continue ;
}
}
delete formatter ;
delete percentFormatter ;
2003-06-07 00:03:51 +00:00
Mutex m ( & ftMutex ) ;
1999-08-16 21:50:52 +00:00
done ( ) ;
}
private :
int32_t fOffset ; // where we are testing from.
} ;
// ** The actual test function.
void MultithreadTest : : TestThreadedIntl ( )
{
2003-06-07 00:03:51 +00:00
umtx_init ( & ftMutex ) ;
1999-08-16 21:50:52 +00:00
FormatThreadTest tests [ kFormatThreadThreads ] ;
logln ( UnicodeString ( " Spawning: " ) + kFormatThreadThreads + " threads * " + kFormatThreadIterations + " iterations each. " ) ;
2003-06-05 18:15:20 +00:00
for ( int32_t j = 0 ; j < kFormatThreadThreads ; j + + ) {
int32_t threadStatus = tests [ j ] . start ( ) ;
if ( threadStatus ! = 0 ) {
errln ( " System Error %d starting thread number %d. " , threadStatus , j ) ;
return ;
}
}
1999-08-16 21:50:52 +00:00
2003-06-07 00:03:51 +00:00
int32_t patience ;
for ( patience = kFormatThreadPatience ; patience > 0 ; patience - - )
1999-08-16 21:50:52 +00:00
{
logln ( " Waiting... " ) ;
int32_t i ;
int32_t terrs = 0 ;
int32_t completed = 0 ;
2003-06-03 23:59:29 +00:00
for ( i = 0 ; i < kFormatThreadThreads ; i + + ) {
2003-06-07 00:03:51 +00:00
umtx_lock ( & ftMutex ) ;
2003-06-03 23:59:29 +00:00
UBool threadIsDone = tests [ i ] . getDone ( ) ;
2003-06-07 00:03:51 +00:00
umtx_unlock ( & ftMutex ) ;
2003-06-03 23:59:29 +00:00
if ( threadIsDone )
1999-08-16 21:50:52 +00:00
{
completed + + ;
2003-06-03 23:59:29 +00:00
1999-08-16 21:50:52 +00:00
logln ( UnicodeString ( " Test # " ) + i + " is complete.. " ) ;
2003-06-03 23:59:29 +00:00
1999-08-16 21:50:52 +00:00
UnicodeString theErr ;
if ( tests [ i ] . getError ( theErr ) )
{
terrs + + ;
errln ( UnicodeString ( " # " ) + i + " : " + theErr ) ;
}
// print out the error, too, if any.
}
}
2003-06-03 23:59:29 +00:00
1999-08-16 21:50:52 +00:00
if ( completed = = kFormatThreadThreads )
{
logln ( " Done! " ) ;
if ( terrs )
{
errln ( " There were errors. " ) ;
}
2003-06-07 00:03:51 +00:00
break ;
1999-08-16 21:50:52 +00:00
}
2000-01-27 17:57:14 +00:00
SimpleThread : : sleep ( 900 ) ;
1999-08-16 21:50:52 +00:00
}
2003-06-07 00:03:51 +00:00
if ( patience < = 0 ) {
errln ( " patience exceeded. " ) ;
}
umtx_destroy ( & ftMutex ) ;
return ;
2003-08-10 23:57:35 +00:00
1999-08-16 21:50:52 +00:00
}
2002-09-21 00:43:14 +00:00
# endif /* #if !UCONFIG_NO_FORMATTING */
2003-03-31 23:10:33 +00:00
# if !UCONFIG_NO_COLLATION
# define kCollatorThreadThreads 10 // # of threads to spawn
2003-03-27 18:24:28 +00:00
# define kCollatorThreadPatience kCollatorThreadThreads*100
struct Line {
2003-03-28 08:14:43 +00:00
UChar buff [ 25 ] ;
2003-03-27 18:24:28 +00:00
int32_t buflen ;
} ;
class CollatorThreadTest : public ThreadWithStatus
{
private :
const UCollator * coll ;
const Line * lines ;
int32_t noLines ;
public :
CollatorThreadTest ( ) : ThreadWithStatus ( ) ,
coll ( NULL ) ,
lines ( NULL ) ,
noLines ( 0 )
{
} ;
void setCollator ( UCollator * c , Line * l , int32_t nl )
{
coll = c ;
lines = l ;
noLines = nl ;
}
virtual void run ( ) {
2003-03-29 08:46:15 +00:00
//sleep(10000);
2003-03-27 18:24:28 +00:00
int32_t line = 0 ;
uint8_t sk1 [ 1024 ] , sk2 [ 1024 ] ;
uint8_t * oldSk = NULL , * newSk = sk1 ;
int32_t resLen = 0 , oldLen = 0 ;
int32_t i = 0 ;
for ( i = 0 ; i < noLines ; i + + ) {
resLen = ucol_getSortKey ( coll , lines [ i ] . buff , lines [ i ] . buflen , newSk , 1024 ) ;
int32_t res = 0 , cmpres = 0 , cmpres2 = 0 ;
if ( oldSk ! = NULL ) {
res = strcmp ( ( char * ) oldSk , ( char * ) newSk ) ;
cmpres = ucol_strcoll ( coll , lines [ i - 1 ] . buff , lines [ i - 1 ] . buflen , lines [ i ] . buff , lines [ i ] . buflen ) ;
cmpres2 = ucol_strcoll ( coll , lines [ i ] . buff , lines [ i ] . buflen , lines [ i - 1 ] . buff , lines [ i - 1 ] . buflen ) ;
2003-03-29 08:46:15 +00:00
//cmpres = res;
//cmpres2 = -cmpres;
2003-03-27 18:24:28 +00:00
if ( cmpres ! = - cmpres2 ) {
error ( " Compare result not symmetrical on line " + line ) ;
}
if ( ( ( res & 0x80000000 ) ! = ( cmpres & 0x80000000 ) ) | | ( res = = 0 & & cmpres ! = 0 ) | | ( res ! = 0 & & cmpres = = 0 ) ) {
error ( UnicodeString ( " Difference between ucol_strcoll and sortkey compare on line " ) + UnicodeString ( line ) ) ;
}
if ( res > 0 ) {
error ( UnicodeString ( " Line %i is not greater or equal than previous line " ) + UnicodeString ( i ) ) ;
break ;
} else if ( res = = 0 ) { /* equal */
res = u_strcmpCodePointOrder ( lines [ i - 1 ] . buff , lines [ i ] . buff ) ;
if ( res = = 0 ) {
error ( UnicodeString ( " Probable error in test file on line %i (comparing identical strings) " ) + UnicodeString ( i ) ) ;
break ;
} else if ( res > 0 ) {
error ( UnicodeString ( " Sortkeys are identical, but code point comapare gives >0 on line " ) + UnicodeString ( i ) ) ;
}
}
}
oldSk = newSk ;
oldLen = resLen ;
newSk = ( newSk = = sk1 ) ? sk2 : sk1 ;
}
2003-06-03 23:59:29 +00:00
Mutex m ;
2003-03-27 18:24:28 +00:00
done ( ) ;
}
} ;
void MultithreadTest : : TestCollators ( )
{
UErrorCode status = U_ZERO_ERROR ;
FILE * testFile = NULL ;
char testDataPath [ 1024 ] ;
uprv_strcpy ( testDataPath , IntlTest : : loadTestData ( status ) ) ;
char * index = 0 ;
2003-05-16 19:52:01 +00:00
if ( U_FAILURE ( status ) ) {
errln ( " ERROR: could not open test data %s " , u_errorName ( status ) ) ;
return ;
}
2003-03-27 18:24:28 +00:00
index = strrchr ( testDataPath , ( char ) U_FILE_SEP_CHAR ) ;
if ( ( unsigned int ) ( index - testDataPath ) ! = ( strlen ( testDataPath ) - 1 ) ) {
* ( index + 1 ) = 0 ;
}
uprv_strcat ( testDataPath , " .. " U_FILE_SEP_STRING ) ;
uprv_strcat ( testDataPath , " CollationTest_ " ) ;
const char * type = " NON_IGNORABLE " ;
const char * ext = " .txt " ;
if ( testFile ) {
fclose ( testFile ) ;
}
char buffer [ 1024 ] ;
uprv_strcpy ( buffer , testDataPath ) ;
uprv_strcat ( buffer , type ) ;
int32_t bufLen = uprv_strlen ( buffer ) ;
// we try to open 3 files:
// path/CollationTest_type.txt
// path/CollationTest_type_SHORT.txt
// path/CollationTest_type_STUB.txt
// we are going to test with the first one that we manage to open.
uprv_strcpy ( buffer + bufLen , ext ) ;
testFile = fopen ( buffer , " rb " ) ;
if ( testFile = = 0 ) {
uprv_strcpy ( buffer + bufLen , " _SHORT " ) ;
uprv_strcat ( buffer , ext ) ;
testFile = fopen ( buffer , " rb " ) ;
if ( testFile = = 0 ) {
uprv_strcpy ( buffer + bufLen , " _STUB " ) ;
uprv_strcat ( buffer , ext ) ;
testFile = fopen ( buffer , " rb " ) ;
if ( testFile = = 0 ) {
* ( buffer + bufLen ) = 0 ;
errln ( " ERROR: could not open any of the conformance test files, tried opening base %s " , buffer ) ;
return ;
} else {
infoln (
" INFO: Working with the stub file. \n "
" If you need the full conformance test, please \n "
" download the appropriate data files from: \n "
" http://oss.software.ibm.com/cvs/icu4j/unicodetools/com/ibm/text/data/ " ) ;
}
}
}
2003-08-23 01:42:56 +00:00
Line * lines = new Line [ 200000 ] ;
uprv_memset ( lines , 0 , sizeof ( Line ) * 200000 ) ;
2003-03-27 18:24:28 +00:00
int32_t lineNum = 0 ;
UChar bufferU [ 1024 ] ;
int32_t buflen = 0 ;
uint32_t first = 0 ;
uint32_t offset = 0 ;
while ( fgets ( buffer , 1024 , testFile ) ! = NULL ) {
offset = 0 ;
if ( * buffer = = 0 | | buffer [ 0 ] = = ' # ' ) {
continue ;
}
offset = u_parseString ( buffer , bufferU , 1024 , & first , & status ) ;
buflen = offset ;
bufferU [ offset + + ] = 0 ;
lines [ lineNum ] . buflen = buflen ;
2003-03-28 08:14:43 +00:00
//lines[lineNum].buff = new UChar[buflen+1];
2003-03-27 18:24:28 +00:00
u_memcpy ( lines [ lineNum ] . buff , bufferU , buflen ) ;
lineNum + + ;
}
2003-06-12 17:45:25 +00:00
fclose ( testFile ) ;
2003-03-27 18:24:28 +00:00
UCollator * coll = ucol_open ( " root " , & status ) ;
2003-04-24 23:18:00 +00:00
if ( U_FAILURE ( status ) ) {
errln ( " Couldn't open UCA collator " ) ;
return ;
}
ucol_setAttribute ( coll , UCOL_NORMALIZATION_MODE , UCOL_ON , & status ) ;
2003-03-27 18:24:28 +00:00
ucol_setAttribute ( coll , UCOL_CASE_FIRST , UCOL_OFF , & status ) ;
ucol_setAttribute ( coll , UCOL_CASE_LEVEL , UCOL_OFF , & status ) ;
ucol_setAttribute ( coll , UCOL_STRENGTH , UCOL_TERTIARY , & status ) ;
ucol_setAttribute ( coll , UCOL_ALTERNATE_HANDLING , UCOL_NON_IGNORABLE , & status ) ;
2003-03-29 08:46:15 +00:00
int32_t noSpawned = 0 ;
int32_t spawnResult = 0 ;
2003-03-27 18:24:28 +00:00
CollatorThreadTest * tests ;
tests = new CollatorThreadTest [ kCollatorThreadThreads ] ;
2003-03-28 08:14:43 +00:00
logln ( UnicodeString ( " Spawning: " ) + kCollatorThreadThreads + " threads * " + kFormatThreadIterations + " iterations each. " ) ;
int32_t j = 0 ;
for ( j = 0 ; j < kCollatorThreadThreads ; j + + ) {
2003-03-29 08:46:15 +00:00
//logln("Setting collator %i", j);
2003-03-27 18:24:28 +00:00
tests [ j ] . setCollator ( coll , lines , lineNum ) ;
2003-03-28 08:14:43 +00:00
}
for ( j = 0 ; j < kCollatorThreadThreads ; j + + ) {
2003-03-29 08:46:15 +00:00
log ( " %i " , j ) ;
spawnResult = tests [ j ] . start ( ) ;
if ( spawnResult ! = 0 ) {
2003-03-29 09:00:40 +00:00
infoln ( " THREAD INFO: Couldn't spawn more than %i threads " , noSpawned ) ;
2003-03-29 08:46:15 +00:00
break ;
}
noSpawned + + ;
2003-03-27 18:24:28 +00:00
}
2003-03-29 08:46:15 +00:00
logln ( " Spawned all " ) ;
2003-03-27 18:24:28 +00:00
//for(int32_t patience = kCollatorThreadPatience;patience > 0; patience --)
for ( ; ; )
{
logln ( " Waiting... " ) ;
int32_t i ;
int32_t terrs = 0 ;
int32_t completed = 0 ;
for ( i = 0 ; i < kCollatorThreadThreads ; i + + )
{
2003-06-03 23:59:29 +00:00
umtx_lock ( NULL ) ;
UBool threadIsDone = tests [ i ] . getDone ( ) ;
umtx_unlock ( NULL ) ;
if ( threadIsDone )
2003-03-27 18:24:28 +00:00
{
completed + + ;
2003-03-29 08:46:15 +00:00
//logln(UnicodeString("Test #") + i + " is complete.. ");
2003-03-27 18:24:28 +00:00
UnicodeString theErr ;
if ( tests [ i ] . getError ( theErr ) )
{
terrs + + ;
errln ( UnicodeString ( " # " ) + i + " : " + theErr ) ;
}
// print out the error, too, if any.
}
}
2003-03-29 08:46:15 +00:00
logln ( " Completed %i tests " , completed ) ;
2003-03-27 18:24:28 +00:00
2003-03-29 08:46:15 +00:00
if ( completed = = noSpawned )
2003-03-27 18:24:28 +00:00
{
2003-03-29 09:00:40 +00:00
logln ( " Done! All %i tests are finished " , noSpawned ) ;
2003-03-27 18:24:28 +00:00
if ( terrs )
{
errln ( " There were errors. " ) ;
}
ucol_close ( coll ) ;
delete [ ] tests ;
2003-03-28 08:14:43 +00:00
//for(i = 0; i < lineNum; i++) {
//delete[] lines[i].buff;
//}
2003-03-27 18:24:28 +00:00
delete [ ] lines ;
return ;
}
SimpleThread : : sleep ( 900 ) ;
}
errln ( " patience exceeded. " ) ;
ucol_close ( coll ) ;
}
2003-03-31 23:10:33 +00:00
# endif /* #if !UCONFIG_NO_COLLATION */
1999-12-09 23:11:48 +00:00
# endif // ICU_USE_THREADS