Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10)

Unified Diff: icu46/source/test/cintltst/hpmufn.c

Issue 5516007: Check in the pristine copy of ICU 4.6... (Closed) Base URL: svn://chrome-svn/chrome/trunk/deps/third_party/
Patch Set: Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « icu46/source/test/cintltst/eurocreg.c ('k') | icu46/source/test/cintltst/idnatest.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: icu46/source/test/cintltst/hpmufn.c
===================================================================
--- icu46/source/test/cintltst/hpmufn.c (revision 0)
+++ icu46/source/test/cintltst/hpmufn.c (revision 0)
@@ -0,0 +1,475 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2003-2009, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+/*
+* File hpmufn.c
+*
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/putil.h"
+#include "unicode/uclean.h"
+#include "unicode/uchar.h"
+#include "unicode/ures.h"
+#include "cintltst.h"
+#include "umutex.h"
+#include "unicode/utrace.h"
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * This should align the memory properly on any machine.
+ */
+typedef union {
+ long t1;
+ double t2;
+ void *t3;
+} ctest_AlignedMemory;
+
+static void TestHeapFunctions(void);
+static void TestMutexFunctions(void);
+static void TestIncDecFunctions(void);
+
+void addHeapMutexTest(TestNode **root);
+
+
+void
+addHeapMutexTest(TestNode** root)
+{
+ addTest(root, &TestHeapFunctions, "hpmufn/TestHeapFunctions" );
+ addTest(root, &TestMutexFunctions, "hpmufn/TestMutexFunctions" );
+ addTest(root, &TestIncDecFunctions, "hpmufn/TestIncDecFunctions");
+}
+
+static int32_t gMutexFailures = 0;
+
+#define TEST_STATUS(status, expected) \
+if (status != expected) { \
+log_err_status(status, "FAIL at %s:%d. Actual status = \"%s\"; Expected status = \"%s\"\n", \
+ __FILE__, __LINE__, u_errorName(status), u_errorName(expected)); gMutexFailures++; }
+
+
+#define TEST_ASSERT(expr) \
+if (!(expr)) { \
+ log_err("FAILED Assertion \"" #expr "\" at %s:%d.\n", __FILE__, __LINE__); \
+ gMutexFailures++; \
+}
+
+
+/* These tests do cleanup and reinitialize ICU in the course of their operation.
+ * The ICU data directory must be preserved across these operations.
+ * Here is a helper function to assist with that.
+ */
+static char *safeGetICUDataDirectory() {
+ const char *dataDir = u_getDataDirectory(); /* Returned string vanashes with u_cleanup */
+ char *retStr = NULL;
+ if (dataDir != NULL) {
+ retStr = (char *)malloc(strlen(dataDir)+1);
+ strcpy(retStr, dataDir);
+ }
+ return retStr;
+}
+
+
+
+/*
+ * Test Heap Functions.
+ * Implemented on top of the standard malloc heap.
+ * All blocks increased in size by 8 to 16 bytes, and the poiner returned to ICU is
+ * offset up by 8 to 16, which should cause a good heap corruption if one of our "blocks"
+ * ends up being freed directly, without coming through us.
+ * Allocations are counted, to check that ICU actually does call back to us.
+ */
+int gBlockCount = 0;
+const void *gContext;
+
+static void * U_CALLCONV myMemAlloc(const void *context, size_t size) {
+ char *retPtr = (char *)malloc(size+sizeof(ctest_AlignedMemory));
+ if (retPtr != NULL) {
+ retPtr += sizeof(ctest_AlignedMemory);
+ }
+ gBlockCount ++;
+ return retPtr;
+}
+
+static void U_CALLCONV myMemFree(const void *context, void *mem) {
+ char *freePtr = (char *)mem;
+ if (freePtr != NULL) {
+ freePtr -= sizeof(ctest_AlignedMemory);
+ }
+ free(freePtr);
+}
+
+
+
+static void * U_CALLCONV myMemRealloc(const void *context, void *mem, size_t size) {
+ char *p = (char *)mem;
+ char *retPtr;
+
+ if (p!=NULL) {
+ p -= sizeof(ctest_AlignedMemory);
+ }
+ retPtr = realloc(p, size+sizeof(ctest_AlignedMemory));
+ if (retPtr != NULL) {
+ p += sizeof(ctest_AlignedMemory);
+ }
+ return retPtr;
+}
+
+
+static void TestHeapFunctions() {
+ UErrorCode status = U_ZERO_ERROR;
+ UResourceBundle *rb = NULL;
+ char *icuDataDir;
+ UVersionInfo unicodeVersion = {0,0,0,0};
+
+ icuDataDir = safeGetICUDataDirectory(); /* save icu data dir, so we can put it back
+ * after doing u_cleanup(). */
+
+
+ /* Verify that ICU can be cleaned up and reinitialized successfully.
+ * Failure here usually means that some ICU service didn't clean up successfully,
+ * probably because some earlier test accidently left something open. */
+ ctest_resetICU();
+
+ /* Can not set memory functions if ICU is already initialized */
+ u_setMemoryFunctions(&gContext, myMemAlloc, myMemRealloc, myMemFree, &status);
+ TEST_STATUS(status, U_INVALID_STATE_ERROR);
+
+ /* Un-initialize ICU */
+ u_cleanup();
+
+ /* Can not set memory functions with NULL values */
+ status = U_ZERO_ERROR;
+ u_setMemoryFunctions(&gContext, NULL, myMemRealloc, myMemFree, &status);
+ TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR);
+ status = U_ZERO_ERROR;
+ u_setMemoryFunctions(&gContext, myMemAlloc, NULL, myMemFree, &status);
+ TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR);
+ status = U_ZERO_ERROR;
+ u_setMemoryFunctions(&gContext, myMemAlloc, myMemRealloc, NULL, &status);
+ TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR);
+
+ /* u_setMemoryFunctions() should work with null or non-null context pointer */
+ status = U_ZERO_ERROR;
+ u_setMemoryFunctions(NULL, myMemAlloc, myMemRealloc, myMemFree, &status);
+ TEST_STATUS(status, U_ZERO_ERROR);
+ u_setMemoryFunctions(&gContext, myMemAlloc, myMemRealloc, myMemFree, &status);
+ TEST_STATUS(status, U_ZERO_ERROR);
+
+
+ /* After reinitializing ICU, we should not be able to set the memory funcs again. */
+ status = U_ZERO_ERROR;
+ u_setDataDirectory(icuDataDir);
+ u_init(&status);
+ TEST_STATUS(status, U_ZERO_ERROR);
+ u_setMemoryFunctions(NULL, myMemAlloc, myMemRealloc, myMemFree, &status);
+ TEST_STATUS(status, U_INVALID_STATE_ERROR);
+
+ /* Doing ICU operations should cause allocations to come through our test heap */
+ gBlockCount = 0;
+ status = U_ZERO_ERROR;
+ rb = ures_open(NULL, "es", &status);
+ TEST_STATUS(status, U_ZERO_ERROR);
+ if (gBlockCount == 0) {
+ log_err("Heap functions are not being called from ICU.\n");
+ }
+ ures_close(rb);
+
+ /* Cleanup should put the heap back to its default implementation. */
+ ctest_resetICU();
+ u_getUnicodeVersion(unicodeVersion);
+ if (unicodeVersion[0] <= 0) {
+ log_err("Properties doesn't reinitialize without u_init.\n");
+ }
+ status = U_ZERO_ERROR;
+ u_init(&status);
+ TEST_STATUS(status, U_ZERO_ERROR);
+
+ /* ICU operations should no longer cause allocations to come through our test heap */
+ gBlockCount = 0;
+ status = U_ZERO_ERROR;
+ rb = ures_open(NULL, "fr", &status);
+ TEST_STATUS(status, U_ZERO_ERROR);
+ if (gBlockCount != 0) {
+ log_err("Heap functions did not reset after u_cleanup.\n");
+ }
+ ures_close(rb);
+ free(icuDataDir);
+
+ ctest_resetICU();
+}
+
+
+/*
+ * Test u_setMutexFunctions()
+ */
+
+int gTotalMutexesInitialized = 0; /* Total number of mutexes created */
+int gTotalMutexesActive = 0; /* Total mutexes created, but not destroyed */
+int gAccumulatedLocks = 0;
+const void *gMutexContext;
+
+typedef struct DummyMutex {
+ int fLockCount;
+ int fMagic;
+} DummyMutex;
+
+
+static void U_CALLCONV myMutexInit(const void *context, UMTX *mutex, UErrorCode *status) {
+ DummyMutex *theMutex;
+
+ TEST_STATUS(*status, U_ZERO_ERROR);
+ theMutex = (DummyMutex *)malloc(sizeof(DummyMutex));
+ theMutex->fLockCount = 0;
+ theMutex->fMagic = 123456;
+ gTotalMutexesInitialized++;
+ gTotalMutexesActive++;
+ gMutexContext = context;
+ *mutex = theMutex;
+}
+
+
+static void U_CALLCONV myMutexDestroy(const void *context, UMTX *mutex) {
+ DummyMutex *This = *(DummyMutex **)mutex;
+
+ gTotalMutexesActive--;
+ TEST_ASSERT(This->fLockCount == 0);
+ TEST_ASSERT(This->fMagic == 123456);
+ This->fMagic = 0;
+ This->fLockCount = 0;
+ free(This);
+}
+
+static void U_CALLCONV myMutexLock(const void *context, UMTX *mutex) {
+ DummyMutex *This = *(DummyMutex **)mutex;
+
+ TEST_ASSERT(This->fMagic == 123456);
+ This->fLockCount++;
+ gAccumulatedLocks++;
+}
+
+static void U_CALLCONV myMutexUnlock(const void *context, UMTX *mutex) {
+ DummyMutex *This = *(DummyMutex **)mutex;
+
+ TEST_ASSERT(This->fMagic == 123456);
+ This->fLockCount--;
+ TEST_ASSERT(This->fLockCount >= 0);
+}
+
+
+
+static void TestMutexFunctions() {
+ UErrorCode status = U_ZERO_ERROR;
+ UResourceBundle *rb = NULL;
+ char *icuDataDir;
+
+ gMutexFailures = 0;
+
+ /* Save initial ICU state so that it can be restored later.
+ * u_cleanup(), which is called in this test, resets ICU's state.
+ */
+ icuDataDir = safeGetICUDataDirectory();
+
+ /* Verify that ICU can be cleaned up and reinitialized successfully.
+ * Failure here usually means that some ICU service didn't clean up successfully,
+ * probably because some earlier test accidently left something open. */
+ ctest_resetICU();
+
+ /* Can not set mutex functions if ICU is already initialized */
+ u_setMutexFunctions(&gContext, myMutexInit, myMutexDestroy, myMutexLock, myMutexUnlock, &status);
+ TEST_STATUS(status, U_INVALID_STATE_ERROR);
+
+ /* Un-initialize ICU */
+ u_cleanup();
+
+ /* Can not set Mutex functions with NULL values */
+ status = U_ZERO_ERROR;
+ u_setMutexFunctions(&gContext, NULL, myMutexDestroy, myMutexLock, myMutexUnlock, &status);
+ TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR);
+ status = U_ZERO_ERROR;
+ u_setMutexFunctions(&gContext, myMutexInit, NULL, myMutexLock, myMutexUnlock, &status);
+ TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR);
+ status = U_ZERO_ERROR;
+ u_setMutexFunctions(&gContext, myMutexInit, myMutexDestroy, NULL, myMutexUnlock, &status);
+ TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR);
+ status = U_ZERO_ERROR;
+ u_setMutexFunctions(&gContext, myMutexInit, myMutexDestroy, myMutexLock, NULL, &status);
+ TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR);
+
+ /* u_setMutexFunctions() should work with null or non-null context pointer */
+ status = U_ZERO_ERROR;
+ u_setMutexFunctions(NULL, myMutexInit, myMutexDestroy, myMutexLock, myMutexUnlock, &status);
+ TEST_STATUS(status, U_ZERO_ERROR);
+ u_setMutexFunctions(&gContext, myMutexInit, myMutexDestroy, myMutexLock, myMutexUnlock, &status);
+ TEST_STATUS(status, U_ZERO_ERROR);
+
+
+ /* After reinitializing ICU, we should not be able to set the mutex funcs again. */
+ status = U_ZERO_ERROR;
+ u_setDataDirectory(icuDataDir);
+ u_init(&status);
+ TEST_STATUS(status, U_ZERO_ERROR);
+ u_setMutexFunctions(&gContext, myMutexInit, myMutexDestroy, myMutexLock, myMutexUnlock, &status);
+ TEST_STATUS(status, U_INVALID_STATE_ERROR);
+
+ /* Doing ICU operations should cause allocations to come through our test mutexes */
+ gBlockCount = 0;
+ status = U_ZERO_ERROR;
+ /*
+ * Note: If we get assertion failures here because
+ * uresbund.c:resbMutex's fMagic is wrong, check if ures_flushCache() did
+ * flush and delete the cache. If it fails to empty the cache, it will not
+ * delete it and ures_cleanup() will not destroy resbMutex.
+ * That would leave a mutex from the default implementation which does not
+ * pass this test implementation's assertions.
+ */
+ rb = ures_open(NULL, "es", &status);
+ TEST_STATUS(status, U_ZERO_ERROR);
+ TEST_ASSERT(gTotalMutexesInitialized > 0);
+ TEST_ASSERT(gTotalMutexesActive > 0);
+
+ ures_close(rb);
+
+ /* Cleanup should destroy all of the mutexes. */
+ ctest_resetICU();
+ status = U_ZERO_ERROR;
+ TEST_ASSERT(gTotalMutexesInitialized > 0);
+ TEST_ASSERT(gTotalMutexesActive == 0);
+
+
+ /* Additional ICU operations should no longer use our dummy test mutexes */
+ gTotalMutexesInitialized = 0;
+ gTotalMutexesActive = 0;
+ u_init(&status);
+ TEST_STATUS(status, U_ZERO_ERROR);
+
+ status = U_ZERO_ERROR;
+ rb = ures_open(NULL, "fr", &status);
+ TEST_STATUS(status, U_ZERO_ERROR);
+ TEST_ASSERT(gTotalMutexesInitialized == 0);
+ TEST_ASSERT(gTotalMutexesActive == 0);
+
+ ures_close(rb);
+ free(icuDataDir);
+
+ if(gMutexFailures) {
+ log_info("Note: these failures may be caused by ICU failing to initialize/uninitialize properly.\n");
+ log_verbose("Check for prior tests which may not have closed all open resources. See the internal function ures_flushCache()\n");
+ }
+}
+
+
+
+
+/*
+ * Test Atomic Increment & Decrement Functions
+ */
+
+int gIncCount = 0;
+int gDecCount = 0;
+const void *gIncDecContext;
+const void *gExpectedContext = &gIncDecContext;
+
+
+static int32_t U_CALLCONV myIncFunc(const void *context, int32_t *p) {
+ int32_t retVal;
+ TEST_ASSERT(context == gExpectedContext);
+ gIncCount++;
+ retVal = ++(*p);
+ return retVal;
+}
+
+static int32_t U_CALLCONV myDecFunc(const void *context, int32_t *p) {
+ int32_t retVal;
+ TEST_ASSERT(context == gExpectedContext);
+ gDecCount++;
+ retVal = --(*p);
+ return retVal;
+}
+
+
+
+
+static void TestIncDecFunctions() {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t t = 1; /* random value to make sure that Inc/dec works */
+ char *dataDir;
+
+ /* Save ICU's data dir and tracing functions so that they can be resored
+ after cleanup and reinit. */
+ dataDir = safeGetICUDataDirectory();
+
+ /* Verify that ICU can be cleaned up and reinitialized successfully.
+ * Failure here usually means that some ICU service didn't clean up successfully,
+ * probably because some earlier test accidently left something open. */
+ ctest_resetICU();
+
+ /* Can not set mutex functions if ICU is already initialized */
+ u_setAtomicIncDecFunctions(&gIncDecContext, myIncFunc, myDecFunc, &status);
+ TEST_STATUS(status, U_INVALID_STATE_ERROR);
+
+ /* Clean up ICU */
+ u_cleanup();
+
+ /* Can not set functions with NULL values */
+ status = U_ZERO_ERROR;
+ u_setAtomicIncDecFunctions(&gIncDecContext, NULL, myDecFunc, &status);
+ TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR);
+ status = U_ZERO_ERROR;
+ u_setAtomicIncDecFunctions(&gIncDecContext, myIncFunc, NULL, &status);
+ TEST_STATUS(status, U_ILLEGAL_ARGUMENT_ERROR);
+
+ /* u_setIncDecFunctions() should work with null or non-null context pointer */
+ status = U_ZERO_ERROR;
+ gExpectedContext = NULL;
+ u_setAtomicIncDecFunctions(NULL, myIncFunc, myDecFunc, &status);
+ TEST_STATUS(status, U_ZERO_ERROR);
+ gExpectedContext = &gIncDecContext;
+ u_setAtomicIncDecFunctions(&gIncDecContext, myIncFunc, myDecFunc, &status);
+ TEST_STATUS(status, U_ZERO_ERROR);
+
+
+ /* After reinitializing ICU, we should not be able to set the inc/dec funcs again. */
+ status = U_ZERO_ERROR;
+ u_setDataDirectory(dataDir);
+ u_init(&status);
+ TEST_STATUS(status, U_ZERO_ERROR);
+ gExpectedContext = &gIncDecContext;
+ u_setAtomicIncDecFunctions(&gIncDecContext, myIncFunc, myDecFunc, &status);
+ TEST_STATUS(status, U_INVALID_STATE_ERROR);
+
+ /* Doing ICU operations should cause our functions to be called */
+ gIncCount = 0;
+ gDecCount = 0;
+ umtx_atomic_inc(&t);
+ TEST_ASSERT(t == 2);
+ umtx_atomic_dec(&t);
+ TEST_ASSERT(t == 1);
+ TEST_ASSERT(gIncCount > 0);
+ TEST_ASSERT(gDecCount > 0);
+
+
+ /* Cleanup should cancel use of our inc/dec functions. */
+ /* Additional ICU operations should not use them */
+ ctest_resetICU();
+ gIncCount = 0;
+ gDecCount = 0;
+ status = U_ZERO_ERROR;
+ u_setDataDirectory(dataDir);
+ u_init(&status);
+ TEST_ASSERT(gIncCount == 0);
+ TEST_ASSERT(gDecCount == 0);
+
+ status = U_ZERO_ERROR;
+ umtx_atomic_inc(&t);
+ umtx_atomic_dec(&t);
+ TEST_STATUS(status, U_ZERO_ERROR);
+ TEST_ASSERT(gIncCount == 0);
+ TEST_ASSERT(gDecCount == 0);
+
+ free(dataDir);
+}
+
Property changes on: icu46/source/test/cintltst/hpmufn.c
___________________________________________________________________
Added: svn:eol-style
+ LF
« no previous file with comments | « icu46/source/test/cintltst/eurocreg.c ('k') | icu46/source/test/cintltst/idnatest.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698