X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/46f4442e9a5a4f3b98b7c1083586332f6a8a99a4..151279e3792e85d0417b499c229886b3af724f55:/icuSources/test/intltest/tsmthred.cpp?ds=inline diff --git a/icuSources/test/intltest/tsmthred.cpp b/icuSources/test/intltest/tsmthred.cpp index 772d3518..c6e8a8ce 100644 --- a/icuSources/test/intltest/tsmthred.cpp +++ b/icuSources/test/intltest/tsmthred.cpp @@ -1,6 +1,6 @@ /******************************************************************** * COPYRIGHT: - * Copyright (c) 1999-2008, International Business Machines Corporation and + * Copyright (c) 1999-2012, International Business Machines Corporation and * others. All Rights Reserved. ********************************************************************/ @@ -10,10 +10,7 @@ # endif #endif -/* Needed by z/OS to get usleep */ -#if !defined(_XOPEN_SOURCE_EXTENDED) -#define _XOPEN_SOURCE_EXTENDED 1 -#endif +#include "simplethread.h" #include "unicode/utypes.h" #include "unicode/ustring.h" @@ -21,16 +18,38 @@ #include "cmemory.h" #include "cstring.h" #include "uparse.h" +#include "unicode/localpointer.h" #include "unicode/resbund.h" #include "unicode/udata.h" #include "unicode/uloc.h" #include "unicode/locid.h" #include "putilimp.h" -#if !defined(U_WINDOWS) && !defined(XP_MAC) && !defined(U_RHAPSODY) -#define POSIX 1 +#include "intltest.h" +#include "tsmthred.h" +#include "unicode/ushape.h" + + +#if U_PLATFORM_USES_ONLY_WIN32_API + /* Prefer native Windows APIs even if POSIX is implemented (i.e., on Cygwin). */ +# undef POSIX +#elif U_PLATFORM_IMPLEMENTS_POSIX +# define POSIX +#else +# undef POSIX #endif -#if defined(POSIX) || defined(U_SOLARIS) || defined(U_AIX) || defined(U_HPUX) + +#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) +/* Needed by z/OS to get usleep */ +#if U_PLATFORM == U_PF_OS390 +#define __DOT1 1 +#define __UU +#ifndef _XPG4_2 +#define _XPG4_2 +#endif +#include +#endif +#if defined(POSIX) #define HAVE_IMP @@ -49,7 +68,13 @@ #define __EXTENSIONS__ #endif +#if U_PLATFORM == U_PF_OS390 +#include +#endif + +#if U_PLATFORM != U_PF_OS390 #include +#endif /* Define _XPG4_2 for Solaris and friends. */ #ifndef _XPG4_2 @@ -74,10 +99,6 @@ #undef sleep #endif - - -#include "tsmthred.h" - #define TSMTHREAD_FAIL(msg) errln("%s at file %s, line %d", msg, __FILE__, __LINE__) #define TSMTHREAD_ASSERT(expr) {if (!(expr)) {TSMTHREAD_FAIL("Fail");}} @@ -106,380 +127,25 @@ void MultithreadTest::runIndexedTest( int32_t index, UBool exec, } #else - - -// 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 #include #include // tolower, toupper #include "unicode/putil.h" -/* for mthreadtest*/ +// for mthreadtest #include "unicode/numfmt.h" #include "unicode/choicfmt.h" #include "unicode/msgfmt.h" #include "unicode/locid.h" -#include "unicode/ucol.h" +#include "unicode/coll.h" #include "unicode/calendar.h" #include "ucaconf.h" -//----------------------------------------------------------------------------------- -// -// class SimpleThread Of course we need a thread class first.. -// This wrapper has a ported implementation. -// -//----------------------------------------------------------------------------------- -class SimpleThread -{ -public: - SimpleThread(); - virtual ~SimpleThread(); - int32_t start(void); // start the thread - UBool isRunning(); // return true if a started thread has exited. - - virtual void run(void) = 0; // Override this to provide the code to run - // in the thread. - void *fImplementation; - -public: - static void sleep(int32_t millis); // probably shouldn't go here but oh well. - static void errorFunc(); // Empty function, provides a single convenient place - // to break on errors. -}; - void SimpleThread::errorFunc() { // *(char *)0 = 3; // Force entry into a debugger via a crash; } - - - -#ifdef U_WINDOWS -#define HAVE_IMP - -# define VC_EXTRALEAN -# define WIN32_LEAN_AND_MEAN -# define NOUSER -# define NOSERVICE -# define NOIME -# define NOMCX -#include -#include - - - -//----------------------------------------------------------------------------------- -// -// class SimpleThread Windows Implementation -// -//----------------------------------------------------------------------------------- -struct Win32ThreadImplementation -{ - HANDLE fHandle; - unsigned int fThreadID; -}; - - -extern "C" unsigned int __stdcall SimpleThreadProc(void *arg) -{ - ((SimpleThread*)arg)->run(); - return 0; -} - -SimpleThread::SimpleThread() -:fImplementation(0) -{ - Win32ThreadImplementation *imp = new Win32ThreadImplementation; - imp->fHandle = 0; - fImplementation = imp; -} - -SimpleThread::~SimpleThread() -{ - // Destructor. Because we start the thread running with _beginthreadex(), - // we own the Windows HANDLE for the thread and must - // close it here. - Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation; - if (imp != 0) { - if (imp->fHandle != 0) { - CloseHandle(imp->fHandle); - imp->fHandle = 0; - } - } - delete (Win32ThreadImplementation*)fImplementation; -} - -int32_t SimpleThread::start() -{ - Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation; - 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; - } - - imp->fHandle = (HANDLE) _beginthreadex( - NULL, // Security - 0x20000, // Stack Size - SimpleThreadProc, // Function to Run - (void *)this, // Arg List - 0, // initflag. Start running, not suspended - &imp->fThreadID // thraddr - ); - - if (imp->fHandle == 0) { - // An error occured - int err = errno; - if (err == 0) { - err = -1; - } - return err; - } - return 0; -} - - -UBool SimpleThread::isRunning() { - // - // Test whether the thread associated with the SimpleThread object is - // still actually running. - // - // NOTE: on Win64 on Itanium processors, a crashes - // occur if the main thread of a process exits concurrently with some - // other thread(s) exiting. To avoid the possibility, we wait until the - // OS indicates that all threads have terminated, rather than waiting - // only until the end of the user's Run function has been reached. - // - // I don't know whether the crashes represent a Windows bug, or whether - // main() programs are supposed to have to wait for their threads. - // - Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation; - - bool success; - DWORD threadExitCode; - - if (imp->fHandle == 0) { - // No handle, thread must not be running. - return FALSE; - } - success = GetExitCodeThread(imp->fHandle, &threadExitCode) != 0; - if (! success) { - // Can't get status, thread must not be running. - return FALSE; - } - return (threadExitCode == STILL_ACTIVE); -} - - -void SimpleThread::sleep(int32_t millis) -{ - ::Sleep(millis); -} - -//----------------------------------------------------------------------------------- -// -// class SimpleThread NULL Implementation -// -//----------------------------------------------------------------------------------- -#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() -{} - -int32_t -SimpleThread::start() -{ return 0; } - -void -SimpleThread::run() -{} - -void -SimpleThread::sleep(int32_t millis) -{} - -UBool -SimpleThread::isRunning() { - return FALSE; -} - -#endif - - -//----------------------------------------------------------------------------------- -// -// class SimpleThread POSIX implementation -// -// A note on the POSIX vs the Windows implementations of this class.. -// On Windows, the main thread must verify that other threads have finished -// before exiting, or crashes occasionally occur. (Seen on Itanium Win64 only) -// The function SimpleThread::isRunning() is used for this purpose. -// -// On POSIX, there is NO reliable non-blocking mechanism to determine -// whether a thread has exited. pthread_kill(thread, 0) almost works, -// but the system can recycle thread ids immediately, so seeing that a -// thread exists with this call could mean that the original thread has -// finished and a new one started with the same ID. Useless. -// -// So we need to do the check with user code, by setting a flag just before -// the thread function returns. A technique that is guaranteed to fail -// on Windows, because it indicates that the thread is done before all -// system level cleanup has happened. -// -//----------------------------------------------------------------------------------- -#if defined(POSIX)||defined(U_SOLARIS)||defined(U_AIX)||defined(U_HPUX) -#define HAVE_IMP - -struct PosixThreadImplementation -{ - pthread_t fThread; - UBool fRunning; - UBool fRan; /* True if the thread was successfully started */ -}; - -extern "C" void* SimpleThreadProc(void *arg) -{ - // This is the code that is run in the new separate thread. - SimpleThread *This = (SimpleThread *)arg; - This->run(); // Run the user code. - - // The user function has returned. Set the flag indicating that this thread - // is done. Need a mutex for memory barrier purposes only, so that other thread - // will reliably see that the flag has changed. - PosixThreadImplementation *imp = (PosixThreadImplementation*)This->fImplementation; - umtx_lock(NULL); - imp->fRunning = FALSE; - umtx_unlock(NULL); - return 0; -} - -SimpleThread::SimpleThread() -{ - PosixThreadImplementation *imp = new PosixThreadImplementation; - imp->fRunning = FALSE; - imp->fRan = FALSE; - fImplementation = imp; -} - -SimpleThread::~SimpleThread() -{ - PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation; - if (imp->fRan) { - pthread_join(imp->fThread, NULL); - } - delete imp; - fImplementation = (void *)0xdeadbeef; -} - -int32_t SimpleThread::start() -{ - int32_t rc; - static pthread_attr_t attr; - static UBool attrIsInitialized = FALSE; - - PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation; - imp->fRunning = TRUE; - imp->fRan = TRUE; - -#ifdef HPUX_CMA - if (attrIsInitialized == FALSE) { - rc = pthread_attr_create(&attr); - attrIsInitialized = TRUE; - } - rc = pthread_create(&(imp->fThread),attr,&SimpleThreadProc,(void*)this); -#else - if (attrIsInitialized == FALSE) { - rc = pthread_attr_init(&attr); -#if defined(OS390) - { - int detachstate = 0; /* jdc30: detach state of zero causes - threads created with this attr to be in - an undetached state. An undetached - thread will keep its resources after - termination. */ - pthread_attr_setdetachstate(&attr, &detachstate); - } -#else - // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); -#endif - attrIsInitialized = TRUE; - } - rc = pthread_create(&(imp->fThread),&attr,&SimpleThreadProc,(void*)this); -#endif - - if (rc != 0) { - // some kind of error occured, the thread did not start. - imp->fRan = FALSE; - imp->fRunning = FALSE; - } - - return rc; -} - - -UBool -SimpleThread::isRunning() { - // Note: Mutex functions are used here not for synchronization, - // but to force memory barriors to exist, to ensure that one thread - // can see changes made by another when running on processors - // with memory models having weak coherency. - PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation; - umtx_lock(NULL); - UBool retVal = imp->fRunning; - umtx_unlock(NULL); - return retVal; -} - - -void SimpleThread::sleep(int32_t millis) -{ -#ifdef U_SOLARIS - sigignore(SIGALRM); -#endif - -#ifdef HPUX_CMA - cma_sleep(millis/100); -#elif defined(U_HPUX) || defined(OS390) - millis *= 1000; - while(millis >= 1000000) { - usleep(999999); - millis -= 1000000; - } - if(millis > 0) { - usleep(millis); - } -#else - usleep(millis * 1000); -#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. */ void MultithreadTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) { if (exec) @@ -522,6 +188,14 @@ void MultithreadTest::runIndexedTest( int32_t index, UBool exec, } break; + case 5: + name = "TestArabicShapingThreads"; + if (exec) { + TestArabicShapingThreads(); + } + break; + + default: name = ""; break; //needed to end loop @@ -539,6 +213,7 @@ void MultithreadTest::runIndexedTest( int32_t index, UBool exec, // //----------------------------------------------------------------------------------- #define THREADTEST_NRTHREADS 8 +#define ARABICSHAPE_THREADTEST 30 class TestThreadsThread : public SimpleThread { @@ -550,6 +225,75 @@ public: } private: char *fWhatToChange; +}; +//----------------------------------------------------------------------------------- +// +// TestArabicShapeThreads -- see if calls to u_shapeArabic in many threads works successfully +// +// Set up N threads pointing at N chars. When they are started, they will make calls to doTailTest which tests +// u_shapeArabic, if the calls are successful it will the set * chars. +// At the end we make sure all threads managed to run u_shapeArabic successfully. +// This is a unit test for ticket 9473 +// +//----------------------------------------------------------------------------------- +class TestArabicShapeThreads : public SimpleThread +{ +public: + TestArabicShapeThreads(char* whatToChange) { fWhatToChange = whatToChange;} + virtual void run() { + if(doTailTest()==TRUE) + *fWhatToChange = '*'; + } +private: + char *fWhatToChange; + + UBool doTailTest(void) { + static const UChar src[] = { 0x0020, 0x0633, 0 }; + static const UChar dst_old[] = { 0xFEB1, 0x200B,0 }; + static const UChar dst_new[] = { 0xFEB1, 0xFE73,0 }; + UChar dst[3] = { 0x0000, 0x0000,0 }; + int32_t length; + UErrorCode status; + IntlTest inteltst = IntlTest(); + + status = U_ZERO_ERROR; + length = u_shapeArabic(src, -1, dst, LENGTHOF(dst), + U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR, &status); + if(U_FAILURE(status)) { + inteltst.errln("Fail: status %s\n", u_errorName(status)); + return FALSE; + } else if(length!=2) { + inteltst.errln("Fail: len %d expected 3\n", length); + return FALSE; + } else if(u_strncmp(dst,dst_old,LENGTHOF(dst))) { + inteltst.errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n", + dst[0],dst[1],dst_old[0],dst_old[1]); + return FALSE; + } + + + //"Trying new tail + status = U_ZERO_ERROR; + length = u_shapeArabic(src, -1, dst, LENGTHOF(dst), + U_SHAPE_LETTERS_SHAPE|U_SHAPE_SEEN_TWOCELL_NEAR|U_SHAPE_TAIL_NEW_UNICODE, &status); + if(U_FAILURE(status)) { + inteltst.errln("Fail: status %s\n", u_errorName(status)); + return FALSE; + } else if(length!=2) { + inteltst.errln("Fail: len %d expected 3\n", length); + return FALSE; + } else if(u_strncmp(dst,dst_new,LENGTHOF(dst))) { + inteltst.errln("Fail: got U+%04X U+%04X expected U+%04X U+%04X\n", + dst[0],dst[1],dst_new[0],dst_new[1]); + return FALSE; + } + + + return TRUE; + +} + + }; void MultithreadTest::TestThreads() @@ -622,6 +366,78 @@ void MultithreadTest::TestThreads() } +void MultithreadTest::TestArabicShapingThreads() +{ + char threadTestChars[ARABICSHAPE_THREADTEST + 1]; + SimpleThread *threads[ARABICSHAPE_THREADTEST]; + int32_t numThreadsStarted = 0; + + int32_t i; + + for(i=0;i do TestArabicShapingThreads <- Firing off threads.. "); + for(i=0;istart() != 0) { + errln("Error starting thread %d", i); + } + else { + numThreadsStarted++; + } + //SimpleThread::sleep(100); + logln(" Subthread started."); + } + + logln("Waiting for threads to be set.."); + if (numThreadsStarted == 0) { + errln("No threads could be started for testing!"); + return; + } + + int32_t patience = 100; // seconds to wait + + while(patience--) + { + int32_t count = 0; + umtx_lock(NULL); + for(i=0;iTestArabicShapingThreads <- Got all threads! cya"); + for(i=0;i TestArabicShapingThreads <- Waiting.."); + SimpleThread::sleep(500); + } + + errln("-> TestArabicShapingThreads <- PATIENCE EXCEEDED!! Still missing some."); + for(i=0;i percentFormatter; UErrorCode status = U_ZERO_ERROR; #if 0 @@ -979,15 +789,15 @@ public: int32_t iteration; status = U_ZERO_ERROR; - formatter = NumberFormat::createInstance(Locale::getEnglish(),status); + LocalPointer formatter(NumberFormat::createInstance(Locale::getEnglish(),status)); if(U_FAILURE(status)) { - error("Error on NumberFormat::createInstance()"); + error("Error on NumberFormat::createInstance()."); goto cleanupAndReturn; } - percentFormatter = NumberFormat::createPercentInstance(Locale::getFrench(),status); + percentFormatter.adoptInstead(NumberFormat::createPercentInstance(Locale::getFrench(),status)); if(U_FAILURE(status)) { - error("Error on NumberFormat::createPercentInstance()"); + error("Error on NumberFormat::createPercentInstance()."); goto cleanupAndReturn; } @@ -1050,7 +860,7 @@ public: countryToCheck= Locale("","BF"); currencyToCheck= 2.32; expected= CharsToUnicodeString( - "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing 2,32\\u00A0DM."); + "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing 2,32\\u00A0DEM."); break; case 2: statusToCheck= U_MEMORY_ALLOCATION_ERROR; @@ -1087,9 +897,6 @@ public: } /* end of for loop */ cleanupAndReturn: - delete formatter; - delete percentFormatter; - // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing fTraceInfo = 2; } @@ -1112,14 +919,14 @@ void MultithreadTest::TestThreadedIntl() // logln("Spawning: %d threads * %d iterations each.", kFormatThreadThreads, kFormatThreadIterations); - FormatThreadTest *tests = new FormatThreadTest[kFormatThreadThreads]; + LocalArray tests(new FormatThreadTest[kFormatThreadThreads]); for(int32_t j = 0; j < kFormatThreadThreads; j++) { tests[j].fNum = j; int32_t threadStatus = tests[j].start(); if (threadStatus != 0) { errln("System Error %d starting thread number %d.", threadStatus, j); SimpleThread::errorFunc(); - goto cleanupAndReturn; + return; } haveDisplayedInfo[j] = FALSE; } @@ -1149,7 +956,7 @@ void MultithreadTest::TestThreadedIntl() } else if (haveDisplayedInfo[i] == FALSE) { logln("Thread # %d is complete..", i); if(tests[i].getError(theErr)) { - errln(UnicodeString("#") + i + ": " + theErr); + dataerrln(UnicodeString("#") + i + ": " + theErr); SimpleThread::errorFunc(); } haveDisplayedInfo[i] = TRUE; @@ -1160,8 +967,6 @@ void MultithreadTest::TestThreadedIntl() // // All threads have finished. // -cleanupAndReturn: - delete [] tests; } #endif /* #if !UCONFIG_NO_FORMATTING */ @@ -1184,78 +989,96 @@ struct Line { int32_t buflen; } ; +static UBool +skipLineBecauseOfBug(const UChar *s, int32_t length) { + // TODO: Fix ICU ticket #8052 + if(length >= 3 && + (s[0] == 0xfb2 || s[0] == 0xfb3) && + s[1] == 0x334 && + (s[2] == 0xf73 || s[2] == 0xf75 || s[2] == 0xf81)) { + return TRUE; + } + return FALSE; +} + +static UCollationResult +normalizeResult(int32_t result) { + return result<0 ? UCOL_LESS : result==0 ? UCOL_EQUAL : UCOL_GREATER; +} + class CollatorThreadTest : public ThreadWithStatus { private: - const UCollator *coll; + const Collator *coll; const Line *lines; int32_t noLines; + UBool isAtLeastUCA62; public: CollatorThreadTest() : ThreadWithStatus(), coll(NULL), lines(NULL), - noLines(0) + noLines(0), + isAtLeastUCA62(TRUE) { }; - void setCollator(UCollator *c, Line *l, int32_t nl) + void setCollator(Collator *c, Line *l, int32_t nl, UBool atLeastUCA62) { coll = c; lines = l; noLines = nl; + isAtLeastUCA62 = atLeastUCA62; } virtual void run() { - //sleep(10000); - int32_t line = 0; - uint8_t sk1[1024], sk2[1024]; uint8_t *oldSk = NULL, *newSk = sk1; - int32_t resLen = 0, oldLen = 0; + int32_t oldLen = 0; + int32_t prev = 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(lines[i].buflen == 0) { continue; } + + if(skipLineBecauseOfBug(lines[i].buff, lines[i].buflen)) { continue; } + + int32_t resLen = coll->getSortKey(lines[i].buff, lines[i].buflen, newSk, 1024); + 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); - //cmpres = res; - //cmpres2 = -cmpres; - + int32_t skres = strcmp((char *)oldSk, (char *)newSk); + int32_t cmpres = coll->compare(lines[prev].buff, lines[prev].buflen, lines[i].buff, lines[i].buflen); + int32_t cmpres2 = coll->compare(lines[i].buff, lines[i].buflen, lines[prev].buff, lines[prev].buflen); + if(cmpres != -cmpres2) { - error("Compare result not symmetrical on line "+ line); + error(UnicodeString("Compare result not symmetrical on line ") + (i + 1)); break; } - - 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(cmpres != normalizeResult(skres)) { + error(UnicodeString("Difference between coll->compare and sortkey compare on line ") + (i + 1)); break; } - + + int32_t res = cmpres; + if(res == 0 && !isAtLeastUCA62) { + // Up to UCA 6.1, the collation test files use a custom tie-breaker, + // comparing the raw input strings. + res = u_strcmpCodePointOrder(lines[prev].buff, lines[i].buff); + // Starting with UCA 6.2, the collation test files use the standard UCA tie-breaker, + // comparing the NFD versions of the input strings, + // which we do via setting strength=identical. + } if(res > 0) { - error(UnicodeString("Line %i is not greater or equal than previous line ")+ UnicodeString(i)); + error(UnicodeString("Line is not greater or equal than previous line, for line ") + (i + 1)); 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)); - break; - } } } - + oldSk = newSk; oldLen = resLen; - + prev = i; + newSk = (newSk == sk1)?sk2:sk1; } } - }; void MultithreadTest::TestCollators() @@ -1304,7 +1127,7 @@ void MultithreadTest::TestCollators() if (testFile == 0) { *(buffer+bufLen) = 0; - dataerrln("[DATA] could not open any of the conformance test files, tried opening base %s", buffer); + dataerrln("could not open any of the conformance test files, tried opening base %s", buffer); return; } else { infoln( @@ -1316,55 +1139,58 @@ void MultithreadTest::TestCollators() } } - Line *lines = new Line[200000]; - memset(lines, 0, sizeof(Line)*200000); + LocalArray lines(new Line[200000]); + memset(lines.getAlias(), 0, sizeof(Line)*200000); 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 || strlen(buffer) < 3 || buffer[0] == '#') { - continue; + if(*buffer == 0 || buffer[0] == '#') { + // Store empty and comment lines so that errors are reported + // for the real test file lines. + lines[lineNum].buflen = 0; + lines[lineNum].buff[0] = 0; + } else { + int32_t buflen = u_parseString(buffer, bufferU, 1024, &first, &status); + lines[lineNum].buflen = buflen; + u_memcpy(lines[lineNum].buff, bufferU, buflen); + lines[lineNum].buff[buflen] = 0; } - offset = u_parseString(buffer, bufferU, 1024, &first, &status); - buflen = offset; - bufferU[offset++] = 0; - lines[lineNum].buflen = buflen; - //lines[lineNum].buff = new UChar[buflen+1]; - u_memcpy(lines[lineNum].buff, bufferU, buflen); lineNum++; } fclose(testFile); if(U_FAILURE(status)) { - dataerrln("[DATA] Couldn't read the test file!"); + dataerrln("Couldn't read the test file!"); return; } - UCollator *coll = ucol_open("root", &status); + UVersionInfo uniVersion; + static const UVersionInfo v62 = { 6, 2, 0, 0 }; + u_getUnicodeVersion(uniVersion); + UBool isAtLeastUCA62 = uprv_memcmp(uniVersion, v62, 4) >= 0; + + LocalPointer coll(Collator::createInstance(Locale::getRoot(), status)); if(U_FAILURE(status)) { - errln("Couldn't open UCA collator"); + errcheckln(status, "Couldn't open UCA collator"); return; } - ucol_setAttribute(coll, UCOL_NORMALIZATION_MODE, UCOL_ON, &status); - 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); + coll->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status); + coll->setAttribute(UCOL_CASE_FIRST, UCOL_OFF, status); + coll->setAttribute(UCOL_CASE_LEVEL, UCOL_OFF, status); + coll->setAttribute(UCOL_STRENGTH, isAtLeastUCA62 ? UCOL_IDENTICAL : UCOL_TERTIARY, status); + coll->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE, status); int32_t noSpawned = 0; int32_t spawnResult = 0; - CollatorThreadTest *tests; - tests = new CollatorThreadTest[kCollatorThreadThreads]; + LocalArray tests(new CollatorThreadTest[kCollatorThreadThreads]); logln(UnicodeString("Spawning: ") + kCollatorThreadThreads + " threads * " + kFormatThreadIterations + " iterations each."); int32_t j = 0; for(j = 0; j < kCollatorThreadThreads; j++) { //logln("Setting collator %i", j); - tests[j].setCollator(coll, lines, lineNum); + tests[j].setCollator(coll.getAlias(), lines.getAlias(), lineNum, isAtLeastUCA62); } for(j = 0; j < kCollatorThreadThreads; j++) { log("%i ", j); @@ -1417,13 +1243,6 @@ void MultithreadTest::TestCollators() errln("There were errors."); SimpleThread::errorFunc(); } - ucol_close(coll); - delete[] tests; - //for(i = 0; i < lineNum; i++) { - //delete[] lines[i].buff; - //} - delete[] lines; - return; } @@ -1431,7 +1250,6 @@ void MultithreadTest::TestCollators() } errln("patience exceeded. "); SimpleThread::errorFunc(); - ucol_close(coll); } #endif /* #if !UCONFIG_NO_COLLATION */ @@ -1501,6 +1319,9 @@ void MultithreadTest::TestString() UnicodeString *testString = new UnicodeString("This is the original test string."); + // Not using LocalArray tests[kStringThreadThreads]; + // because we don't always want to delete them. + // See the comments below the cleanupAndReturn label. StringThreadTest2 *tests[kStringThreadThreads]; for(j = 0; j < kStringThreadThreads; j++) { tests[j] = new StringThreadTest2(testString, j); @@ -1578,9 +1399,4 @@ cleanupAndReturn: } } - - - - #endif // ICU_USE_THREADS -