1 /********************************************************************
3 * Copyright (c) 2003-2006, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
11 #include "unicode/utypes.h"
12 #include "unicode/putil.h"
13 #include "unicode/uclean.h"
14 #include "unicode/uchar.h"
15 #include "unicode/ures.h"
18 #include "unicode/utrace.h"
23 * This should align the memory properly on any machine.
29 } ctest_AlignedMemory
;
31 static void TestHeapFunctions(void);
32 static void TestMutexFunctions(void);
33 static void TestIncDecFunctions(void);
35 void addHeapMutexTest(TestNode
**root
);
39 addHeapMutexTest(TestNode
** root
)
41 addTest(root
, &TestHeapFunctions
, "hpmufn/TestHeapFunctions" );
42 addTest(root
, &TestMutexFunctions
, "hpmufn/TestMutexFunctions" );
43 addTest(root
, &TestIncDecFunctions
, "hpmufn/TestIncDecFunctions");
46 static int32_t gMutexFailures
= 0;
48 #define TEST_STATUS(status, expected) \
49 if (status != expected) { \
50 log_err("FAIL at %s:%d. Actual status = \"%s\"; Expected status = \"%s\"\n", \
51 __FILE__, __LINE__, u_errorName(status), u_errorName(expected)); gMutexFailures++; }
54 #define TEST_ASSERT(expr) \
56 log_err("FAILED Assertion \"" #expr "\" at %s:%d.\n", __FILE__, __LINE__); \
61 /* These tests do cleanup and reinitialize ICU in the course of their operation.
62 * The ICU data directory must be preserved across these operations.
63 * Here is a helper function to assist with that.
65 static char *safeGetICUDataDirectory() {
66 const char *dataDir
= u_getDataDirectory(); /* Returned string vanashes with u_cleanup */
68 if (dataDir
!= NULL
) {
69 retStr
= (char *)malloc(strlen(dataDir
)+1);
70 strcpy(retStr
, dataDir
);
78 * Test Heap Functions.
79 * Implemented on top of the standard malloc heap.
80 * All blocks increased in size by 8 to 16 bytes, and the poiner returned to ICU is
81 * offset up by 8 to 16, which should cause a good heap corruption if one of our "blocks"
82 * ends up being freed directly, without coming through us.
83 * Allocations are counted, to check that ICU actually does call back to us.
88 static void * U_CALLCONV
myMemAlloc(const void *context
, size_t size
) {
89 char *retPtr
= (char *)malloc(size
+sizeof(ctest_AlignedMemory
));
91 retPtr
+= sizeof(ctest_AlignedMemory
);
97 static void U_CALLCONV
myMemFree(const void *context
, void *mem
) {
98 char *freePtr
= (char *)mem
;
99 if (freePtr
!= NULL
) {
100 freePtr
-= sizeof(ctest_AlignedMemory
);
107 static void * U_CALLCONV
myMemRealloc(const void *context
, void *mem
, size_t size
) {
108 char *p
= (char *)mem
;
112 p
-= sizeof(ctest_AlignedMemory
);
114 retPtr
= realloc(p
, size
+sizeof(ctest_AlignedMemory
));
115 if (retPtr
!= NULL
) {
116 p
+= sizeof(ctest_AlignedMemory
);
122 static void TestHeapFunctions() {
123 UErrorCode status
= U_ZERO_ERROR
;
124 UResourceBundle
*rb
= NULL
;
126 UVersionInfo unicodeVersion
= {0,0,0,0};
128 icuDataDir
= safeGetICUDataDirectory(); /* save icu data dir, so we can put it back
129 * after doing u_cleanup(). */
132 /* Verify that ICU can be cleaned up and reinitialized successfully.
133 * Failure here usually means that some ICU service didn't clean up successfully,
134 * probably because some earlier test accidently left something open. */
137 /* Can not set memory functions if ICU is already initialized */
138 u_setMemoryFunctions(&gContext
, myMemAlloc
, myMemRealloc
, myMemFree
, &status
);
139 TEST_STATUS(status
, U_INVALID_STATE_ERROR
);
141 /* Un-initialize ICU */
144 /* Can not set memory functions with NULL values */
145 status
= U_ZERO_ERROR
;
146 u_setMemoryFunctions(&gContext
, NULL
, myMemRealloc
, myMemFree
, &status
);
147 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
148 status
= U_ZERO_ERROR
;
149 u_setMemoryFunctions(&gContext
, myMemAlloc
, NULL
, myMemFree
, &status
);
150 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
151 status
= U_ZERO_ERROR
;
152 u_setMemoryFunctions(&gContext
, myMemAlloc
, myMemRealloc
, NULL
, &status
);
153 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
155 /* u_setMemoryFunctions() should work with null or non-null context pointer */
156 status
= U_ZERO_ERROR
;
157 u_setMemoryFunctions(NULL
, myMemAlloc
, myMemRealloc
, myMemFree
, &status
);
158 TEST_STATUS(status
, U_ZERO_ERROR
);
159 u_setMemoryFunctions(&gContext
, myMemAlloc
, myMemRealloc
, myMemFree
, &status
);
160 TEST_STATUS(status
, U_ZERO_ERROR
);
163 /* After reinitializing ICU, we should not be able to set the memory funcs again. */
164 status
= U_ZERO_ERROR
;
165 u_setDataDirectory(icuDataDir
);
167 TEST_STATUS(status
, U_ZERO_ERROR
);
168 u_setMemoryFunctions(NULL
, myMemAlloc
, myMemRealloc
, myMemFree
, &status
);
169 TEST_STATUS(status
, U_INVALID_STATE_ERROR
);
171 /* Doing ICU operations should cause allocations to come through our test heap */
173 status
= U_ZERO_ERROR
;
174 rb
= ures_open(NULL
, "es", &status
);
175 TEST_STATUS(status
, U_ZERO_ERROR
);
176 if (gBlockCount
== 0) {
177 log_err("Heap functions are not being called from ICU.\n");
181 /* Cleanup should put the heap back to its default implementation. */
183 u_getUnicodeVersion(unicodeVersion
);
184 if (unicodeVersion
[0] <= 0) {
185 log_err("Properties doesn't reinitialize without u_init.\n");
187 status
= U_ZERO_ERROR
;
189 TEST_STATUS(status
, U_ZERO_ERROR
);
191 /* ICU operations should no longer cause allocations to come through our test heap */
193 status
= U_ZERO_ERROR
;
194 rb
= ures_open(NULL
, "fr", &status
);
195 TEST_STATUS(status
, U_ZERO_ERROR
);
196 if (gBlockCount
!= 0) {
197 log_err("Heap functions did not reset after u_cleanup.\n");
207 * Test u_setMutexFunctions()
210 int gTotalMutexesInitialized
= 0; /* Total number of mutexes created */
211 int gTotalMutexesActive
= 0; /* Total mutexes created, but not destroyed */
212 int gAccumulatedLocks
= 0;
213 const void *gMutexContext
;
215 typedef struct DummyMutex
{
221 static void U_CALLCONV
myMutexInit(const void *context
, UMTX
*mutex
, UErrorCode
*status
) {
222 DummyMutex
*theMutex
;
224 TEST_STATUS(*status
, U_ZERO_ERROR
);
225 theMutex
= (DummyMutex
*)malloc(sizeof(DummyMutex
));
226 theMutex
->fLockCount
= 0;
227 theMutex
->fMagic
= 123456;
228 gTotalMutexesInitialized
++;
229 gTotalMutexesActive
++;
230 gMutexContext
= context
;
235 static void U_CALLCONV
myMutexDestroy(const void *context
, UMTX
*mutex
) {
236 DummyMutex
*This
= *(DummyMutex
**)mutex
;
238 gTotalMutexesActive
--;
239 TEST_ASSERT(This
->fLockCount
== 0);
240 TEST_ASSERT(This
->fMagic
== 123456);
242 This
->fLockCount
= 0;
246 static void U_CALLCONV
myMutexLock(const void *context
, UMTX
*mutex
) {
247 DummyMutex
*This
= *(DummyMutex
**)mutex
;
249 TEST_ASSERT(This
->fMagic
== 123456);
254 static void U_CALLCONV
myMutexUnlock(const void *context
, UMTX
*mutex
) {
255 DummyMutex
*This
= *(DummyMutex
**)mutex
;
257 TEST_ASSERT(This
->fMagic
== 123456);
259 TEST_ASSERT(This
->fLockCount
>= 0);
264 static void TestMutexFunctions() {
265 UErrorCode status
= U_ZERO_ERROR
;
266 UResourceBundle
*rb
= NULL
;
271 /* Save initial ICU state so that it can be restored later.
272 * u_cleanup(), which is called in this test, resets ICU's state.
274 icuDataDir
= safeGetICUDataDirectory();
276 /* Verify that ICU can be cleaned up and reinitialized successfully.
277 * Failure here usually means that some ICU service didn't clean up successfully,
278 * probably because some earlier test accidently left something open. */
281 /* Can not set mutex functions if ICU is already initialized */
282 u_setMutexFunctions(&gContext
, myMutexInit
, myMutexDestroy
, myMutexLock
, myMutexUnlock
, &status
);
283 TEST_STATUS(status
, U_INVALID_STATE_ERROR
);
285 /* Un-initialize ICU */
288 /* Can not set Mutex functions with NULL values */
289 status
= U_ZERO_ERROR
;
290 u_setMutexFunctions(&gContext
, NULL
, myMutexDestroy
, myMutexLock
, myMutexUnlock
, &status
);
291 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
292 status
= U_ZERO_ERROR
;
293 u_setMutexFunctions(&gContext
, myMutexInit
, NULL
, myMutexLock
, myMutexUnlock
, &status
);
294 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
295 status
= U_ZERO_ERROR
;
296 u_setMutexFunctions(&gContext
, myMutexInit
, myMutexDestroy
, NULL
, myMutexUnlock
, &status
);
297 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
298 status
= U_ZERO_ERROR
;
299 u_setMutexFunctions(&gContext
, myMutexInit
, myMutexDestroy
, myMutexLock
, NULL
, &status
);
300 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
302 /* u_setMutexFunctions() should work with null or non-null context pointer */
303 status
= U_ZERO_ERROR
;
304 u_setMutexFunctions(&gContext
, myMutexInit
, myMutexDestroy
, myMutexLock
, myMutexUnlock
, &status
);
305 TEST_STATUS(status
, U_ZERO_ERROR
);
306 u_setMutexFunctions(&gContext
, myMutexInit
, myMutexDestroy
, myMutexLock
, myMutexUnlock
, &status
);
307 TEST_STATUS(status
, U_ZERO_ERROR
);
310 /* After reinitializing ICU, we should not be able to set the mutex funcs again. */
311 status
= U_ZERO_ERROR
;
312 u_setDataDirectory(icuDataDir
);
314 TEST_STATUS(status
, U_ZERO_ERROR
);
315 u_setMutexFunctions(&gContext
, myMutexInit
, myMutexDestroy
, myMutexLock
, myMutexUnlock
, &status
);
316 TEST_STATUS(status
, U_INVALID_STATE_ERROR
);
318 /* Doing ICU operations should cause allocations to come through our test mutexes */
320 status
= U_ZERO_ERROR
;
321 rb
= ures_open(NULL
, "es", &status
);
322 TEST_STATUS(status
, U_ZERO_ERROR
);
323 TEST_ASSERT(gTotalMutexesInitialized
> 0);
324 TEST_ASSERT(gTotalMutexesActive
> 0);
328 /* Cleanup should destroy all of the mutexes. */
330 status
= U_ZERO_ERROR
;
331 TEST_ASSERT(gTotalMutexesInitialized
> 0);
332 TEST_ASSERT(gTotalMutexesActive
== 0);
335 /* Additional ICU operations should no longer use our dummy test mutexes */
336 gTotalMutexesInitialized
= 0;
337 gTotalMutexesActive
= 0;
339 TEST_STATUS(status
, U_ZERO_ERROR
);
341 status
= U_ZERO_ERROR
;
342 rb
= ures_open(NULL
, "fr", &status
);
343 TEST_STATUS(status
, U_ZERO_ERROR
);
344 TEST_ASSERT(gTotalMutexesInitialized
== 0);
345 TEST_ASSERT(gTotalMutexesActive
== 0);
351 log_info("Note: these failures may be caused by ICU failing to initialize/uninitialize properly.\n");
352 log_verbose("Check for prior tests which may not have closed all open resources. See the internal function ures_flushCache()\n");
360 * Test Atomic Increment & Decrement Functions
365 const void *gIncDecContext
;
366 const void *gExpectedContext
= &gIncDecContext
;
369 static int32_t U_CALLCONV
myIncFunc(const void *context
, int32_t *p
) {
371 TEST_ASSERT(context
== gExpectedContext
);
377 static int32_t U_CALLCONV
myDecFunc(const void *context
, int32_t *p
) {
379 TEST_ASSERT(context
== gExpectedContext
);
388 static void TestIncDecFunctions() {
389 UErrorCode status
= U_ZERO_ERROR
;
390 int32_t t
= 1; /* random value to make sure that Inc/dec works */
393 /* Save ICU's data dir and tracing functions so that they can be resored
394 after cleanup and reinit. */
395 dataDir
= safeGetICUDataDirectory();
397 /* Verify that ICU can be cleaned up and reinitialized successfully.
398 * Failure here usually means that some ICU service didn't clean up successfully,
399 * probably because some earlier test accidently left something open. */
402 /* Can not set mutex functions if ICU is already initialized */
403 u_setAtomicIncDecFunctions(&gIncDecContext
, myIncFunc
, myDecFunc
, &status
);
404 TEST_STATUS(status
, U_INVALID_STATE_ERROR
);
409 /* Can not set functions with NULL values */
410 status
= U_ZERO_ERROR
;
411 u_setAtomicIncDecFunctions(&gIncDecContext
, NULL
, myDecFunc
, &status
);
412 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
413 status
= U_ZERO_ERROR
;
414 u_setAtomicIncDecFunctions(&gIncDecContext
, myIncFunc
, NULL
, &status
);
415 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
417 /* u_setIncDecFunctions() should work with null or non-null context pointer */
418 status
= U_ZERO_ERROR
;
419 gExpectedContext
= NULL
;
420 u_setAtomicIncDecFunctions(NULL
, myIncFunc
, myDecFunc
, &status
);
421 TEST_STATUS(status
, U_ZERO_ERROR
);
422 gExpectedContext
= &gIncDecContext
;
423 u_setAtomicIncDecFunctions(&gIncDecContext
, myIncFunc
, myDecFunc
, &status
);
424 TEST_STATUS(status
, U_ZERO_ERROR
);
427 /* After reinitializing ICU, we should not be able to set the inc/dec funcs again. */
428 status
= U_ZERO_ERROR
;
429 u_setDataDirectory(dataDir
);
431 TEST_STATUS(status
, U_ZERO_ERROR
);
432 gExpectedContext
= &gIncDecContext
;
433 u_setAtomicIncDecFunctions(&gIncDecContext
, myIncFunc
, myDecFunc
, &status
);
434 TEST_STATUS(status
, U_INVALID_STATE_ERROR
);
436 /* Doing ICU operations should cause our functions to be called */
443 TEST_ASSERT(gIncCount
> 0);
444 TEST_ASSERT(gDecCount
> 0);
447 /* Cleanup should cancel use of our inc/dec functions. */
448 /* Additional ICU operations should not use them */
452 status
= U_ZERO_ERROR
;
453 u_setDataDirectory(dataDir
);
455 TEST_ASSERT(gIncCount
== 0);
456 TEST_ASSERT(gDecCount
== 0);
458 status
= U_ZERO_ERROR
;
461 TEST_STATUS(status
, U_ZERO_ERROR
);
462 TEST_ASSERT(gIncCount
== 0);
463 TEST_ASSERT(gDecCount
== 0);