tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ctest.c (36630B)


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