1 /********************************************************************
3 * Copyright (c) 2003-2009, 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_status(status, "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(NULL
, 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
;
322 * Note: If we get assertion failures here because
323 * uresbund.c:resbMutex's fMagic is wrong, check if ures_flushCache() did
324 * flush and delete the cache. If it fails to empty the cache, it will not
325 * delete it and ures_cleanup() will not destroy resbMutex.
326 * That would leave a mutex from the default implementation which does not
327 * pass this test implementation's assertions.
329 rb
= ures_open(NULL
, "es", &status
);
330 TEST_STATUS(status
, U_ZERO_ERROR
);
331 TEST_ASSERT(gTotalMutexesInitialized
> 0);
332 TEST_ASSERT(gTotalMutexesActive
> 0);
336 /* Cleanup should destroy all of the mutexes. */
338 status
= U_ZERO_ERROR
;
339 TEST_ASSERT(gTotalMutexesInitialized
> 0);
340 TEST_ASSERT(gTotalMutexesActive
== 0);
343 /* Additional ICU operations should no longer use our dummy test mutexes */
344 gTotalMutexesInitialized
= 0;
345 gTotalMutexesActive
= 0;
347 TEST_STATUS(status
, U_ZERO_ERROR
);
349 status
= U_ZERO_ERROR
;
350 rb
= ures_open(NULL
, "fr", &status
);
351 TEST_STATUS(status
, U_ZERO_ERROR
);
352 TEST_ASSERT(gTotalMutexesInitialized
== 0);
353 TEST_ASSERT(gTotalMutexesActive
== 0);
359 log_info("Note: these failures may be caused by ICU failing to initialize/uninitialize properly.\n");
360 log_verbose("Check for prior tests which may not have closed all open resources. See the internal function ures_flushCache()\n");
368 * Test Atomic Increment & Decrement Functions
373 const void *gIncDecContext
;
374 const void *gExpectedContext
= &gIncDecContext
;
377 static int32_t U_CALLCONV
myIncFunc(const void *context
, int32_t *p
) {
379 TEST_ASSERT(context
== gExpectedContext
);
385 static int32_t U_CALLCONV
myDecFunc(const void *context
, int32_t *p
) {
387 TEST_ASSERT(context
== gExpectedContext
);
396 static void TestIncDecFunctions() {
397 UErrorCode status
= U_ZERO_ERROR
;
398 int32_t t
= 1; /* random value to make sure that Inc/dec works */
401 /* Save ICU's data dir and tracing functions so that they can be resored
402 after cleanup and reinit. */
403 dataDir
= safeGetICUDataDirectory();
405 /* Verify that ICU can be cleaned up and reinitialized successfully.
406 * Failure here usually means that some ICU service didn't clean up successfully,
407 * probably because some earlier test accidently left something open. */
410 /* Can not set mutex functions if ICU is already initialized */
411 u_setAtomicIncDecFunctions(&gIncDecContext
, myIncFunc
, myDecFunc
, &status
);
412 TEST_STATUS(status
, U_INVALID_STATE_ERROR
);
417 /* Can not set functions with NULL values */
418 status
= U_ZERO_ERROR
;
419 u_setAtomicIncDecFunctions(&gIncDecContext
, NULL
, myDecFunc
, &status
);
420 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
421 status
= U_ZERO_ERROR
;
422 u_setAtomicIncDecFunctions(&gIncDecContext
, myIncFunc
, NULL
, &status
);
423 TEST_STATUS(status
, U_ILLEGAL_ARGUMENT_ERROR
);
425 /* u_setIncDecFunctions() should work with null or non-null context pointer */
426 status
= U_ZERO_ERROR
;
427 gExpectedContext
= NULL
;
428 u_setAtomicIncDecFunctions(NULL
, myIncFunc
, myDecFunc
, &status
);
429 TEST_STATUS(status
, U_ZERO_ERROR
);
430 gExpectedContext
= &gIncDecContext
;
431 u_setAtomicIncDecFunctions(&gIncDecContext
, myIncFunc
, myDecFunc
, &status
);
432 TEST_STATUS(status
, U_ZERO_ERROR
);
435 /* After reinitializing ICU, we should not be able to set the inc/dec funcs again. */
436 status
= U_ZERO_ERROR
;
437 u_setDataDirectory(dataDir
);
439 TEST_STATUS(status
, U_ZERO_ERROR
);
440 gExpectedContext
= &gIncDecContext
;
441 u_setAtomicIncDecFunctions(&gIncDecContext
, myIncFunc
, myDecFunc
, &status
);
442 TEST_STATUS(status
, U_INVALID_STATE_ERROR
);
444 /* Doing ICU operations should cause our functions to be called */
451 TEST_ASSERT(gIncCount
> 0);
452 TEST_ASSERT(gDecCount
> 0);
455 /* Cleanup should cancel use of our inc/dec functions. */
456 /* Additional ICU operations should not use them */
460 status
= U_ZERO_ERROR
;
461 u_setDataDirectory(dataDir
);
463 TEST_ASSERT(gIncCount
== 0);
464 TEST_ASSERT(gDecCount
== 0);
466 status
= U_ZERO_ERROR
;
469 TEST_STATUS(status
, U_ZERO_ERROR
);
470 TEST_ASSERT(gIncCount
== 0);
471 TEST_ASSERT(gDecCount
== 0);