/********************************************************************
* COPYRIGHT:
- * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * Copyright (c) 1997-2005, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
/********************************************************************************
#include <string.h>
#include "unicode/utypes.h"
#include "unicode/putil.h"
-
+#include "cstring.h"
#include "cintltst.h"
#include "umutex.h"
-
+#include "uassert.h"
+#include "cmemory.h"
#include "unicode/uchar.h"
#include "unicode/ustring.h"
#include "unicode/ucnv.h"
#include "unicode/ures.h"
#include "unicode/uclean.h"
+#include "unicode/ucal.h"
+#include "uoptions.h"
+#include "putilimp.h" /* for uprv_getUTCtime() */
#ifdef XP_MAC_CONSOLE
# include <console.h>
#define CTST_LEAK_CHECK 1
#ifdef CTST_LEAK_CHECK
U_CFUNC void ctst_freeAll(void);
-U_CFUNC void ctst_init(void);
#endif
static char* _testDataPath=NULL;
*/
void ctest_setICU_DATA(void);
-static UBool gMutexInitialized = FALSE;
-
-static void TestMutex(void) {
- if (!gMutexInitialized) {
- log_verbose("*** Failure! The global mutex was not initialized.\n"
- "*** Make sure the right linker was used.\n");
- }
-}
-
-U_CFUNC void addSetup(TestNode** root);
-void addSetup(TestNode** root)
-{
- addTest(root, &TestMutex, "setup/TestMutex");
-}
#if UCONFIG_NO_LEGACY_CONVERSION
# define TRY_CNV_1 "iso-8859-1"
# define TRY_CNV_2 "sjis"
#endif
+
+/*
+ * Tracing functions.
+ */
+static int traceFnNestingDepth = 0;
+U_CDECL_BEGIN
+static void U_CALLCONV TraceEntry(const void *context, int32_t fnNumber) {
+ char buf[500];
+ utrace_format(buf, sizeof(buf), traceFnNestingDepth*3, "%s() enter.\n", utrace_functionName(fnNumber));
+ buf[sizeof(buf)-1]=0;
+ fputs(buf, stdout);
+ traceFnNestingDepth++;
+}
+
+static void U_CALLCONV TraceExit(const void *context, int32_t fnNumber, const char *fmt, va_list args) {
+ char buf[500];
+
+ if (traceFnNestingDepth>0) {
+ traceFnNestingDepth--;
+ }
+ utrace_format(buf, sizeof(buf), traceFnNestingDepth*3, "%s() ", utrace_functionName(fnNumber));
+ buf[sizeof(buf)-1]=0;
+ fputs(buf, stdout);
+ utrace_vformat(buf, sizeof(buf), traceFnNestingDepth*3, fmt, args);
+ buf[sizeof(buf)-1]=0;
+ fputs(buf, stdout);
+ putc('\n', stdout);
+}
+
+static void U_CALLCONV TraceData(const void *context, int32_t fnNumber,
+ int32_t level, const char *fmt, va_list args) {
+ char buf[500];
+ utrace_vformat(buf, sizeof(buf), traceFnNestingDepth*3, fmt, args);
+ buf[sizeof(buf)-1]=0;
+ fputs(buf, stdout);
+ putc('\n', stdout);
+}
+U_CDECL_END
+
+
+
int main(int argc, const char* const argv[])
{
int nerrors = 0;
int warnOnMissingData = 0;
- int i;
+ int i, j;
+ UBool defaultDataFound;
TestNode *root;
const char *warnOrErr = "Failure";
+ const char** argv2;
+ UDate startTime, endTime;
+ int32_t diffTime;
/* initial check for the default converter */
UErrorCode errorCode = U_ZERO_ERROR;
UResourceBundle *rb;
UConverter *cnv;
- /* This must be tested before using anything! */
- gMutexInitialized = umtx_isInitialized(NULL);
+ U_MAIN_INIT_ARGS(argc, argv);
+
+ startTime = uprv_getUTCtime();
+
+ argv2 = (const char**) malloc(sizeof(char*) * argc);
+ if (argv2 == NULL) {
+ printf("*** Error: Out of memory (too many cmd line args?)\n");
+ return 1;
+ }
+ argv2[0] = argv[0];
+
/* Checkargs */
- for(i=1;i<argc;i++) {
+ /* TODO: Test framework arg handling needs to be decoupled from test execution
+ * so that the args being processed here don't need special handling,
+ * separate from the other test args.
+ */
+ ICU_TRACE = UTRACE_OFF;
+ for(i=1,j=1;i<argc;i++) {
+ argv2[j++] = argv[i];
if(!strcmp(argv[i],"-w")) {
warnOnMissingData = 1;
warnOrErr = "Warning";
}
+ else if (strcmp( argv[i], "-t_error") == 0) {
+ ICU_TRACE = UTRACE_ERROR;
+ }
+ else if (strcmp( argv[i], "-t_warn") == 0) {
+ ICU_TRACE = UTRACE_WARNING;
+ }
+ else if (strcmp( argv[i], "-t_oc") == 0) {
+ ICU_TRACE = UTRACE_OPEN_CLOSE;
+ }
+ else if (strcmp( argv[i], "-t_info") == 0) {
+ ICU_TRACE = UTRACE_INFO;
+ }
+ else if (strcmp( argv[i], "-t_verbose") == 0) {
+ ICU_TRACE = UTRACE_VERBOSE;
+ }
}
-
- while (REPEAT_TESTS > 0) {
-
-#ifdef CTST_LEAK_CHECK
- ctst_init();
-#endif
- /* try opening the data from dll instead of the dat file */
- cnv = ucnv_open(TRY_CNV_1, &errorCode);
- if(cnv != 0) {
- /* ok */
- ucnv_close(cnv);
- } else {
+ argc = j;
+
+
+ utrace_setFunctions(NULL, TraceEntry, TraceExit, TraceData);
+ utrace_setLevel(ICU_TRACE);
+
+
+ while (REPEAT_TESTS > 0) { /* Loop runs once per complete execution of the tests
+ * used for -r (repeat) test option. */
+
+ /* Check whether ICU will initialize without forcing the build data directory into
+ * the ICU_DATA path. Success here means either the data dll contains data, or that
+ * this test program was run with ICU_DATA set externally. Failure of this check
+ * is normal when ICU data is not packaged into a shared library.
+ *
+ * Whether or not this test succeeds, we want to cleanup and reinitialize
+ * with a data path so that data loading from individual files can be tested.
+ */
+ defaultDataFound = TRUE;
+ u_init(&errorCode);
+ if (U_FAILURE(errorCode)) {
fprintf(stderr,
- "#### WARNING! The converter for " TRY_CNV_1 " cannot be loaded from data dll/so."
- "Proceeding to load data from dat file.\n");
- errorCode = U_ZERO_ERROR;
-
- ctest_setICU_DATA();
+ "#### Note: ICU Init without build-specific setDataDirectory() failed.\n");
+ defaultDataFound = FALSE;
}
-
- /* If no ICU_DATA environment was set, try to fake up one. */
- /* fprintf(stderr, "u_getDataDirectory() = %s\n", u_getDataDirectory()); */
-
-#ifdef XP_MAC_CONSOLE
- argc = ccommand((char***)&argv);
-#endif
-
- cnv = ucnv_open(NULL, &errorCode);
- if(cnv != NULL) {
- /* ok */
- ucnv_close(cnv);
- } else {
+ u_cleanup();
+ errorCode = U_ZERO_ERROR;
+ utrace_setFunctions(NULL, TraceEntry, TraceExit, TraceData);
+ utrace_setLevel(ICU_TRACE);
+
+ /* Initialize ICU */
+ if (!defaultDataFound) {
+ ctest_setICU_DATA(); /* u_setDataDirectory() must happen Before u_init() */
+ }
+ u_init(&errorCode);
+ if (U_FAILURE(errorCode)) {
fprintf(stderr,
- "*** %s! The default converter cannot be opened.\n"
+ "#### ERROR! %s: u_init() failed with status = \"%s\".\n"
"*** Check the ICU_DATA environment variable and \n"
- "*** check that the data files are present.\n", warnOrErr);
- if(warnOnMissingData == 0) {
- fprintf(stderr, "*** Exitting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
- return 1;
- }
+ "*** check that the data files are present.\n", argv[0], u_errorName(errorCode));
+ if(warnOnMissingData == 0) {
+ fprintf(stderr, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
+ u_cleanup();
+ return 1;
+ }
}
+
+
/* try more data */
cnv = ucnv_open(TRY_CNV_2, &errorCode);
"*** check that the data files are present.\n", warnOrErr);
if(warnOnMissingData == 0) {
fprintf(stderr, "*** Exitting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
+ u_cleanup();
return 1;
}
}
"*** check that the data files are present.\n", warnOrErr);
if(warnOnMissingData == 0) {
fprintf(stderr, "*** Exitting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
+ u_cleanup();
return 1;
}
}
fprintf(stdout, "Default locale for this run is %s\n", uloc_getDefault());
+ /* Build a tree of all tests.
+ * Subsequently will be used to find / iterate the tests to run */
root = NULL;
addAllTests(&root);
- nerrors = processArgs(root, argc, argv);
+
+ /* Tests acutally run HERE. TODO: separate command line option parsing & setting from test execution!! */
+ nerrors = processArgs(root, argc, argv2);
+
if (--REPEAT_TESTS > 0) {
printf("Repeating tests %d more time(s)\n", REPEAT_TESTS);
}
cleanUpTestTree(root);
+
#ifdef CTST_LEAK_CHECK
ctst_freeAll();
-
/* To check for leaks */
-
u_cleanup(); /* nuke the hashtable.. so that any still-open cnvs are leaked */
#endif
- }
- if (!gMutexInitialized) {
- fprintf(stderr,
- "#### WARNING!\n"
- " The global mutex was not initialized during C++ static initialization.\n"
- " You must explicitly initialize ICU by calling u_init() before using ICU in multiple threads.\n"
- " If you are using ICU in a single threaded application, use of u_init() is recommended,\n"
- " but is not required.\n"
- "#### WARNING!\n"
- );
- }
+ } /* End of loop that repeats the entire test, if requested. (Normally doesn't loop) */
+
+ free((void*)argv2);
+
+ endTime = uprv_getUTCtime();
+ diffTime = (int32_t)(endTime - startTime);
+ printf("Elapsed Time: %02d:%02d:%02d.%03d\n",
+ (int)((diffTime%U_MILLIS_PER_DAY)/U_MILLIS_PER_HOUR),
+ (int)((diffTime%U_MILLIS_PER_HOUR)/U_MILLIS_PER_MINUTE),
+ (int)((diffTime%U_MILLIS_PER_MINUTE)/U_MILLIS_PER_SECOND),
+ (int)(diffTime%U_MILLIS_PER_SECOND));
return nerrors ? 1 : 0;
}
}
*/
-void
-ctest_pathnameInContext( char* fullname, int32_t maxsize, const char* relPath )
-{
- char mainDirBuffer[1024];
- char* mainDir = NULL;
- const char *dataDirectory = ctest_dataOutDir();
- const char inpSepChar = '|';
- char* tmp;
- int32_t lenMainDir;
- int32_t lenRelPath;
-
-#ifdef XP_MAC
- Str255 volName;
- int16_t volNum;
- OSErr err = GetVol( volName, &volNum );
- if (err != noErr)
- volName[0] = 0;
- mainDir = (char*) &(volName[1]);
- mainDir[volName[0]] = 0;
-#else
- if (dataDirectory != NULL) {
- strcpy(mainDirBuffer, dataDirectory);
- strcat(mainDirBuffer, ".." U_FILE_SEP_STRING);
- } else {
- mainDirBuffer[0]='\0';
- }
- mainDir = mainDirBuffer;
-#endif
-
- lenMainDir = (int32_t)strlen(mainDir);
- if(lenMainDir > 0 && mainDir[lenMainDir - 1] != U_FILE_SEP_CHAR) {
- mainDir[lenMainDir++] = U_FILE_SEP_CHAR;
- mainDir[lenMainDir] = 0;
- }
-
- if (relPath[0] == '|')
- relPath++;
- lenRelPath = (int32_t)strlen(relPath);
- if (maxsize < lenMainDir + lenRelPath + 2) {
- fullname[0] = 0;
- return;
- }
- strcpy(fullname, mainDir);
- /*strcat(fullname, U_FILE_SEP_STRING);*/
- strcat(fullname, relPath);
- strchr(fullname, inpSepChar);
- tmp = strchr(fullname, inpSepChar);
- while (tmp) {
- *tmp = U_FILE_SEP_CHAR;
- tmp = strchr(tmp+1, inpSepChar);
- }
-}
-
-
/* returns the path to icu/source/data */
const char * ctest_dataSrcDir()
{
char *pBackSlash;
int i;
- dataSrcDir = p;
strcpy(p, __FILE__);
/* We want to back over three '\' chars. */
/* Only Windows should end up here, so looking for '\' is safe. */
* Now append "source\data" and set the environment
*/
strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING );
+ dataSrcDir = p;
}
else {
/* __FILE__ on MSVC7 does not contain the directory */
- strcpy(p, ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING);
+ FILE *file = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "Makefile.in", "r");
+ if (file) {
+ fclose(file);
+ dataSrcDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
+ }
+ else {
+ dataSrcDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
+ }
}
}
#endif
*/
#if defined (U_TOPBUILDDIR)
{
- dataOutDir = U_TOPBUILDDIR U_FILE_SEP_STRING "data"U_FILE_SEP_STRING"out"U_FILE_SEP_STRING;
+ dataOutDir = U_TOPBUILDDIR "data"U_FILE_SEP_STRING"out"U_FILE_SEP_STRING;
}
#else
char *pBackSlash;
int i;
- dataOutDir = p;
strcpy(p, __FILE__);
/* We want to back over three '\' chars. */
/* Only Windows should end up here, so looking for '\' is safe. */
* Now append "source\data" and set the environment
*/
strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING);
+ dataOutDir = p;
}
else {
/* __FILE__ on MSVC7 does not contain the directory */
- strcpy(p, ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING);
+ FILE *file = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "Makefile.in", "r");
+ if (file) {
+ fclose(file);
+ dataOutDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
+ }
+ else {
+ dataOutDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
+ }
}
}
#endif
*/
void ctest_setICU_DATA() {
-
/* No location for the data dir was identifiable.
* Add other fallbacks for the test data location here if the need arises
*/
- u_setDataDirectory(ctest_dataOutDir());
+ if (getenv("ICU_DATA") == NULL) {
+ /* If ICU_DATA isn't set, set it to the usual location */
+ u_setDataDirectory(ctest_dataOutDir());
+ }
}
UChar* CharsToUChars(const char* str) {
}
const char* loadTestData(UErrorCode* err){
- const char* directory=NULL;
- UResourceBundle* test =NULL;
- char* tdpath=NULL;
- const char* tdrelativepath = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING"out"U_FILE_SEP_STRING;
if( _testDataPath == NULL){
+ const char* directory=NULL;
+ UResourceBundle* test =NULL;
+ char* tdpath=NULL;
+ const char* tdrelativepath;
+#if defined (U_TOPBUILDDIR)
+ tdrelativepath = "test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING"out"U_FILE_SEP_STRING;
+ directory = U_TOPBUILDDIR;
+#else
+ tdrelativepath = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING"out"U_FILE_SEP_STRING;
directory= ctest_dataOutDir();
+#endif
tdpath = (char*) ctst_malloc(sizeof(char) *(( strlen(directory) * strlen(tdrelativepath)) + 10));
return _testDataPath;
}
+#define CTEST_MAX_TIMEZONE_SIZE 256
+static UChar gOriginalTimeZone[CTEST_MAX_TIMEZONE_SIZE] = {0};
+
+/**
+ * Call this once to get a consistent timezone. Use ctest_resetTimeZone to set it back to the original value.
+ * @param optionalTimeZone Set this to a requested timezone.
+ * Set to NULL to use the standard test timezone (Pacific Time)
+ */
+U_CFUNC void ctest_setTimeZone(const char *optionalTimeZone, UErrorCode *status) {
+#if !UCONFIG_NO_FORMATTING
+ UChar zoneID[CTEST_MAX_TIMEZONE_SIZE];
+
+ if (optionalTimeZone == NULL) {
+ optionalTimeZone = "America/Los_Angeles";
+ }
+ if (gOriginalTimeZone[0]) {
+ log_err("*** Error: time zone saved twice. New value will be %s\n",
+ optionalTimeZone);
+ }
+ ucal_getDefaultTimeZone(gOriginalTimeZone, CTEST_MAX_TIMEZONE_SIZE, status);
+ if (U_FAILURE(*status)) {
+ log_err("*** Error: Failed to save default time zone: %s\n",
+ u_errorName(*status));
+ *status = U_ZERO_ERROR;
+ }
+
+ u_uastrncpy(zoneID, optionalTimeZone, CTEST_MAX_TIMEZONE_SIZE-1);
+ zoneID[CTEST_MAX_TIMEZONE_SIZE-1] = 0;
+ ucal_setDefaultTimeZone(zoneID, status);
+ if (U_FAILURE(*status)) {
+ log_err("*** Error: Failed to set default time zone to \"%s\": %s\n",
+ optionalTimeZone, u_errorName(*status));
+ }
+#endif
+}
+
+/**
+ * Call this once get back the original timezone
+ */
+U_CFUNC void ctest_resetTimeZone(void) {
+#if !UCONFIG_NO_FORMATTING
+ UErrorCode status = U_ZERO_ERROR;
+
+ ucal_setDefaultTimeZone(gOriginalTimeZone, &status);
+ if (U_FAILURE(status)) {
+ log_err("*** Error: Failed to reset default time zone: %s\n",
+ u_errorName(status));
+ }
+ /* Set to an empty state */
+ gOriginalTimeZone[0] = 0;
+#endif
+}
+
#define CTST_MAX_ALLOC 10000
/* Array used as a queue */
-static void * ctst_allocated_stuff[CTST_MAX_ALLOC];
+static void * ctst_allocated_stuff[CTST_MAX_ALLOC] = {0};
static int ctst_allocated = 0;
static UBool ctst_free = FALSE;
-void ctst_init(void) {
- int i;
- for(i=0; i<CTST_MAX_ALLOC; i++) {
- ctst_allocated_stuff[i] = NULL;
- }
-}
-
void *ctst_malloc(size_t size) {
if(ctst_allocated >= CTST_MAX_ALLOC - 1) {
ctst_allocated = 0;
if(ctst_free == 0) {
for(i=0; i<ctst_allocated; i++) {
free(ctst_allocated_stuff[i]);
+ ctst_allocated_stuff[i] = NULL;
}
} else {
for(i=0; i<CTST_MAX_ALLOC; i++) {
free(ctst_allocated_stuff[i]);
+ ctst_allocated_stuff[i] = NULL;
}
}
+ ctst_allocated = 0;
_testDataPath=NULL;
}
+
+#define VERBOSE_ASSERTIONS
+
+U_CFUNC UBool assertSuccess(const char* msg, UErrorCode* ec) {
+ U_ASSERT(ec!=NULL);
+ if (U_FAILURE(*ec)) {
+ log_err("FAIL: %s (%s)\n", msg, u_errorName(*ec));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* if 'condition' is a UBool, the compiler complains bitterly about
+ expressions like 'a > 0' which it evaluates as int */
+U_CFUNC UBool assertTrue(const char* msg, int /*not UBool*/ condition) {
+ if (!condition) {
+ log_err("FAIL: assertTrue() failed: %s\n", msg);
+ }
+#ifdef VERBOSE_ASSERTIONS
+ else {
+ log_verbose("Ok: %s\n", msg);
+ }
+#endif
+ return (UBool)condition;
+}
+
+U_CFUNC UBool assertEquals(const char* message, const char* expected,
+ const char* actual) {
+ if (uprv_strcmp(expected, actual) != 0) {
+ log_err("FAIL: %s; got \"%s\"; expected \"%s\"\n",
+ message, actual, expected);
+ return FALSE;
+ }
+#ifdef VERBOSE_ASSERTIONS
+ else {
+ log_verbose("Ok: %s; got \"%s\"\n", message, actual);
+ }
+#endif
+ return TRUE;
+}
+/*--------------------------------------------------------------------
+ * Time bomb - allows temporary behavior that expires at a given
+ * release
+ *--------------------------------------------------------------------
+ */
+
+U_CFUNC UBool isICUVersionAtLeast(const UVersionInfo x) {
+ UVersionInfo v;
+ u_getVersion(v);
+ return (uprv_memcmp(v, x, U_MAX_VERSION_LENGTH) >= 0);
+}
#endif