Home | History | Annotate | Download | only in ctestfw
      1 /*
      2 ********************************************************************************
      3 *
      4 *   Copyright (C) 1996-2010, International Business Machines
      5 *   Corporation and others.  All Rights Reserved.
      6 *
      7 ********************************************************************************
      8 */
      9 #include <stdio.h>
     10 #include <stdlib.h>
     11 #include <string.h>
     12 #include <assert.h>
     13 #include <stdarg.h>
     14 #include <ctype.h>
     15 
     16 #include "unicode/utrace.h"
     17 #include "unicode/uclean.h"
     18 #include "umutex.h"
     19 #include "putilimp.h"
     20 
     21 /* NOTES:
     22    3/20/1999 srl - strncpy called w/o setting nulls at the end
     23  */
     24 
     25 #define MAXTESTNAME 128
     26 #define MAXTESTS  512
     27 #define MAX_TEST_LOG 4096
     28 
     29 /**
     30  *  How may columns to indent the 'OK' markers.
     31  */
     32 #define FLAG_INDENT 45
     33 /**
     34  *   How many lines of scrollage can go by before we need to remind the user what the test is.
     35  */
     36 #define PAGE_SIZE_LIMIT 25
     37 
     38 #ifndef SHOW_TIMES
     39 #define SHOW_TIMES 1
     40 #endif
     41 
     42 struct TestNode
     43 {
     44   void (*test)(void);
     45   struct TestNode* sibling;
     46   struct TestNode* child;
     47   char name[1]; /* This is dynamically allocated off the end with malloc. */
     48 };
     49 
     50 
     51 static const struct TestNode* currentTest;
     52 
     53 typedef enum { RUNTESTS, SHOWTESTS } TestMode;
     54 #define TEST_SEPARATOR '/'
     55 
     56 #ifndef C_TEST_IMPL
     57 #define C_TEST_IMPL
     58 #endif
     59 
     60 #include "unicode/ctest.h"
     61 
     62 static char ERROR_LOG[MAX_TEST_LOG][MAXTESTNAME];
     63 
     64 /* Local prototypes */
     65 static TestNode* addTestNode( TestNode *root, const char *name );
     66 
     67 static TestNode *createTestNode(const char* name, int32_t nameLen);
     68 
     69 static int strncmp_nullcheck( const char* s1,
     70                   const char* s2,
     71                   int n );
     72 
     73 static void getNextLevel( const char* name,
     74               int* nameLen,
     75               const char** nextName );
     76 
     77 static void iterateTestsWithLevel( const TestNode *root, int depth,
     78                    const TestNode** nodeList,
     79                    TestMode mode);
     80 
     81 static void help ( const char *argv0 );
     82 
     83 /**
     84  * Do the work of logging an error. Doesn't increase the error count.
     85  *
     86  * @prefix optional prefix prepended to message, or NULL.
     87  * @param pattern printf style pattern
     88  * @param ap vprintf style arg list
     89  */
     90 static void vlog_err(const char *prefix, const char *pattern, va_list ap);
     91 static void vlog_verbose(const char *prefix, const char *pattern, va_list ap);
     92 
     93 /**
     94  * Log test structure, with indent
     95  * @param pattern printf pattern
     96  */
     97 static void log_testinfo_i(const char *pattern, ...);
     98 
     99 /**
    100  * Log test structure, NO indent
    101  * @param pattern printf pattern
    102  */
    103 static void log_testinfo(const char *pattern, ...);
    104 
    105 /* If we need to make the framework multi-thread safe
    106    we need to pass around the following vars
    107 */
    108 static int ERRONEOUS_FUNCTION_COUNT = 0;
    109 static int ERROR_COUNT = 0; /* Count of errors from all tests. */
    110 static int ONE_ERROR = 0; /* were there any other errors? */
    111 static int DATA_ERROR_COUNT = 0; /* count of data related errors or warnings */
    112 static int INDENT_LEVEL = 0;
    113 static UBool ON_LINE = FALSE; /* are we on the top line with our test name? */
    114 static UBool HANGING_OUTPUT = FALSE; /* did the user leave us without a trailing \n ? */
    115 static int GLOBAL_PRINT_COUNT = 0; /* global count of printouts */
    116 int REPEAT_TESTS_INIT = 0; /* Was REPEAT_TESTS initialized? */
    117 int REPEAT_TESTS = 1; /* Number of times to run the test */
    118 int VERBOSITY = 0; /* be No-verbose by default */
    119 int ERR_MSG =1; /* error messages will be displayed by default*/
    120 int QUICK = 1;  /* Skip some of the slower tests? */
    121 int WARN_ON_MISSING_DATA = 0; /* Reduce data errs to warnings? */
    122 UTraceLevel ICU_TRACE = UTRACE_OFF;  /* ICU tracing level */
    123 size_t MINIMUM_MEMORY_SIZE_FAILURE = (size_t)-1; /* Minimum library memory allocation window that will fail. */
    124 size_t MAXIMUM_MEMORY_SIZE_FAILURE = (size_t)-1; /* Maximum library memory allocation window that will fail. */
    125 int32_t ALLOCATION_COUNT = 0;
    126 static const char *ARGV_0 = "[ALL]";
    127 static const char *XML_FILE_NAME=NULL;
    128 static char XML_PREFIX[256];
    129 
    130 FILE *XML_FILE = NULL;
    131 /*-------------------------------------------*/
    132 
    133 /* strncmp that also makes sure there's a \0 at s2[0] */
    134 static int strncmp_nullcheck( const char* s1,
    135                const char* s2,
    136                int n )
    137 {
    138     if (((int)strlen(s2) >= n) && s2[n] != 0) {
    139         return 3; /* null check fails */
    140     }
    141     else {
    142         return strncmp ( s1, s2, n );
    143     }
    144 }
    145 
    146 static void getNextLevel( const char* name,
    147            int* nameLen,
    148            const char** nextName )
    149 {
    150     /* Get the next component of the name */
    151     *nextName = strchr(name, TEST_SEPARATOR);
    152 
    153     if( *nextName != 0 )
    154     {
    155         char n[255];
    156         *nameLen = (int)((*nextName) - name);
    157         (*nextName)++; /* skip '/' */
    158         strncpy(n, name, *nameLen);
    159         n[*nameLen] = 0;
    160         /*printf("->%s-< [%d] -> [%s]\n", name, *nameLen, *nextName);*/
    161     }
    162     else {
    163         *nameLen = (int)strlen(name);
    164     }
    165 }
    166 
    167 static TestNode *createTestNode(const char* name, int32_t nameLen)
    168 {
    169     TestNode *newNode;
    170 
    171     newNode = (TestNode*)malloc(sizeof(TestNode) + (nameLen + 1));
    172 
    173     newNode->test = NULL;
    174     newNode->sibling = NULL;
    175     newNode->child = NULL;
    176 
    177     strncpy( newNode->name, name, nameLen );
    178     newNode->name[nameLen] = 0;
    179 
    180     return  newNode;
    181 }
    182 
    183 void T_CTEST_EXPORT2
    184 cleanUpTestTree(TestNode *tn)
    185 {
    186     if(tn->child != NULL) {
    187         cleanUpTestTree(tn->child);
    188     }
    189     if(tn->sibling != NULL) {
    190         cleanUpTestTree(tn->sibling);
    191     }
    192 
    193     free(tn);
    194 
    195 }
    196 
    197 
    198 void T_CTEST_EXPORT2
    199 addTest(TestNode** root,
    200         TestFunctionPtr test,
    201         const char* name )
    202 {
    203     TestNode *newNode;
    204 
    205     /*if this is the first Test created*/
    206     if (*root == NULL)
    207         *root = createTestNode("", 0);
    208 
    209     newNode = addTestNode( *root, name );
    210     assert(newNode != 0 );
    211     /*  printf("addTest: nreName = %s\n", newNode->name );*/
    212 
    213     newNode->test = test;
    214 }
    215 
    216 /* non recursive insert function */
    217 static TestNode *addTestNode ( TestNode *root, const char *name )
    218 {
    219     const char* nextName;
    220     TestNode *nextNode, *curNode;
    221     int nameLen; /* length of current 'name' */
    222 
    223     /* remove leading slash */
    224     if ( *name == TEST_SEPARATOR )
    225         name++;
    226 
    227     curNode = root;
    228 
    229     for(;;)
    230     {
    231         /* Start with the next child */
    232         nextNode = curNode->child;
    233 
    234         getNextLevel ( name, &nameLen, &nextName );
    235 
    236         /*      printf("* %s\n", name );*/
    237 
    238         /* if nextNode is already null, then curNode has no children
    239         -- add them */
    240         if( nextNode == NULL )
    241         {
    242             /* Add all children of the node */
    243             do
    244             {
    245                 /* Get the next component of the name */
    246                 getNextLevel(name, &nameLen, &nextName);
    247 
    248                 /* update curName to have the next name segment */
    249                 curNode->child = createTestNode(name, nameLen);
    250                 /* printf("*** added %s\n", curNode->child->name );*/
    251                 curNode = curNode->child;
    252                 name = nextName;
    253             }
    254             while( name != NULL );
    255 
    256             return curNode;
    257         }
    258 
    259         /* Search across for the name */
    260         while (strncmp_nullcheck ( name, nextNode->name, nameLen) != 0 )
    261         {
    262             curNode = nextNode;
    263             nextNode = nextNode -> sibling;
    264 
    265             if ( nextNode == NULL )
    266             {
    267                 /* Did not find 'name' on this level. */
    268                 nextNode = createTestNode(name, nameLen);
    269                 curNode->sibling = nextNode;
    270                 break;
    271             }
    272         }
    273 
    274         /* nextNode matches 'name' */
    275 
    276         if (nextName == NULL) /* end of the line */
    277         {
    278             return nextNode;
    279         }
    280 
    281         /* Loop again with the next item */
    282         name = nextName;
    283         curNode = nextNode;
    284     }
    285 }
    286 
    287 /**
    288  * Log the time taken. May not output anything.
    289  * @param deltaTime change in time
    290  */
    291 void T_CTEST_EXPORT2 str_timeDelta(char *str, UDate deltaTime) {
    292   if (deltaTime > 110000.0 ) {
    293     double mins = uprv_floor(deltaTime/60000.0);
    294     sprintf(str, "[(%.0fm %.1fs)]", mins, (deltaTime-(mins*60000.0))/1000.0);
    295   } else if (deltaTime > 1500.0) {
    296     sprintf(str, "((%.1fs))", deltaTime/1000.0);
    297   } else if(deltaTime>900.0) {
    298     sprintf(str, "( %.2fs )", deltaTime/1000.0);
    299   } else if(deltaTime > 5.0) {
    300     sprintf(str, " (%.0fms) ", deltaTime);
    301   } else {
    302     str[0]=0; /* at least terminate it. */
    303   }
    304 }
    305 
    306 static void print_timeDelta(UDate deltaTime) {
    307   char str[256];
    308   str_timeDelta(str, deltaTime);
    309   if(str[0]) {
    310     printf("%s", str);
    311   }
    312 }
    313 
    314 /**
    315  * Run or list tests (according to mode) in a subtree.
    316  *
    317  * @param root root of the subtree to operate on
    318  * @param depth The depth of this tree (0=root)
    319  * @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.
    320  * @param mode what mode we are operating in.
    321  */
    322 static void iterateTestsWithLevel ( const TestNode* root,
    323                  int depth,
    324                  const TestNode** nodeList,
    325                  TestMode mode)
    326 {
    327     int i;
    328 
    329     char pathToFunction[MAXTESTNAME] = "";
    330     char separatorString[2] = { TEST_SEPARATOR, '\0'};
    331 #if SHOW_TIMES
    332     UDate allStartTime = -1, allStopTime = -1;
    333 #endif
    334 
    335     if(depth<2) {
    336       allStartTime = uprv_getRawUTCtime();
    337     }
    338 
    339     if ( root == NULL )
    340         return;
    341 
    342     /* record the current root node, and increment depth. */
    343     nodeList[depth++] = root;
    344     /* depth is now the depth of root's children. */
    345 
    346     /* Collect the 'path' to the current subtree. */
    347     for ( i=0;i<(depth-1);i++ )
    348     {
    349         strcat(pathToFunction, nodeList[i]->name);
    350         strcat(pathToFunction, separatorString);
    351     }
    352     strcat(pathToFunction, nodeList[i]->name); /* including 'root' */
    353 
    354     /* print test name and space. */
    355     INDENT_LEVEL = depth-1;
    356     if(root->name[0]) {
    357     	log_testinfo_i("%s ", root->name);
    358     } else {
    359     	log_testinfo_i("(%s) ", ARGV_0);
    360     }
    361     ON_LINE = TRUE;  /* we are still on the line with the test name */
    362 
    363 
    364     if ( (mode == RUNTESTS) &&
    365 		(root->test != NULL))  /* if root is a leaf node, run it */
    366     {
    367         int myERROR_COUNT = ERROR_COUNT;
    368         int myGLOBAL_PRINT_COUNT = GLOBAL_PRINT_COUNT;
    369 #if SHOW_TIMES
    370         UDate startTime, stopTime;
    371         char timeDelta[256];
    372         char timeSeconds[256];
    373 #else
    374         const char timeDelta[] = "(unknown)";
    375         const char timeSeconds[] = "0.000";
    376 #endif
    377         currentTest = root;
    378         INDENT_LEVEL = depth;  /* depth of subitems */
    379         ONE_ERROR=0;
    380         HANGING_OUTPUT=FALSE;
    381 #if SHOW_TIMES
    382         startTime = uprv_getRawUTCtime();
    383 #endif
    384         root->test();   /* PERFORM THE TEST ************************/
    385 #if SHOW_TIMES
    386         stopTime = uprv_getRawUTCtime();
    387 #endif
    388         if(HANGING_OUTPUT) {
    389           log_testinfo("\n");
    390           HANGING_OUTPUT=FALSE;
    391         }
    392         INDENT_LEVEL = depth-1;  /* depth of root */
    393         currentTest = NULL;
    394         if((ONE_ERROR>0)&&(ERROR_COUNT==0)) {
    395           ERROR_COUNT++; /* There was an error without a newline */
    396         }
    397         ONE_ERROR=0;
    398 
    399 #if SHOW_TIMES
    400         str_timeDelta(timeDelta, stopTime-startTime);
    401         sprintf(timeSeconds, "%f", (stopTime-startTime)/1000.0);
    402 #endif
    403         ctest_xml_testcase(pathToFunction, pathToFunction, timeSeconds, (myERROR_COUNT!=ERROR_COUNT)?"error":NULL);
    404 
    405         if (myERROR_COUNT != ERROR_COUNT) {
    406           log_testinfo_i("} ---[%d ERRORS in %s] ", ERROR_COUNT - myERROR_COUNT, pathToFunction);
    407           strcpy(ERROR_LOG[ERRONEOUS_FUNCTION_COUNT++], pathToFunction);
    408         } else {
    409           if(!ON_LINE) { /* had some output */
    410             int spaces = FLAG_INDENT-(depth-1);
    411             log_testinfo_i("} %*s[OK] ", spaces, "---");
    412             if((GLOBAL_PRINT_COUNT-myGLOBAL_PRINT_COUNT)>PAGE_SIZE_LIMIT) {
    413               log_testinfo(" %s ", pathToFunction); /* in case they forgot. */
    414             }
    415           } else {
    416             /* put -- out at 30 sp. */
    417             int spaces = FLAG_INDENT-(strlen(root->name)+depth);
    418             if(spaces<0) spaces=0;
    419             log_testinfo(" %*s[OK] ", spaces,"---");
    420           }
    421         }
    422 
    423 #if SHOW_TIMES
    424         if(timeDelta[0]) printf("%s", timeDelta);
    425 #endif
    426 
    427         ON_LINE = TRUE; /* we are back on-line */
    428     }
    429 
    430     INDENT_LEVEL = depth-1; /* root */
    431 
    432     /* we want these messages to be at 0 indent. so just push the indent level breifly. */
    433     if(mode==SHOWTESTS) {
    434     	log_testinfo("---%s%c\n",pathToFunction, nodeList[i]->test?' ':TEST_SEPARATOR );
    435     }
    436 
    437     INDENT_LEVEL = depth;
    438 
    439     if(root->child) {
    440         int myERROR_COUNT = ERROR_COUNT;
    441         int myGLOBAL_PRINT_COUNT = GLOBAL_PRINT_COUNT;
    442         if(mode!=SHOWTESTS) {
    443     		INDENT_LEVEL=depth-1;
    444     		log_testinfo("{\n");
    445     		INDENT_LEVEL=depth;
    446     	}
    447 
    448     	iterateTestsWithLevel ( root->child, depth, nodeList, mode );
    449 
    450     	if(mode!=SHOWTESTS) {
    451     		INDENT_LEVEL=depth-1;
    452     		log_testinfo_i("} "); /* TODO:  summarize subtests */
    453     		if((depth>1) && (ERROR_COUNT > myERROR_COUNT)) {
    454     			log_testinfo("[%d %s in %s] ", ERROR_COUNT-myERROR_COUNT, (ERROR_COUNT-myERROR_COUNT)==1?"error":"errors", pathToFunction);
    455     		} else if((GLOBAL_PRINT_COUNT-myGLOBAL_PRINT_COUNT)>PAGE_SIZE_LIMIT || (depth<1)) {
    456                   if(pathToFunction[0]) {
    457                     log_testinfo(" %s ", pathToFunction); /* in case they forgot. */
    458                   } else {
    459                     log_testinfo(" / (%s) ", ARGV_0);
    460                   }
    461                 }
    462 
    463     		ON_LINE=TRUE;
    464     	}
    465 	}
    466     depth--;
    467 
    468 #if SHOW_TIMES
    469     if(depth<2) {
    470       allStopTime = uprv_getRawUTCtime();
    471       print_timeDelta(allStopTime-allStartTime);
    472     }
    473 #endif
    474 
    475     if(mode!=SHOWTESTS && ON_LINE) {
    476     	log_testinfo("\n");
    477     }
    478 
    479     if ( depth != 0 ) { /* DO NOT iterate over siblings of the root. TODO: why not? */
    480         iterateTestsWithLevel ( root->sibling, depth, nodeList, mode );
    481     }
    482 }
    483 
    484 
    485 
    486 void T_CTEST_EXPORT2
    487 showTests ( const TestNode *root )
    488 {
    489     /* make up one for them */
    490     const TestNode *nodeList[MAXTESTS];
    491 
    492     if (root == NULL)
    493         log_err("TEST CAN'T BE FOUND!");
    494 
    495     iterateTestsWithLevel ( root, 0, nodeList, SHOWTESTS );
    496 
    497 }
    498 
    499 void T_CTEST_EXPORT2
    500 runTests ( const TestNode *root )
    501 {
    502     int i;
    503     const TestNode *nodeList[MAXTESTS];
    504     /* make up one for them */
    505 
    506 
    507     if (root == NULL)
    508         log_err("TEST CAN'T BE FOUND!\n");
    509 
    510     ERRONEOUS_FUNCTION_COUNT = ERROR_COUNT = 0;
    511     iterateTestsWithLevel ( root, 0, nodeList, RUNTESTS );
    512 
    513     /*print out result summary*/
    514 
    515     ON_LINE=FALSE; /* just in case */
    516 
    517     if (ERROR_COUNT)
    518     {
    519         fprintf(stdout,"\nSUMMARY:\n");
    520     	fflush(stdout);
    521         fprintf(stdout,"******* [Total error count:\t%d]\n", ERROR_COUNT);
    522     	fflush(stdout);
    523         fprintf(stdout, " Errors in\n");
    524         for (i=0;i < ERRONEOUS_FUNCTION_COUNT; i++)
    525             fprintf(stdout, "[%s]\n",ERROR_LOG[i]);
    526     }
    527     else
    528     {
    529       log_testinfo("\n[All tests passed successfully...]\n");
    530     }
    531 
    532     if(DATA_ERROR_COUNT) {
    533       if(WARN_ON_MISSING_DATA==0) {
    534     	  log_testinfo("\t*Note* some errors are data-loading related. If the data used is not the \n"
    535                  "\tstock ICU data (i.e some have been added or removed), consider using\n"
    536                  "\tthe '-w' option to turn these errors into warnings.\n");
    537       } else {
    538     	  log_testinfo("\t*WARNING* some data-loading errors were ignored by the -w option.\n");
    539       }
    540     }
    541 }
    542 
    543 const char* T_CTEST_EXPORT2
    544 getTestName(void)
    545 {
    546   if(currentTest != NULL) {
    547     return currentTest->name;
    548   } else {
    549     return NULL;
    550   }
    551 }
    552 
    553 const TestNode* T_CTEST_EXPORT2
    554 getTest(const TestNode* root, const char* name)
    555 {
    556     const char* nextName;
    557     TestNode *nextNode;
    558     const TestNode* curNode;
    559     int nameLen; /* length of current 'name' */
    560 
    561     if (root == NULL) {
    562         log_err("TEST CAN'T BE FOUND!\n");
    563         return NULL;
    564     }
    565     /* remove leading slash */
    566     if ( *name == TEST_SEPARATOR )
    567         name++;
    568 
    569     curNode = root;
    570 
    571     for(;;)
    572     {
    573         /* Start with the next child */
    574         nextNode = curNode->child;
    575 
    576         getNextLevel ( name, &nameLen, &nextName );
    577 
    578         /*      printf("* %s\n", name );*/
    579 
    580         /* if nextNode is already null, then curNode has no children
    581         -- add them */
    582         if( nextNode == NULL )
    583         {
    584             return NULL;
    585         }
    586 
    587         /* Search across for the name */
    588         while (strncmp_nullcheck ( name, nextNode->name, nameLen) != 0 )
    589         {
    590             curNode = nextNode;
    591             nextNode = nextNode -> sibling;
    592 
    593             if ( nextNode == NULL )
    594             {
    595                 /* Did not find 'name' on this level. */
    596                 return NULL;
    597             }
    598         }
    599 
    600         /* nextNode matches 'name' */
    601 
    602         if (nextName == NULL) /* end of the line */
    603         {
    604             return nextNode;
    605         }
    606 
    607         /* Loop again with the next item */
    608         name = nextName;
    609         curNode = nextNode;
    610     }
    611 }
    612 
    613 /*  =========== io functions ======== */
    614 
    615 static void go_offline_with_marker(const char *mrk) {
    616   UBool wasON_LINE = ON_LINE;
    617 
    618   if(ON_LINE) {
    619     log_testinfo(" {\n");
    620     ON_LINE=FALSE;
    621   }
    622 
    623   if(!HANGING_OUTPUT || wasON_LINE) {
    624     if(mrk != NULL) {
    625       fputs(mrk, stdout);
    626     }
    627   }
    628 }
    629 
    630 static void go_offline() {
    631 	go_offline_with_marker(NULL);
    632 }
    633 
    634 static void go_offline_err() {
    635 	go_offline();
    636 }
    637 
    638 static void first_line_verbose() {
    639     go_offline_with_marker("v");
    640 }
    641 
    642 static void first_line_err() {
    643     go_offline_with_marker("!");
    644 }
    645 
    646 static void first_line_info() {
    647     go_offline_with_marker("\"");
    648 }
    649 
    650 static void first_line_test() {
    651 	fputs(" ", stdout);
    652 }
    653 
    654 
    655 static void vlog_err(const char *prefix, const char *pattern, va_list ap)
    656 {
    657     if( ERR_MSG == FALSE){
    658         return;
    659     }
    660     fputs("!", stdout); /* col 1 - bang */
    661     fprintf(stdout, "%-*s", INDENT_LEVEL,"" );
    662     if(prefix) {
    663         fputs(prefix, stdout);
    664     }
    665     vfprintf(stdout, pattern, ap);
    666     fflush(stdout);
    667     va_end(ap);
    668     if((*pattern==0) || (pattern[strlen(pattern)-1]!='\n')) {
    669     	HANGING_OUTPUT=1;
    670     } else {
    671     	HANGING_OUTPUT=0;
    672     }
    673     GLOBAL_PRINT_COUNT++;
    674 }
    675 
    676 void T_CTEST_EXPORT2
    677 vlog_info(const char *prefix, const char *pattern, va_list ap)
    678 {
    679 	first_line_info();
    680     fprintf(stdout, "%-*s", INDENT_LEVEL,"" );
    681     if(prefix) {
    682         fputs(prefix, stdout);
    683     }
    684     vfprintf(stdout, pattern, ap);
    685     fflush(stdout);
    686     va_end(ap);
    687     if((*pattern==0) || (pattern[strlen(pattern)-1]!='\n')) {
    688     	HANGING_OUTPUT=1;
    689     } else {
    690     	HANGING_OUTPUT=0;
    691     }
    692     GLOBAL_PRINT_COUNT++;
    693 }
    694 /**
    695  * Log test structure, with indent
    696  */
    697 static void log_testinfo_i(const char *pattern, ...)
    698 {
    699     va_list ap;
    700     first_line_test();
    701     fprintf(stdout, "%-*s", INDENT_LEVEL,"" );
    702     va_start(ap, pattern);
    703     vfprintf(stdout, pattern, ap);
    704     fflush(stdout);
    705     va_end(ap);
    706     GLOBAL_PRINT_COUNT++;
    707 }
    708 /**
    709  * Log test structure (no ident)
    710  */
    711 static void log_testinfo(const char *pattern, ...)
    712 {
    713     va_list ap;
    714     va_start(ap, pattern);
    715     first_line_test();
    716     vfprintf(stdout, pattern, ap);
    717     fflush(stdout);
    718     va_end(ap);
    719     GLOBAL_PRINT_COUNT++;
    720 }
    721 
    722 
    723 static void vlog_verbose(const char *prefix, const char *pattern, va_list ap)
    724 {
    725     if ( VERBOSITY == FALSE )
    726         return;
    727 
    728     first_line_verbose();
    729     fprintf(stdout, "%-*s", INDENT_LEVEL,"" );
    730     if(prefix) {
    731         fputs(prefix, stdout);
    732     }
    733     vfprintf(stdout, pattern, ap);
    734     fflush(stdout);
    735     va_end(ap);
    736     GLOBAL_PRINT_COUNT++;
    737     if((*pattern==0) || (pattern[strlen(pattern)-1]!='\n')) {
    738     	HANGING_OUTPUT=1;
    739     } else {
    740     	HANGING_OUTPUT=0;
    741     }
    742 }
    743 
    744 void T_CTEST_EXPORT2
    745 log_err(const char* pattern, ...)
    746 {
    747     va_list ap;
    748     first_line_err();
    749     if(strchr(pattern, '\n') != NULL) {
    750         /*
    751          * Count errors only if there is a line feed in the pattern
    752          * so that we do not exaggerate our error count.
    753          */
    754         ++ERROR_COUNT;
    755     } else {
    756     	/* Count at least one error. */
    757     	ONE_ERROR=1;
    758     }
    759     va_start(ap, pattern);
    760     vlog_err(NULL, pattern, ap);
    761 }
    762 
    763 void T_CTEST_EXPORT2
    764 log_err_status(UErrorCode status, const char* pattern, ...)
    765 {
    766     va_list ap;
    767     va_start(ap, pattern);
    768 
    769     first_line_err();
    770     if ((status == U_FILE_ACCESS_ERROR || status == U_MISSING_RESOURCE_ERROR)) {
    771         ++DATA_ERROR_COUNT; /* for informational message at the end */
    772 
    773         if (WARN_ON_MISSING_DATA == 0) {
    774             /* Fatal error. */
    775             if (strchr(pattern, '\n') != NULL) {
    776                 ++ERROR_COUNT;
    777             } else {
    778 				++ONE_ERROR;
    779             }
    780             vlog_err(NULL, pattern, ap); /* no need for prefix in default case */
    781         } else {
    782             vlog_info("[DATA] ", pattern, ap);
    783         }
    784     } else {
    785         /* Fatal error. */
    786         if(strchr(pattern, '\n') != NULL) {
    787             ++ERROR_COUNT;
    788         } else {
    789 			++ONE_ERROR;
    790         }
    791         vlog_err(NULL, pattern, ap); /* no need for prefix in default case */
    792     }
    793 }
    794 
    795 void T_CTEST_EXPORT2
    796 log_info(const char* pattern, ...)
    797 {
    798     va_list ap;
    799 
    800     va_start(ap, pattern);
    801     vlog_info(NULL, pattern, ap);
    802 }
    803 
    804 void T_CTEST_EXPORT2
    805 log_verbose(const char* pattern, ...)
    806 {
    807     va_list ap;
    808 
    809     va_start(ap, pattern);
    810     vlog_verbose(NULL, pattern, ap);
    811 }
    812 
    813 
    814 void T_CTEST_EXPORT2
    815 log_data_err(const char* pattern, ...)
    816 {
    817     va_list ap;
    818     va_start(ap, pattern);
    819 
    820     go_offline_err();
    821     ++DATA_ERROR_COUNT; /* for informational message at the end */
    822 
    823     if(WARN_ON_MISSING_DATA == 0) {
    824         /* Fatal error. */
    825         if(strchr(pattern, '\n') != NULL) {
    826             ++ERROR_COUNT;
    827         }
    828         vlog_err(NULL, pattern, ap); /* no need for prefix in default case */
    829     } else {
    830         vlog_info("[DATA] ", pattern, ap);
    831     }
    832 }
    833 
    834 
    835 /*
    836  * Tracing functions.
    837  */
    838 static int traceFnNestingDepth = 0;
    839 U_CDECL_BEGIN
    840 static void U_CALLCONV TraceEntry(const void *context, int32_t fnNumber) {
    841     char buf[500];
    842     utrace_format(buf, sizeof(buf), traceFnNestingDepth*3, "%s() enter.\n", utrace_functionName(fnNumber));    buf[sizeof(buf)-1]=0;
    843     fputs(buf, stdout);
    844     traceFnNestingDepth++;
    845 }
    846 
    847 static void U_CALLCONV TraceExit(const void *context, int32_t fnNumber, const char *fmt, va_list args) {    char buf[500];
    848 
    849     if (traceFnNestingDepth>0) {
    850         traceFnNestingDepth--;
    851     }
    852     utrace_format(buf, sizeof(buf), traceFnNestingDepth*3, "%s() ", utrace_functionName(fnNumber));    buf[sizeof(buf)-1]=0;
    853     fputs(buf, stdout);
    854     utrace_vformat(buf, sizeof(buf), traceFnNestingDepth*3, fmt, args);
    855     buf[sizeof(buf)-1]=0;
    856     fputs(buf, stdout);
    857     putc('\n', stdout);
    858 }
    859 
    860 static void U_CALLCONV TraceData(const void *context, int32_t fnNumber,
    861                           int32_t level, const char *fmt, va_list args) {
    862     char buf[500];
    863     utrace_vformat(buf, sizeof(buf), traceFnNestingDepth*3, fmt, args);
    864     buf[sizeof(buf)-1]=0;
    865     fputs(buf, stdout);
    866     putc('\n', stdout);
    867 }
    868 
    869 static void *U_CALLCONV ctest_libMalloc(const void *context, size_t size) {
    870     /*if (VERBOSITY) {
    871         printf("Allocated %ld\n", (long)size);
    872     }*/
    873     if (MINIMUM_MEMORY_SIZE_FAILURE <= size && size <= MAXIMUM_MEMORY_SIZE_FAILURE) {
    874         return NULL;
    875     }
    876     umtx_atomic_inc(&ALLOCATION_COUNT);
    877     return malloc(size);
    878 }
    879 static void *U_CALLCONV ctest_libRealloc(const void *context, void *mem, size_t size) {
    880     /*if (VERBOSITY) {
    881         printf("Reallocated %ld\n", (long)size);
    882     }*/
    883     if (MINIMUM_MEMORY_SIZE_FAILURE <= size && size <= MAXIMUM_MEMORY_SIZE_FAILURE) {
    884         /*free(mem);*/ /* Realloc doesn't free on failure. */
    885         return NULL;
    886     }
    887     if (mem == NULL) {
    888         /* New allocation. */
    889         umtx_atomic_inc(&ALLOCATION_COUNT);
    890     }
    891     return realloc(mem, size);
    892 }
    893 static void U_CALLCONV ctest_libFree(const void *context, void *mem) {
    894     if (mem != NULL) {
    895         umtx_atomic_dec(&ALLOCATION_COUNT);
    896     }
    897     free(mem);
    898 }
    899 
    900 int T_CTEST_EXPORT2
    901 initArgs( int argc, const char* const argv[], ArgHandlerPtr argHandler, void *context)
    902 {
    903     int                i;
    904     int                doList = FALSE;
    905 	int                argSkip = 0;
    906 
    907     VERBOSITY = FALSE;
    908     ERR_MSG = TRUE;
    909 
    910     ARGV_0=argv[0];
    911 
    912     for( i=1; i<argc; i++)
    913     {
    914         if ( argv[i][0] == '/' )
    915         {
    916             /* We don't run the tests here. */
    917             continue;
    918         }
    919         else if ((strcmp( argv[i], "-a") == 0) || (strcmp(argv[i],"-all") == 0))
    920         {
    921             /* We don't run the tests here. */
    922             continue;
    923         }
    924         else if (strcmp( argv[i], "-v" )==0 || strcmp( argv[i], "-verbose")==0)
    925         {
    926             VERBOSITY = TRUE;
    927         }
    928         else if (strcmp( argv[i], "-l" )==0 )
    929         {
    930             doList = TRUE;
    931         }
    932         else if (strcmp( argv[i], "-e1") == 0)
    933         {
    934             QUICK = -1;
    935         }
    936         else if (strcmp( argv[i], "-e") ==0)
    937         {
    938             QUICK = 0;
    939         }
    940         else if (strcmp( argv[i], "-w") ==0)
    941         {
    942             WARN_ON_MISSING_DATA = TRUE;
    943         }
    944         else if (strcmp( argv[i], "-m") ==0)
    945         {
    946             UErrorCode errorCode = U_ZERO_ERROR;
    947             if (i+1 < argc) {
    948                 char *endPtr = NULL;
    949                 i++;
    950                 MINIMUM_MEMORY_SIZE_FAILURE = (size_t)strtol(argv[i], &endPtr, 10);
    951                 if (endPtr == argv[i]) {
    952                     printf("Can't parse %s\n", argv[i]);
    953                     help(argv[0]);
    954                     return 0;
    955                 }
    956                 if (*endPtr == '-') {
    957                     char *maxPtr = endPtr+1;
    958                     endPtr = NULL;
    959                     MAXIMUM_MEMORY_SIZE_FAILURE = (size_t)strtol(maxPtr, &endPtr, 10);
    960                     if (endPtr == argv[i]) {
    961                         printf("Can't parse %s\n", argv[i]);
    962                         help(argv[0]);
    963                         return 0;
    964                     }
    965                 }
    966             }
    967             /* Use the default value */
    968             u_setMemoryFunctions(NULL, ctest_libMalloc, ctest_libRealloc, ctest_libFree, &errorCode);
    969             if (U_FAILURE(errorCode)) {
    970                 printf("u_setMemoryFunctions returned %s\n", u_errorName(errorCode));
    971                 return 0;
    972             }
    973         }
    974         else if(strcmp( argv[i], "-n") == 0 || strcmp( argv[i], "-no_err_msg") == 0)
    975         {
    976             ERR_MSG = FALSE;
    977         }
    978         else if (strcmp( argv[i], "-r") == 0)
    979         {
    980             if (!REPEAT_TESTS_INIT) {
    981                 REPEAT_TESTS++;
    982             }
    983         }
    984         else if (strcmp( argv[i], "-x") == 0)
    985         {
    986           if(++i>=argc) {
    987             printf("* Error: '-x' option requires an argument. usage: '-x outfile.xml'.\n");
    988             return 0;
    989           }
    990           if(ctest_xml_setFileName(argv[i])) { /* set the name */
    991             return 0;
    992           }
    993         }
    994         else if (strcmp( argv[i], "-t_info") == 0) {
    995             ICU_TRACE = UTRACE_INFO;
    996         }
    997         else if (strcmp( argv[i], "-t_error") == 0) {
    998             ICU_TRACE = UTRACE_ERROR;
    999         }
   1000         else if (strcmp( argv[i], "-t_warn") == 0) {
   1001             ICU_TRACE = UTRACE_WARNING;
   1002         }
   1003         else if (strcmp( argv[i], "-t_verbose") == 0) {
   1004             ICU_TRACE = UTRACE_VERBOSE;
   1005         }
   1006         else if (strcmp( argv[i], "-t_oc") == 0) {
   1007             ICU_TRACE = UTRACE_OPEN_CLOSE;
   1008         }
   1009         else if (strcmp( argv[i], "-h" )==0 || strcmp( argv[i], "--help" )==0)
   1010         {
   1011             help( argv[0] );
   1012             return 0;
   1013         }
   1014         else if (argHandler != NULL && (argSkip = argHandler(i, argc, argv, context)) > 0)
   1015         {
   1016             i += argSkip - 1;
   1017         }
   1018         else
   1019         {
   1020             printf("* unknown option: %s\n", argv[i]);
   1021             help( argv[0] );
   1022             return 0;
   1023         }
   1024     }
   1025     if (ICU_TRACE != UTRACE_OFF) {
   1026         utrace_setFunctions(NULL, TraceEntry, TraceExit, TraceData);
   1027         utrace_setLevel(ICU_TRACE);
   1028     }
   1029 
   1030     return 1; /* total error count */
   1031 }
   1032 
   1033 int T_CTEST_EXPORT2
   1034 runTestRequest(const TestNode* root,
   1035              int argc,
   1036              const char* const argv[])
   1037 {
   1038     /**
   1039      * This main will parse the l, v, h, n, and path arguments
   1040      */
   1041     const TestNode*    toRun;
   1042     int                i;
   1043     int                doList = FALSE;
   1044     int                subtreeOptionSeen = FALSE;
   1045 
   1046     int                errorCount = 0;
   1047 
   1048     toRun = root;
   1049 
   1050     if(ctest_xml_init(ARGV_0)) {
   1051       return 1; /* couldn't fire up XML thing */
   1052     }
   1053 
   1054     for( i=1; i<argc; i++)
   1055     {
   1056         if ( argv[i][0] == '/' )
   1057         {
   1058             printf("Selecting subtree '%s'\n", argv[i]);
   1059 
   1060             if ( argv[i][1] == 0 )
   1061                 toRun = root;
   1062             else
   1063                 toRun = getTest(root, argv[i]);
   1064 
   1065             if ( toRun == NULL )
   1066             {
   1067                 printf("* Could not find any matching subtree\n");
   1068                 return -1;
   1069             }
   1070 
   1071             ON_LINE=FALSE; /* just in case */
   1072 
   1073             if( doList == TRUE)
   1074                 showTests(toRun);
   1075             else
   1076                 runTests(toRun);
   1077 
   1078             ON_LINE=FALSE; /* just in case */
   1079 
   1080             errorCount += ERROR_COUNT;
   1081 
   1082             subtreeOptionSeen = TRUE;
   1083         } else if ((strcmp( argv[i], "-a") == 0) || (strcmp(argv[i],"-all") == 0)) {
   1084             subtreeOptionSeen=FALSE;
   1085         } else if (strcmp( argv[i], "-l") == 0) {
   1086             doList = TRUE;
   1087         }
   1088         /* else option already handled by initArgs */
   1089     }
   1090 
   1091     if( subtreeOptionSeen == FALSE) /* no other subtree given, run the default */
   1092     {
   1093         ON_LINE=FALSE; /* just in case */
   1094         if( doList == TRUE)
   1095             showTests(toRun);
   1096         else
   1097             runTests(toRun);
   1098         ON_LINE=FALSE; /* just in case */
   1099 
   1100         errorCount += ERROR_COUNT;
   1101     }
   1102     else
   1103     {
   1104         if( ( doList == FALSE ) && ( errorCount > 0 ) )
   1105             printf(" Total errors: %d\n", errorCount );
   1106     }
   1107 
   1108     REPEAT_TESTS_INIT = 1;
   1109 
   1110     if(ctest_xml_fini()) {
   1111       errorCount++;
   1112     }
   1113 
   1114     return errorCount; /* total error count */
   1115 }
   1116 
   1117 /**
   1118  * Display program invocation arguments
   1119  */
   1120 
   1121 static void help ( const char *argv0 )
   1122 {
   1123     printf("Usage: %s [ -l ] [ -v ] [ -verbose] [-a] [ -all] [-n] [ -no_err_msg]\n"
   1124            "    [ -h ] [-t_info | -t_error | -t_warn | -t_oc | -t_verbose] [-m n[-q] ]\n"
   1125            "    [ /path/to/test ]\n",
   1126             argv0);
   1127     printf("    -l  To get a list of test names\n");
   1128     printf("    -e  to do exhaustive testing\n");
   1129     printf("    -verbose To turn ON verbosity\n");
   1130     printf("    -v  To turn ON verbosity(same as -verbose)\n");
   1131     printf("    -x file.xml   Write junit format output to file.xml\n");
   1132     printf("    -h  To print this message\n");
   1133     printf("    -n  To turn OFF printing error messages\n");
   1134     printf("    -w  Don't fail on data-loading errs, just warn. Useful if\n"
   1135            "        user has reduced/changed the common set of ICU data \n");
   1136     printf("    -t_info | -t_error | -t_warn | -t_oc | -t_verbose  Enable ICU tracing\n");
   1137     printf("    -no_err_msg (same as -n) \n");
   1138     printf("    -m n[-q] Min-Max memory size that will cause an allocation failure.\n");
   1139     printf("        The default is the maximum value of size_t. Max is optional.\n");
   1140     printf("    -r  Repeat tests after calling u_cleanup \n");
   1141     printf("    [/subtest]  To run a subtest \n");
   1142     printf("    eg: to run just the utility tests type: cintltest /tsutil) \n");
   1143 }
   1144 
   1145 int32_t T_CTEST_EXPORT2
   1146 getTestOption ( int32_t testOption ) {
   1147     switch (testOption) {
   1148         case VERBOSITY_OPTION:
   1149             return VERBOSITY;
   1150         case WARN_ON_MISSING_DATA_OPTION:
   1151             return WARN_ON_MISSING_DATA;
   1152         case QUICK_OPTION:
   1153             return QUICK;
   1154         case REPEAT_TESTS_OPTION:
   1155             return REPEAT_TESTS;
   1156         case ERR_MSG_OPTION:
   1157             return ERR_MSG;
   1158         case ICU_TRACE_OPTION:
   1159             return ICU_TRACE;
   1160         default :
   1161             return 0;
   1162     }
   1163 }
   1164 
   1165 void T_CTEST_EXPORT2
   1166 setTestOption ( int32_t testOption, int32_t value) {
   1167     if (value == DECREMENT_OPTION_VALUE) {
   1168         value = getTestOption(testOption);
   1169         --value;
   1170     }
   1171     switch (testOption) {
   1172         case VERBOSITY_OPTION:
   1173             VERBOSITY = value;
   1174             break;
   1175         case WARN_ON_MISSING_DATA_OPTION:
   1176             WARN_ON_MISSING_DATA = value;
   1177             break;
   1178         case QUICK_OPTION:
   1179             QUICK = value;
   1180             break;
   1181         case REPEAT_TESTS_OPTION:
   1182             REPEAT_TESTS = value;
   1183             break;
   1184         case ICU_TRACE_OPTION:
   1185             ICU_TRACE = value;
   1186             break;
   1187         default :
   1188             break;
   1189     }
   1190 }
   1191 
   1192 
   1193 /*
   1194  * ================== JUnit support ================================
   1195  */
   1196 
   1197 int32_t
   1198 T_CTEST_EXPORT2
   1199 ctest_xml_setFileName(const char *name) {
   1200   XML_FILE_NAME=name;
   1201   return 0;
   1202 }
   1203 
   1204 
   1205 int32_t
   1206 T_CTEST_EXPORT2
   1207 ctest_xml_init(const char *rootName) {
   1208   if(!XML_FILE_NAME) return 0;
   1209   XML_FILE = fopen(XML_FILE_NAME,"w");
   1210   if(!XML_FILE) {
   1211     perror("fopen");
   1212     fprintf(stderr," Error: couldn't open XML output file %s\n", XML_FILE_NAME);
   1213     return 1;
   1214   }
   1215   while(*rootName&&!isalnum(*rootName)) {
   1216     rootName++;
   1217   }
   1218   strcpy(XML_PREFIX,rootName);
   1219   {
   1220     char *p = XML_PREFIX+strlen(XML_PREFIX);
   1221     for(p--;*p&&p>XML_PREFIX&&!isalnum(*p);p--) {
   1222       *p=0;
   1223     }
   1224   }
   1225   /* write prefix */
   1226   fprintf(XML_FILE, "<testsuite name=\"%s\">\n", XML_PREFIX);
   1227 
   1228   return 0;
   1229 }
   1230 
   1231 int32_t
   1232 T_CTEST_EXPORT2
   1233 ctest_xml_fini(void) {
   1234   if(!XML_FILE) return 0;
   1235 
   1236   fprintf(XML_FILE, "</testsuite>\n");
   1237   fclose(XML_FILE);
   1238   printf(" ( test results written to %s )\n", XML_FILE_NAME);
   1239   XML_FILE=0;
   1240   return 0;
   1241 }
   1242 
   1243 
   1244 int32_t
   1245 T_CTEST_EXPORT2
   1246 ctest_xml_testcase(const char *classname, const char *name, const char *time, const char *failMsg) {
   1247   if(!XML_FILE) return 0;
   1248 
   1249   fprintf(XML_FILE, "\t<testcase classname=\"%s:%s\" name=\"%s:%s\" time=\"%s\"", XML_PREFIX, classname, XML_PREFIX, name, time);
   1250   if(failMsg) {
   1251     fprintf(XML_FILE, ">\n\t\t<failure type=\"err\" message=\"%s\"/>\n\t</testcase>\n", failMsg);
   1252   } else {
   1253     fprintf(XML_FILE, "/>\n");
   1254   }
   1255 
   1256   return 0;
   1257 }
   1258 
   1259 
   1260