X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/374ca955a76ecab1204ca8bfa63ff9238d998416..b331163bffd790ced0e88b73f44f86d49ccc48a5:/icuSources/tools/ctestfw/ctest.c?ds=inline diff --git a/icuSources/tools/ctestfw/ctest.c b/icuSources/tools/ctestfw/ctest.c index f493be14..da641f2d 100644 --- a/icuSources/tools/ctestfw/ctest.c +++ b/icuSources/tools/ctestfw/ctest.c @@ -1,18 +1,22 @@ /* -***************************************************************************************** +******************************************************************************** * -* Copyright (C) 1996-2004, International Business Machines +* Copyright (C) 1996-2014, International Business Machines * Corporation and others. All Rights Reserved. * -***************************************************************************************** +******************************************************************************** */ #include #include #include #include #include +#include #include "unicode/utrace.h" +#include "unicode/uclean.h" +#include "putilimp.h" +#include "udbgutil.h" /* NOTES: 3/20/1999 srl - strncpy called w/o setting nulls at the end @@ -22,12 +26,25 @@ #define MAXTESTS 512 #define MAX_TEST_LOG 4096 +/** + * How may columns to indent the 'OK' markers. + */ +#define FLAG_INDENT 45 +/** + * How many lines of scrollage can go by before we need to remind the user what the test is. + */ +#define PAGE_SIZE_LIMIT 25 + +#ifndef SHOW_TIMES +#define SHOW_TIMES 1 +#endif + struct TestNode { - char name[MAXTESTNAME]; void (*test)(void); struct TestNode* sibling; struct TestNode* child; + char name[1]; /* This is dynamically allocated off the end with malloc. */ }; @@ -47,7 +64,7 @@ static char ERROR_LOG[MAX_TEST_LOG][MAXTESTNAME]; /* Local prototypes */ static TestNode* addTestNode( TestNode *root, const char *name ); -static TestNode* createTestNode(); +static TestNode *createTestNode(const char* name, int32_t nameLen); static int strncmp_nullcheck( const char* s1, const char* s2, @@ -57,8 +74,8 @@ static void getNextLevel( const char* name, int* nameLen, const char** nextName ); -static void iterateTestsWithLevel( const TestNode *root, int len, - const TestNode** list, +static void iterateTestsWithLevel( const TestNode *root, int depth, + const TestNode** nodeList, TestMode mode); static void help ( const char *argv0 ); @@ -72,14 +89,34 @@ static void help ( const char *argv0 ); */ static void vlog_err(const char *prefix, const char *pattern, va_list ap); static void vlog_verbose(const char *prefix, const char *pattern, va_list ap); +static UBool vlog_knownIssue(const char *ticket, const char *pattern, va_list ap); + +/** + * Log test structure, with indent + * @param pattern printf pattern + */ +static void log_testinfo_i(const char *pattern, ...); + +/** + * Log test structure, NO indent + * @param pattern printf pattern + */ +static void log_testinfo(const char *pattern, ...); /* If we need to make the framework multi-thread safe we need to pass around the following vars */ static int ERRONEOUS_FUNCTION_COUNT = 0; static int ERROR_COUNT = 0; /* Count of errors from all tests. */ +static int ONE_ERROR = 0; /* were there any other errors? */ static int DATA_ERROR_COUNT = 0; /* count of data related errors or warnings */ static int INDENT_LEVEL = 0; +static UBool NO_KNOWN = FALSE; +static void *knownList = NULL; +static char gTestName[1024] = ""; +static UBool ON_LINE = FALSE; /* are we on the top line with our test name? */ +static UBool HANGING_OUTPUT = FALSE; /* did the user leave us without a trailing \n ? */ +static int GLOBAL_PRINT_COUNT = 0; /* global count of printouts */ int REPEAT_TESTS_INIT = 0; /* Was REPEAT_TESTS initialized? */ int REPEAT_TESTS = 1; /* Number of times to run the test */ int VERBOSITY = 0; /* be No-verbose by default */ @@ -87,6 +124,13 @@ int ERR_MSG =1; /* error messages will be displayed by default*/ int QUICK = 1; /* Skip some of the slower tests? */ int WARN_ON_MISSING_DATA = 0; /* Reduce data errs to warnings? */ UTraceLevel ICU_TRACE = UTRACE_OFF; /* ICU tracing level */ +size_t MINIMUM_MEMORY_SIZE_FAILURE = (size_t)-1; /* Minimum library memory allocation window that will fail. */ +size_t MAXIMUM_MEMORY_SIZE_FAILURE = (size_t)-1; /* Maximum library memory allocation window that will fail. */ +static const char *ARGV_0 = "[ALL]"; +static const char *XML_FILE_NAME=NULL; +static char XML_PREFIX[256]; +static const char *SUMMARY_FILE = NULL; +FILE *XML_FILE = NULL; /*-------------------------------------------*/ /* strncmp that also makes sure there's a \0 at s2[0] */ @@ -123,17 +167,19 @@ static void getNextLevel( const char* name, } } -static TestNode *createTestNode( ) +static TestNode *createTestNode(const char* name, int32_t nameLen) { TestNode *newNode; - newNode = (TestNode*)malloc ( sizeof ( TestNode ) ); + newNode = (TestNode*)malloc(sizeof(TestNode) + (nameLen + 1)); - newNode->name[0] = '\0'; newNode->test = NULL; newNode->sibling = NULL; newNode->child = NULL; + strncpy( newNode->name, name, nameLen ); + newNode->name[nameLen] = 0; + return newNode; } @@ -148,6 +194,7 @@ cleanUpTestTree(TestNode *tn) } free(tn); + } @@ -160,7 +207,7 @@ addTest(TestNode** root, /*if this is the first Test created*/ if (*root == NULL) - *root = createTestNode(); + *root = createTestNode("", 0); newNode = addTestNode( *root, name ); assert(newNode != 0 ); @@ -198,14 +245,11 @@ static TestNode *addTestNode ( TestNode *root, const char *name ) /* Add all children of the node */ do { - curNode->child = createTestNode ( ); - /* Get the next component of the name */ - getNextLevel ( name, &nameLen, &nextName ); + getNextLevel(name, &nameLen, &nextName); /* update curName to have the next name segment */ - strncpy ( curNode->child->name , name, nameLen ); - curNode->child->name[nameLen] = 0; + curNode->child = createTestNode(name, nameLen); /* printf("*** added %s\n", curNode->child->name );*/ curNode = curNode->child; name = nextName; @@ -224,9 +268,7 @@ static TestNode *addTestNode ( TestNode *root, const char *name ) if ( nextNode == NULL ) { /* Did not find 'name' on this level. */ - nextNode = createTestNode ( ); - strncpy( nextNode->name, name, nameLen ); - nextNode->name[nameLen] = 0; + nextNode = createTestNode(name, nameLen); curNode->sibling = nextNode; break; } @@ -245,60 +287,202 @@ static TestNode *addTestNode ( TestNode *root, const char *name ) } } +/** + * Log the time taken. May not output anything. + * @param deltaTime change in time + */ +void T_CTEST_EXPORT2 str_timeDelta(char *str, UDate deltaTime) { + if (deltaTime > 110000.0 ) { + double mins = uprv_floor(deltaTime/60000.0); + sprintf(str, "[(%.0fm %.1fs)]", mins, (deltaTime-(mins*60000.0))/1000.0); + } else if (deltaTime > 1500.0) { + sprintf(str, "((%.1fs))", deltaTime/1000.0); + } else if(deltaTime>900.0) { + sprintf(str, "( %.2fs )", deltaTime/1000.0); + } else if(deltaTime > 5.0) { + sprintf(str, " (%.0fms) ", deltaTime); + } else { + str[0]=0; /* at least terminate it. */ + } +} + +static void print_timeDelta(UDate deltaTime) { + char str[256]; + str_timeDelta(str, deltaTime); + if(str[0]) { + printf("%s", str); + } +} + +/** + * Run or list tests (according to mode) in a subtree. + * + * @param root root of the subtree to operate on + * @param depth The depth of this tree (0=root) + * @param nodeList an array of MAXTESTS depth that's used for keeping track of where we are. nodeList[depth] points to the 'parent' at depth depth. + * @param mode what mode we are operating in. + */ static void iterateTestsWithLevel ( const TestNode* root, - int len, - const TestNode** list, + int depth, + const TestNode** nodeList, TestMode mode) { int i; - int saveIndent; char pathToFunction[MAXTESTNAME] = ""; char separatorString[2] = { TEST_SEPARATOR, '\0'}; +#if SHOW_TIMES + UDate allStartTime = -1, allStopTime = -1; +#endif + + if(depth<2) { + allStartTime = uprv_getRawUTCtime(); + } if ( root == NULL ) return; - list[len++] = root; + /* record the current root node, and increment depth. */ + nodeList[depth++] = root; + /* depth is now the depth of root's children. */ - for ( i=0;i<(len-1);i++ ) + /* Collect the 'path' to the current subtree. */ + for ( i=0;i<(depth-1);i++ ) { - strcat(pathToFunction, list[i]->name); + strcat(pathToFunction, nodeList[i]->name); strcat(pathToFunction, separatorString); } + strcat(pathToFunction, nodeList[i]->name); /* including 'root' */ + + /* print test name and space. */ + INDENT_LEVEL = depth-1; + if(root->name[0]) { + log_testinfo_i("%s ", root->name); + } else { + log_testinfo_i("(%s) ", ARGV_0); + } + ON_LINE = TRUE; /* we are still on the line with the test name */ - strcat(pathToFunction, list[i]->name); - INDENT_LEVEL = len; - if ( (mode == RUNTESTS) && (root->test != NULL)) + if ( (mode == RUNTESTS) && + (root->test != NULL)) /* if root is a leaf node, run it */ { int myERROR_COUNT = ERROR_COUNT; + int myGLOBAL_PRINT_COUNT = GLOBAL_PRINT_COUNT; +#if SHOW_TIMES + UDate startTime, stopTime; + char timeDelta[256]; + char timeSeconds[256]; +#else + const char timeDelta[] = "(unknown)"; + const char timeSeconds[] = "0.000"; +#endif currentTest = root; - root->test(); + INDENT_LEVEL = depth; /* depth of subitems */ + ONE_ERROR=0; + HANGING_OUTPUT=FALSE; +#if SHOW_TIMES + startTime = uprv_getRawUTCtime(); +#endif + strcpy(gTestName, pathToFunction); + root->test(); /* PERFORM THE TEST ************************/ +#if SHOW_TIMES + stopTime = uprv_getRawUTCtime(); +#endif + if(HANGING_OUTPUT) { + log_testinfo("\n"); + HANGING_OUTPUT=FALSE; + } + INDENT_LEVEL = depth-1; /* depth of root */ currentTest = NULL; - if (myERROR_COUNT != ERROR_COUNT) - { - - log_info("---[%d ERRORS] ", ERROR_COUNT - myERROR_COUNT); - strcpy(ERROR_LOG[ERRONEOUS_FUNCTION_COUNT++], pathToFunction); + if((ONE_ERROR>0)&&(ERROR_COUNT==0)) { + ERROR_COUNT++; /* There was an error without a newline */ } - else - log_info("---[OK] "); + ONE_ERROR=0; + +#if SHOW_TIMES + str_timeDelta(timeDelta, stopTime-startTime); + sprintf(timeSeconds, "%f", (stopTime-startTime)/1000.0); +#endif + ctest_xml_testcase(pathToFunction, pathToFunction, timeSeconds, (myERROR_COUNT!=ERROR_COUNT)?"error":NULL); + + if (myERROR_COUNT != ERROR_COUNT) { + log_testinfo_i("} ---[%d ERRORS in %s] ", ERROR_COUNT - myERROR_COUNT, pathToFunction); + strcpy(ERROR_LOG[ERRONEOUS_FUNCTION_COUNT++], pathToFunction); + } else { + if(!ON_LINE) { /* had some output */ + int spaces = FLAG_INDENT-(depth-1); + log_testinfo_i("} %*s[OK] ", spaces, "---"); + if((GLOBAL_PRINT_COUNT-myGLOBAL_PRINT_COUNT)>PAGE_SIZE_LIMIT) { + log_testinfo(" %s ", pathToFunction); /* in case they forgot. */ + } + } else { + /* put -- out at 30 sp. */ + int spaces = FLAG_INDENT-(strlen(root->name)+depth); + if(spaces<0) spaces=0; + log_testinfo(" %*s[OK] ", spaces,"---"); + } + } + +#if SHOW_TIMES + if(timeDelta[0]) printf("%s", timeDelta); +#endif + + ON_LINE = TRUE; /* we are back on-line */ } + INDENT_LEVEL = depth-1; /* root */ /* we want these messages to be at 0 indent. so just push the indent level breifly. */ - saveIndent = INDENT_LEVEL; - INDENT_LEVEL = 0; - log_info("%s%s%c\n", (list[i]->test||mode==SHOWTESTS)?"---":"",pathToFunction, list[i]->test?' ':TEST_SEPARATOR ); - INDENT_LEVEL = saveIndent; + if(mode==SHOWTESTS) { + log_testinfo("---%s%c\n",pathToFunction, nodeList[i]->test?' ':TEST_SEPARATOR ); + } - iterateTestsWithLevel ( root->child, len, list, mode ); + INDENT_LEVEL = depth; + + if(root->child) { + int myERROR_COUNT = ERROR_COUNT; + int myGLOBAL_PRINT_COUNT = GLOBAL_PRINT_COUNT; + if(mode!=SHOWTESTS) { + INDENT_LEVEL=depth-1; + log_testinfo("{\n"); + INDENT_LEVEL=depth; + } + + iterateTestsWithLevel ( root->child, depth, nodeList, mode ); + + if(mode!=SHOWTESTS) { + INDENT_LEVEL=depth-1; + log_testinfo_i("} "); /* TODO: summarize subtests */ + if((depth>1) && (ERROR_COUNT > myERROR_COUNT)) { + log_testinfo("[%d %s in %s] ", ERROR_COUNT-myERROR_COUNT, (ERROR_COUNT-myERROR_COUNT)==1?"error":"errors", pathToFunction); + } else if((GLOBAL_PRINT_COUNT-myGLOBAL_PRINT_COUNT)>PAGE_SIZE_LIMIT || (depth<1)) { + if(pathToFunction[0]) { + log_testinfo(" %s ", pathToFunction); /* in case they forgot. */ + } else { + log_testinfo(" / (%s) ", ARGV_0); + } + } + + ON_LINE=TRUE; + } + } + depth--; + +#if SHOW_TIMES + if(depth<2) { + allStopTime = uprv_getRawUTCtime(); + print_timeDelta(allStopTime-allStartTime); + } +#endif - len--; + if(mode!=SHOWTESTS && ON_LINE) { + log_testinfo("\n"); + } - if ( len != 0 ) /* DO NOT iterate over siblings of the root. */ - iterateTestsWithLevel ( root->sibling, len, list, mode ); + if ( depth != 0 ) { /* DO NOT iterate over siblings of the root. TODO: why not? */ + iterateTestsWithLevel ( root->sibling, depth, nodeList, mode ); + } } @@ -307,12 +491,12 @@ void T_CTEST_EXPORT2 showTests ( const TestNode *root ) { /* make up one for them */ - const TestNode *aList[MAXTESTS]; + const TestNode *nodeList[MAXTESTS]; if (root == NULL) log_err("TEST CAN'T BE FOUND!"); - iterateTestsWithLevel ( root, 0, aList, SHOWTESTS ); + iterateTestsWithLevel ( root, 0, nodeList, SHOWTESTS ); } @@ -320,7 +504,7 @@ void T_CTEST_EXPORT2 runTests ( const TestNode *root ) { int i; - const TestNode *aList[MAXTESTS]; + const TestNode *nodeList[MAXTESTS]; /* make up one for them */ @@ -328,28 +512,50 @@ runTests ( const TestNode *root ) log_err("TEST CAN'T BE FOUND!\n"); ERRONEOUS_FUNCTION_COUNT = ERROR_COUNT = 0; - iterateTestsWithLevel ( root, 0, aList, RUNTESTS ); + iterateTestsWithLevel ( root, 0, nodeList, RUNTESTS ); /*print out result summary*/ + ON_LINE=FALSE; /* just in case */ + + if(knownList != NULL) { + if( udbg_knownIssue_print(knownList) ) { + fprintf(stdout, "(To run suppressed tests, use the -K option.) \n\n"); + } + udbg_knownIssue_close(knownList); + knownList = NULL; + } + if (ERROR_COUNT) { - log_info("\nSUMMARY:\n******* [Total error count:\t%d]\n Errors in\n", ERROR_COUNT); + fprintf(stdout,"\nSUMMARY:\n"); + fflush(stdout); + fprintf(stdout,"******* [Total error count:\t%d]\n", ERROR_COUNT); + fflush(stdout); + fprintf(stdout, " Errors in\n"); for (i=0;i < ERRONEOUS_FUNCTION_COUNT; i++) - log_info("[%s]\n",ERROR_LOG[i]); + fprintf(stdout, "[%s]\n",ERROR_LOG[i]); + if(SUMMARY_FILE != NULL) { + FILE *summf = fopen(SUMMARY_FILE, "w"); + if(summf!=NULL) { + for (i=0;i < ERRONEOUS_FUNCTION_COUNT; i++) + fprintf(summf, "%s\n",ERROR_LOG[i]); + fclose(summf); + } + } } else { - log_info("\n[All tests passed successfully...]\n"); + log_testinfo("\n[All tests passed successfully...]\n"); } if(DATA_ERROR_COUNT) { if(WARN_ON_MISSING_DATA==0) { - log_info("\t*Note* some errors are data-loading related. If the data used is not the \n" + log_testinfo("\t*Note* some errors are data-loading related. If the data used is not the \n" "\tstock ICU data (i.e some have been added or removed), consider using\n" "\tthe '-w' option to turn these errors into warnings.\n"); } else { - log_info("\t*WARNING* some data-loading errors were ignored by the -w option.\n"); + log_testinfo("\t*WARNING* some data-loading errors were ignored by the -w option.\n"); } } } @@ -372,8 +578,10 @@ getTest(const TestNode* root, const char* name) const TestNode* curNode; int nameLen; /* length of current 'name' */ - if (root == NULL) + if (root == NULL) { log_err("TEST CAN'T BE FOUND!\n"); + return NULL; + } /* remove leading slash */ if ( *name == TEST_SEPARATOR ) name++; @@ -422,61 +630,219 @@ getTest(const TestNode* root, const char* name) } } +/* =========== io functions ======== */ + +static void go_offline_with_marker(const char *mrk) { + UBool wasON_LINE = ON_LINE; + + if(ON_LINE) { + log_testinfo(" {\n"); + ON_LINE=FALSE; + } + + if(!HANGING_OUTPUT || wasON_LINE) { + if(mrk != NULL) { + fputs(mrk, stdout); + } + } +} + +static void go_offline() { + go_offline_with_marker(NULL); +} + +static void go_offline_err() { + go_offline(); +} + +static void first_line_verbose() { + go_offline_with_marker("v"); +} + +static void first_line_err() { + go_offline_with_marker("!"); +} + +static void first_line_info() { + go_offline_with_marker("\""); +} + +static void first_line_test() { + fputs(" ", stdout); +} + + static void vlog_err(const char *prefix, const char *pattern, va_list ap) { if( ERR_MSG == FALSE){ return; } - fprintf(stderr, "%-*s", INDENT_LEVEL," " ); + fputs("!", stdout); /* col 1 - bang */ + fprintf(stdout, "%-*s", INDENT_LEVEL,"" ); if(prefix) { - fputs(prefix, stderr); + fputs(prefix, stdout); } - vfprintf(stderr, pattern, ap); - fflush(stderr); + vfprintf(stdout, pattern, ap); + fflush(stdout); va_end(ap); + if((*pattern==0) || (pattern[strlen(pattern)-1]!='\n')) { + HANGING_OUTPUT=1; + } else { + HANGING_OUTPUT=0; + } + GLOBAL_PRINT_COUNT++; +} + +static UBool vlog_knownIssue(const char *ticket, const char *pattern, va_list ap) +{ + char buf[2048]; + UBool firstForTicket; + UBool firstForWhere; + + if(NO_KNOWN) return FALSE; + if(pattern==NULL) pattern=""; + + vsprintf(buf, pattern, ap); + knownList = udbg_knownIssue_open(knownList, ticket, gTestName, buf, + &firstForTicket, &firstForWhere); + + if(firstForTicket || firstForWhere) { + log_info("(Known issue #%s) %s\n", ticket, buf); + } else { + log_verbose("(Known issue #%s) %s\n", ticket, buf); + } + + return TRUE; } + void T_CTEST_EXPORT2 vlog_info(const char *prefix, const char *pattern, va_list ap) { - fprintf(stdout, "%-*s", INDENT_LEVEL," " ); + first_line_info(); + fprintf(stdout, "%-*s", INDENT_LEVEL,"" ); if(prefix) { - fputs(prefix, stderr); + fputs(prefix, stdout); + } + vfprintf(stdout, pattern, ap); + fflush(stdout); + va_end(ap); + if((*pattern==0) || (pattern[strlen(pattern)-1]!='\n')) { + HANGING_OUTPUT=1; + } else { + HANGING_OUTPUT=0; } + GLOBAL_PRINT_COUNT++; +} +/** + * Log test structure, with indent + */ +static void log_testinfo_i(const char *pattern, ...) +{ + va_list ap; + first_line_test(); + fprintf(stdout, "%-*s", INDENT_LEVEL,"" ); + va_start(ap, pattern); + vfprintf(stdout, pattern, ap); + fflush(stdout); + va_end(ap); + GLOBAL_PRINT_COUNT++; +} +/** + * Log test structure (no ident) + */ +static void log_testinfo(const char *pattern, ...) +{ + va_list ap; + va_start(ap, pattern); + first_line_test(); vfprintf(stdout, pattern, ap); fflush(stdout); va_end(ap); + GLOBAL_PRINT_COUNT++; } + static void vlog_verbose(const char *prefix, const char *pattern, va_list ap) { if ( VERBOSITY == FALSE ) return; - fprintf(stdout, "%-*s", INDENT_LEVEL," " ); + first_line_verbose(); + fprintf(stdout, "%-*s", INDENT_LEVEL,"" ); if(prefix) { - fputs(prefix, stderr); + fputs(prefix, stdout); } vfprintf(stdout, pattern, ap); fflush(stdout); va_end(ap); + GLOBAL_PRINT_COUNT++; + if((*pattern==0) || (pattern[strlen(pattern)-1]!='\n')) { + HANGING_OUTPUT=1; + } else { + HANGING_OUTPUT=0; + } } void T_CTEST_EXPORT2 log_err(const char* pattern, ...) { va_list ap; + first_line_err(); if(strchr(pattern, '\n') != NULL) { /* * Count errors only if there is a line feed in the pattern * so that we do not exaggerate our error count. */ ++ERROR_COUNT; + } else { + /* Count at least one error. */ + ONE_ERROR=1; } va_start(ap, pattern); vlog_err(NULL, pattern, ap); } +UBool T_CTEST_EXPORT2 +log_knownIssue(const char *ticket, const char *pattern, ...) { + va_list ap; + va_start(ap, pattern); + return vlog_knownIssue(ticket, pattern, ap); +} + +void T_CTEST_EXPORT2 +log_err_status(UErrorCode status, const char* pattern, ...) +{ + va_list ap; + va_start(ap, pattern); + + if ((status == U_FILE_ACCESS_ERROR || status == U_MISSING_RESOURCE_ERROR)) { + ++DATA_ERROR_COUNT; /* for informational message at the end */ + + if (WARN_ON_MISSING_DATA == 0) { + first_line_err(); + /* Fatal error. */ + if (strchr(pattern, '\n') != NULL) { + ++ERROR_COUNT; + } else { + ++ONE_ERROR; + } + vlog_err(NULL, pattern, ap); /* no need for prefix in default case */ + } else { + vlog_info("[DATA] ", pattern, ap); + } + } else { + first_line_err(); + /* Fatal error. */ + if(strchr(pattern, '\n') != NULL) { + ++ERROR_COUNT; + } else { + ++ONE_ERROR; + } + vlog_err(NULL, pattern, ap); /* no need for prefix in default case */ + } +} + void T_CTEST_EXPORT2 log_info(const char* pattern, ...) { @@ -499,67 +865,103 @@ log_verbose(const char* pattern, ...) void T_CTEST_EXPORT2 log_data_err(const char* pattern, ...) { - va_list ap; - va_start(ap, pattern); + va_list ap; + va_start(ap, pattern); - ++DATA_ERROR_COUNT; /* for informational message at the end */ + go_offline_err(); + ++DATA_ERROR_COUNT; /* for informational message at the end */ - if(WARN_ON_MISSING_DATA == 0) { - /* Fatal error. */ - if(strchr(pattern, '\n') != NULL) { - ++ERROR_COUNT; + if(WARN_ON_MISSING_DATA == 0) { + /* Fatal error. */ + if(strchr(pattern, '\n') != NULL) { + ++ERROR_COUNT; + } + vlog_err(NULL, pattern, ap); /* no need for prefix in default case */ + } else { + vlog_info("[DATA] ", pattern, ap); } - vlog_err(NULL, pattern, ap); /* no need for prefix in default case */ - } else { - vlog_info("[Data] ", pattern, ap); - } } +/* + * 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); +} + +static void *U_CALLCONV ctest_libMalloc(const void *context, size_t size) { + /*if (VERBOSITY) { + printf("Allocated %ld\n", (long)size); + }*/ + if (MINIMUM_MEMORY_SIZE_FAILURE <= size && size <= MAXIMUM_MEMORY_SIZE_FAILURE) { + return NULL; + } + return malloc(size); +} +static void *U_CALLCONV ctest_libRealloc(const void *context, void *mem, size_t size) { + /*if (VERBOSITY) { + printf("Reallocated %ld\n", (long)size); + }*/ + if (MINIMUM_MEMORY_SIZE_FAILURE <= size && size <= MAXIMUM_MEMORY_SIZE_FAILURE) { + /*free(mem);*/ /* Realloc doesn't free on failure. */ + return NULL; + } + return realloc(mem, size); +} +static void U_CALLCONV ctest_libFree(const void *context, void *mem) { + free(mem); +} + int T_CTEST_EXPORT2 -processArgs(const TestNode* root, - int argc, - const char* const argv[]) +initArgs( int argc, const char* const argv[], ArgHandlerPtr argHandler, void *context) { - /** - * This main will parse the l, v, h, n, and path arguments - */ - const TestNode* toRun; int i; - int doList = FALSE; - int subtreeOptionSeen = FALSE; + int argSkip = 0; - int errorCount = 0; - - toRun = root; VERBOSITY = FALSE; ERR_MSG = TRUE; + ARGV_0=argv[0]; + for( i=1; i=argc) { + printf("* Error: '-x' option requires an argument. usage: '-x outfile.xml'.\n"); + return 0; + } + if(ctest_xml_setFileName(argv[i])) { /* set the name */ + return 0; + } } else if (strcmp( argv[i], "-t_info") == 0) { ICU_TRACE = UTRACE_INFO; @@ -615,20 +1061,91 @@ processArgs(const TestNode* root, help( argv[0] ); return 0; } + else if (argHandler != NULL && (argSkip = argHandler(i, argc, argv, context)) > 0) + { + i += argSkip - 1; + } else { printf("* unknown option: %s\n", argv[i]); help( argv[0] ); - return -1; + return 0; } } + if (ICU_TRACE != UTRACE_OFF) { + utrace_setFunctions(NULL, TraceEntry, TraceExit, TraceData); + utrace_setLevel(ICU_TRACE); + } + + return 1; /* total error count */ +} + +int T_CTEST_EXPORT2 +runTestRequest(const TestNode* root, + int argc, + const char* const argv[]) +{ + /** + * This main will parse the l, v, h, n, and path arguments + */ + const TestNode* toRun; + int i; + int doList = FALSE; + int subtreeOptionSeen = FALSE; + + int errorCount = 0; + + toRun = root; + + if(ctest_xml_init(ARGV_0)) { + return 1; /* couldn't fire up XML thing */ + } + + for( i=1; iXML_PREFIX&&!isalnum((int)*p);p--) { + *p=0; + } + } + /* write prefix */ + fprintf(XML_FILE, "\n", XML_PREFIX); + + return 0; +} + +int32_t +T_CTEST_EXPORT2 +ctest_xml_fini(void) { + if(!XML_FILE) return 0; + + fprintf(XML_FILE, "\n"); + fclose(XML_FILE); + printf(" ( test results written to %s )\n", XML_FILE_NAME); + XML_FILE=0; + return 0; +} + + +int32_t +T_CTEST_EXPORT2 +ctest_xml_testcase(const char *classname, const char *name, const char *timeSeconds, const char *failMsg) { + if(!XML_FILE) return 0; + + fprintf(XML_FILE, "\t\n\t\t\n\t\n", failMsg); + } else { + fprintf(XML_FILE, "/>\n"); + } + + return 0; +} + +