ctest.c revision 85bf2e2fbc60a9f938064abc8127d61da7d19882
1/*
2********************************************************************************
3*
4*   Copyright (C) 1996-2009, 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
15#include "unicode/utrace.h"
16#include "unicode/uclean.h"
17#include "umutex.h"
18
19/* NOTES:
20   3/20/1999 srl - strncpy called w/o setting nulls at the end
21 */
22
23#define MAXTESTNAME 128
24#define MAXTESTS  512
25#define MAX_TEST_LOG 4096
26
27struct TestNode
28{
29  void (*test)(void);
30  struct TestNode* sibling;
31  struct TestNode* child;
32  char name[1]; /* This is dynamically allocated off the end with malloc. */
33};
34
35
36static const struct TestNode* currentTest;
37
38typedef enum { RUNTESTS, SHOWTESTS } TestMode;
39#define TEST_SEPARATOR '/'
40
41#ifndef C_TEST_IMPL
42#define C_TEST_IMPL
43#endif
44
45#include "unicode/ctest.h"
46
47static char ERROR_LOG[MAX_TEST_LOG][MAXTESTNAME];
48
49/* Local prototypes */
50static TestNode* addTestNode( TestNode *root, const char *name );
51
52static TestNode *createTestNode(const char* name, int32_t nameLen);
53
54static int strncmp_nullcheck( const char* s1,
55                  const char* s2,
56                  int n );
57
58static void getNextLevel( const char* name,
59              int* nameLen,
60              const char** nextName );
61
62static void iterateTestsWithLevel( const TestNode *root, int len,
63                   const TestNode** list,
64                   TestMode mode);
65
66static void help ( const char *argv0 );
67
68/**
69 * Do the work of logging an error. Doesn't increase the error count.
70 *
71 * @prefix optional prefix prepended to message, or NULL.
72 * @param pattern printf style pattern
73 * @param ap vprintf style arg list
74 */
75static void vlog_err(const char *prefix, const char *pattern, va_list ap);
76static void vlog_verbose(const char *prefix, const char *pattern, va_list ap);
77
78/* If we need to make the framework multi-thread safe
79   we need to pass around the following vars
80*/
81static int ERRONEOUS_FUNCTION_COUNT = 0;
82static int ERROR_COUNT = 0; /* Count of errors from all tests. */
83static int DATA_ERROR_COUNT = 0; /* count of data related errors or warnings */
84static int INDENT_LEVEL = 0;
85int REPEAT_TESTS_INIT = 0; /* Was REPEAT_TESTS initialized? */
86int REPEAT_TESTS = 1; /* Number of times to run the test */
87int VERBOSITY = 0; /* be No-verbose by default */
88int ERR_MSG =1; /* error messages will be displayed by default*/
89int QUICK = 1;  /* Skip some of the slower tests? */
90int WARN_ON_MISSING_DATA = 0; /* Reduce data errs to warnings? */
91UTraceLevel ICU_TRACE = UTRACE_OFF;  /* ICU tracing level */
92size_t MINIMUM_MEMORY_SIZE_FAILURE = (size_t)-1; /* Minimum library memory allocation window that will fail. */
93size_t MAXIMUM_MEMORY_SIZE_FAILURE = (size_t)-1; /* Maximum library memory allocation window that will fail. */
94int32_t ALLOCATION_COUNT = 0;
95/*-------------------------------------------*/
96
97/* strncmp that also makes sure there's a \0 at s2[0] */
98static int strncmp_nullcheck( const char* s1,
99               const char* s2,
100               int n )
101{
102    if (((int)strlen(s2) >= n) && s2[n] != 0) {
103        return 3; /* null check fails */
104    }
105    else {
106        return strncmp ( s1, s2, n );
107    }
108}
109
110static void getNextLevel( const char* name,
111           int* nameLen,
112           const char** nextName )
113{
114    /* Get the next component of the name */
115    *nextName = strchr(name, TEST_SEPARATOR);
116
117    if( *nextName != 0 )
118    {
119        char n[255];
120        *nameLen = (int)((*nextName) - name);
121        (*nextName)++; /* skip '/' */
122        strncpy(n, name, *nameLen);
123        n[*nameLen] = 0;
124        /*printf("->%s-< [%d] -> [%s]\n", name, *nameLen, *nextName);*/
125    }
126    else {
127        *nameLen = (int)strlen(name);
128    }
129}
130
131static TestNode *createTestNode(const char* name, int32_t nameLen)
132{
133    TestNode *newNode;
134
135    newNode = (TestNode*)malloc(sizeof(TestNode) + (nameLen + 1));
136
137    newNode->test = NULL;
138    newNode->sibling = NULL;
139    newNode->child = NULL;
140
141    strncpy( newNode->name, name, nameLen );
142    newNode->name[nameLen] = 0;
143
144    return  newNode;
145}
146
147void T_CTEST_EXPORT2
148cleanUpTestTree(TestNode *tn)
149{
150    if(tn->child != NULL) {
151        cleanUpTestTree(tn->child);
152    }
153    if(tn->sibling != NULL) {
154        cleanUpTestTree(tn->sibling);
155    }
156
157    free(tn);
158}
159
160
161void T_CTEST_EXPORT2
162addTest(TestNode** root,
163        TestFunctionPtr test,
164        const char* name )
165{
166    TestNode *newNode;
167
168    /*if this is the first Test created*/
169    if (*root == NULL)
170        *root = createTestNode("", 0);
171
172    newNode = addTestNode( *root, name );
173    assert(newNode != 0 );
174    /*  printf("addTest: nreName = %s\n", newNode->name );*/
175
176    newNode->test = test;
177}
178
179/* non recursive insert function */
180static TestNode *addTestNode ( TestNode *root, const char *name )
181{
182    const char* nextName;
183    TestNode *nextNode, *curNode;
184    int nameLen; /* length of current 'name' */
185
186    /* remove leading slash */
187    if ( *name == TEST_SEPARATOR )
188        name++;
189
190    curNode = root;
191
192    for(;;)
193    {
194        /* Start with the next child */
195        nextNode = curNode->child;
196
197        getNextLevel ( name, &nameLen, &nextName );
198
199        /*      printf("* %s\n", name );*/
200
201        /* if nextNode is already null, then curNode has no children
202        -- add them */
203        if( nextNode == NULL )
204        {
205            /* Add all children of the node */
206            do
207            {
208                /* Get the next component of the name */
209                getNextLevel(name, &nameLen, &nextName);
210
211                /* update curName to have the next name segment */
212                curNode->child = createTestNode(name, nameLen);
213                /* printf("*** added %s\n", curNode->child->name );*/
214                curNode = curNode->child;
215                name = nextName;
216            }
217            while( name != NULL );
218
219            return curNode;
220        }
221
222        /* Search across for the name */
223        while (strncmp_nullcheck ( name, nextNode->name, nameLen) != 0 )
224        {
225            curNode = nextNode;
226            nextNode = nextNode -> sibling;
227
228            if ( nextNode == NULL )
229            {
230                /* Did not find 'name' on this level. */
231                nextNode = createTestNode(name, nameLen);
232                curNode->sibling = nextNode;
233                break;
234            }
235        }
236
237        /* nextNode matches 'name' */
238
239        if (nextName == NULL) /* end of the line */
240        {
241            return nextNode;
242        }
243
244        /* Loop again with the next item */
245        name = nextName;
246        curNode = nextNode;
247    }
248}
249
250static void iterateTestsWithLevel ( const TestNode* root,
251                 int len,
252                 const TestNode** list,
253                 TestMode mode)
254{
255    int i;
256    int saveIndent;
257
258    char pathToFunction[MAXTESTNAME] = "";
259    char separatorString[2] = { TEST_SEPARATOR, '\0'};
260
261    if ( root == NULL )
262        return;
263
264    list[len++] = root;
265
266    for ( i=0;i<(len-1);i++ )
267    {
268        strcat(pathToFunction, list[i]->name);
269        strcat(pathToFunction, separatorString);
270    }
271
272    strcat(pathToFunction, list[i]->name);
273
274    INDENT_LEVEL = len;
275    if ( (mode == RUNTESTS) && (root->test != NULL))
276    {
277        int myERROR_COUNT = ERROR_COUNT;
278        currentTest = root;
279        root->test();
280        currentTest = NULL;
281        if (myERROR_COUNT != ERROR_COUNT)
282        {
283
284            log_info("---[%d ERRORS] ", ERROR_COUNT - myERROR_COUNT);
285            strcpy(ERROR_LOG[ERRONEOUS_FUNCTION_COUNT++], pathToFunction);
286        }
287        else
288            log_info("---[OK] ");
289    }
290
291
292    /* we want these messages to be at 0 indent. so just push the indent level breifly. */
293    saveIndent = INDENT_LEVEL;
294    INDENT_LEVEL = 0;
295    log_info("%s%s%c\n", (list[i]->test||mode==SHOWTESTS)?"---":"",pathToFunction, list[i]->test?' ':TEST_SEPARATOR );
296    INDENT_LEVEL = saveIndent;
297
298    iterateTestsWithLevel ( root->child, len, list, mode );
299
300    len--;
301
302    if ( len != 0 ) /* DO NOT iterate over siblings of the root. */
303        iterateTestsWithLevel ( root->sibling, len, list, mode );
304}
305
306
307
308void T_CTEST_EXPORT2
309showTests ( const TestNode *root )
310{
311    /* make up one for them */
312    const TestNode *aList[MAXTESTS];
313
314    if (root == NULL)
315        log_err("TEST CAN'T BE FOUND!");
316
317    iterateTestsWithLevel ( root, 0, aList, SHOWTESTS );
318
319}
320
321void T_CTEST_EXPORT2
322runTests ( const TestNode *root )
323{
324    int i;
325    const TestNode *aList[MAXTESTS];
326    /* make up one for them */
327
328
329    if (root == NULL)
330        log_err("TEST CAN'T BE FOUND!\n");
331
332    ERRONEOUS_FUNCTION_COUNT = ERROR_COUNT = 0;
333    iterateTestsWithLevel ( root, 0, aList, RUNTESTS );
334
335    /*print out result summary*/
336
337    if (ERROR_COUNT)
338    {
339        log_info("\nSUMMARY:\n******* [Total error count:\t%d]\n Errors in\n", ERROR_COUNT);
340        for (i=0;i < ERRONEOUS_FUNCTION_COUNT; i++)
341            log_info("[%s]\n",ERROR_LOG[i]);
342    }
343    else
344    {
345      log_info("\n[All tests passed successfully...]\n");
346    }
347
348    if(DATA_ERROR_COUNT) {
349      if(WARN_ON_MISSING_DATA==0) {
350        log_info("\t*Note* some errors are data-loading related. If the data used is not the \n"
351                 "\tstock ICU data (i.e some have been added or removed), consider using\n"
352                 "\tthe '-w' option to turn these errors into warnings.\n");
353      } else {
354        log_info("\t*WARNING* some data-loading errors were ignored by the -w option.\n");
355      }
356    }
357}
358
359const char* T_CTEST_EXPORT2
360getTestName(void)
361{
362  if(currentTest != NULL) {
363    return currentTest->name;
364  } else {
365    return NULL;
366  }
367}
368
369const TestNode* T_CTEST_EXPORT2
370getTest(const TestNode* root, const char* name)
371{
372    const char* nextName;
373    TestNode *nextNode;
374    const TestNode* curNode;
375    int nameLen; /* length of current 'name' */
376
377    if (root == NULL) {
378        log_err("TEST CAN'T BE FOUND!\n");
379        return NULL;
380    }
381    /* remove leading slash */
382    if ( *name == TEST_SEPARATOR )
383        name++;
384
385    curNode = root;
386
387    for(;;)
388    {
389        /* Start with the next child */
390        nextNode = curNode->child;
391
392        getNextLevel ( name, &nameLen, &nextName );
393
394        /*      printf("* %s\n", name );*/
395
396        /* if nextNode is already null, then curNode has no children
397        -- add them */
398        if( nextNode == NULL )
399        {
400            return NULL;
401        }
402
403        /* Search across for the name */
404        while (strncmp_nullcheck ( name, nextNode->name, nameLen) != 0 )
405        {
406            curNode = nextNode;
407            nextNode = nextNode -> sibling;
408
409            if ( nextNode == NULL )
410            {
411                /* Did not find 'name' on this level. */
412                return NULL;
413            }
414        }
415
416        /* nextNode matches 'name' */
417
418        if (nextName == NULL) /* end of the line */
419        {
420            return nextNode;
421        }
422
423        /* Loop again with the next item */
424        name = nextName;
425        curNode = nextNode;
426    }
427}
428
429static void vlog_err(const char *prefix, const char *pattern, va_list ap)
430{
431    if( ERR_MSG == FALSE){
432        return;
433    }
434    fprintf(stderr, "%-*s", INDENT_LEVEL," " );
435    if(prefix) {
436        fputs(prefix, stderr);
437    }
438    vfprintf(stderr, pattern, ap);
439    fflush(stderr);
440    va_end(ap);
441}
442
443void T_CTEST_EXPORT2
444vlog_info(const char *prefix, const char *pattern, va_list ap)
445{
446    fprintf(stdout, "%-*s", INDENT_LEVEL," " );
447    if(prefix) {
448        fputs(prefix, stdout);
449    }
450    vfprintf(stdout, pattern, ap);
451    fflush(stdout);
452    va_end(ap);
453}
454
455static void vlog_verbose(const char *prefix, const char *pattern, va_list ap)
456{
457    if ( VERBOSITY == FALSE )
458        return;
459
460    fprintf(stdout, "%-*s", INDENT_LEVEL," " );
461    if(prefix) {
462        fputs(prefix, stdout);
463    }
464    vfprintf(stdout, pattern, ap);
465    fflush(stdout);
466    va_end(ap);
467}
468
469void T_CTEST_EXPORT2
470log_err(const char* pattern, ...)
471{
472    va_list ap;
473    if(strchr(pattern, '\n') != NULL) {
474        /*
475         * Count errors only if there is a line feed in the pattern
476         * so that we do not exaggerate our error count.
477         */
478        ++ERROR_COUNT;
479    }
480    va_start(ap, pattern);
481    vlog_err(NULL, pattern, ap);
482}
483
484void T_CTEST_EXPORT2
485log_err_status(UErrorCode status, const char* pattern, ...)
486{
487    va_list ap;
488    va_start(ap, pattern);
489
490    if ((status == U_FILE_ACCESS_ERROR || status == U_MISSING_RESOURCE_ERROR)) {
491        ++DATA_ERROR_COUNT; /* for informational message at the end */
492
493        if (WARN_ON_MISSING_DATA == 0) {
494            /* Fatal error. */
495            if (strchr(pattern, '\n') != NULL) {
496                ++ERROR_COUNT;
497            }
498            vlog_err(NULL, pattern, ap); /* no need for prefix in default case */
499        } else {
500            vlog_info("[DATA] ", pattern, ap);
501        }
502    } else {
503        /* Fatal error. */
504        if(strchr(pattern, '\n') != NULL) {
505            ++ERROR_COUNT;
506        }
507        vlog_err(NULL, pattern, ap); /* no need for prefix in default case */
508    }
509}
510
511void T_CTEST_EXPORT2
512log_info(const char* pattern, ...)
513{
514    va_list ap;
515
516    va_start(ap, pattern);
517    vlog_info(NULL, pattern, ap);
518}
519
520void T_CTEST_EXPORT2
521log_verbose(const char* pattern, ...)
522{
523    va_list ap;
524
525    va_start(ap, pattern);
526    vlog_verbose(NULL, pattern, ap);
527}
528
529
530void T_CTEST_EXPORT2
531log_data_err(const char* pattern, ...)
532{
533    va_list ap;
534    va_start(ap, pattern);
535
536    ++DATA_ERROR_COUNT; /* for informational message at the end */
537
538    if(WARN_ON_MISSING_DATA == 0) {
539        /* Fatal error. */
540        if(strchr(pattern, '\n') != NULL) {
541            ++ERROR_COUNT;
542        }
543        vlog_err(NULL, pattern, ap); /* no need for prefix in default case */
544    } else {
545        vlog_info("[DATA] ", pattern, ap);
546    }
547}
548
549
550/*
551 * Tracing functions.
552 */
553static int traceFnNestingDepth = 0;
554U_CDECL_BEGIN
555static void U_CALLCONV TraceEntry(const void *context, int32_t fnNumber) {
556    char buf[500];
557    utrace_format(buf, sizeof(buf), traceFnNestingDepth*3, "%s() enter.\n", utrace_functionName(fnNumber));    buf[sizeof(buf)-1]=0;
558    fputs(buf, stdout);
559    traceFnNestingDepth++;
560}
561
562static void U_CALLCONV TraceExit(const void *context, int32_t fnNumber, const char *fmt, va_list args) {    char buf[500];
563
564    if (traceFnNestingDepth>0) {
565        traceFnNestingDepth--;
566    }
567    utrace_format(buf, sizeof(buf), traceFnNestingDepth*3, "%s() ", utrace_functionName(fnNumber));    buf[sizeof(buf)-1]=0;
568    fputs(buf, stdout);
569    utrace_vformat(buf, sizeof(buf), traceFnNestingDepth*3, fmt, args);
570    buf[sizeof(buf)-1]=0;
571    fputs(buf, stdout);
572    putc('\n', stdout);
573}
574
575static void U_CALLCONV TraceData(const void *context, int32_t fnNumber,
576                          int32_t level, const char *fmt, va_list args) {
577    char buf[500];
578    utrace_vformat(buf, sizeof(buf), traceFnNestingDepth*3, fmt, args);
579    buf[sizeof(buf)-1]=0;
580    fputs(buf, stdout);
581    putc('\n', stdout);
582}
583
584static void *U_CALLCONV ctest_libMalloc(const void *context, size_t size) {
585    /*if (VERBOSITY) {
586        printf("Allocated %ld\n", (long)size);
587    }*/
588    if (MINIMUM_MEMORY_SIZE_FAILURE <= size && size <= MAXIMUM_MEMORY_SIZE_FAILURE) {
589        return NULL;
590    }
591    umtx_atomic_inc(&ALLOCATION_COUNT);
592    return malloc(size);
593}
594static void *U_CALLCONV ctest_libRealloc(const void *context, void *mem, size_t size) {
595    /*if (VERBOSITY) {
596        printf("Reallocated %ld\n", (long)size);
597    }*/
598    if (MINIMUM_MEMORY_SIZE_FAILURE <= size && size <= MAXIMUM_MEMORY_SIZE_FAILURE) {
599        /*free(mem);*/ /* Realloc doesn't free on failure. */
600        return NULL;
601    }
602    if (mem == NULL) {
603        /* New allocation. */
604        umtx_atomic_inc(&ALLOCATION_COUNT);
605    }
606    return realloc(mem, size);
607}
608static void U_CALLCONV ctest_libFree(const void *context, void *mem) {
609    if (mem != NULL) {
610        umtx_atomic_dec(&ALLOCATION_COUNT);
611    }
612    free(mem);
613}
614
615int T_CTEST_EXPORT2
616initArgs( int argc, const char* const argv[], ArgHandlerPtr argHandler, void *context)
617{
618    int                i;
619    int                doList = FALSE;
620	int                argSkip = 0;
621
622    VERBOSITY = FALSE;
623    ERR_MSG = TRUE;
624
625    for( i=1; i<argc; i++)
626    {
627        if ( argv[i][0] == '/' )
628        {
629            /* We don't run the tests here. */
630            continue;
631        }
632        else if ((strcmp( argv[i], "-a") == 0) || (strcmp(argv[i],"-all") == 0))
633        {
634            /* We don't run the tests here. */
635            continue;
636        }
637        else if (strcmp( argv[i], "-v" )==0 || strcmp( argv[i], "-verbose")==0)
638        {
639            VERBOSITY = TRUE;
640        }
641        else if (strcmp( argv[i], "-l" )==0 )
642        {
643            doList = TRUE;
644        }
645        else if (strcmp( argv[i], "-e1") == 0)
646        {
647            QUICK = -1;
648        }
649        else if (strcmp( argv[i], "-e") ==0)
650        {
651            QUICK = 0;
652        }
653        else if (strcmp( argv[i], "-w") ==0)
654        {
655            WARN_ON_MISSING_DATA = TRUE;
656        }
657        else if (strcmp( argv[i], "-m") ==0)
658        {
659            UErrorCode errorCode = U_ZERO_ERROR;
660            if (i+1 < argc) {
661                char *endPtr = NULL;
662                i++;
663                MINIMUM_MEMORY_SIZE_FAILURE = (size_t)strtol(argv[i], &endPtr, 10);
664                if (endPtr == argv[i]) {
665                    printf("Can't parse %s\n", argv[i]);
666                    help(argv[0]);
667                    return 0;
668                }
669                if (*endPtr == '-') {
670                    char *maxPtr = endPtr+1;
671                    endPtr = NULL;
672                    MAXIMUM_MEMORY_SIZE_FAILURE = (size_t)strtol(maxPtr, &endPtr, 10);
673                    if (endPtr == argv[i]) {
674                        printf("Can't parse %s\n", argv[i]);
675                        help(argv[0]);
676                        return 0;
677                    }
678                }
679            }
680            /* Use the default value */
681            u_setMemoryFunctions(NULL, ctest_libMalloc, ctest_libRealloc, ctest_libFree, &errorCode);
682            if (U_FAILURE(errorCode)) {
683                printf("u_setMemoryFunctions returned %s\n", u_errorName(errorCode));
684                return 0;
685            }
686        }
687        else if(strcmp( argv[i], "-n") == 0 || strcmp( argv[i], "-no_err_msg") == 0)
688        {
689            ERR_MSG = FALSE;
690        }
691        else if (strcmp( argv[i], "-r") == 0)
692        {
693            if (!REPEAT_TESTS_INIT) {
694                REPEAT_TESTS++;
695            }
696        }
697        else if (strcmp( argv[i], "-t_info") == 0) {
698            ICU_TRACE = UTRACE_INFO;
699        }
700        else if (strcmp( argv[i], "-t_error") == 0) {
701            ICU_TRACE = UTRACE_ERROR;
702        }
703        else if (strcmp( argv[i], "-t_warn") == 0) {
704            ICU_TRACE = UTRACE_WARNING;
705        }
706        else if (strcmp( argv[i], "-t_verbose") == 0) {
707            ICU_TRACE = UTRACE_VERBOSE;
708        }
709        else if (strcmp( argv[i], "-t_oc") == 0) {
710            ICU_TRACE = UTRACE_OPEN_CLOSE;
711        }
712        else if (strcmp( argv[i], "-h" )==0 || strcmp( argv[i], "--help" )==0)
713        {
714            help( argv[0] );
715            return 0;
716        }
717        else if (argHandler != NULL && (argSkip = argHandler(i, argc, argv, context)) > 0)
718        {
719            i += argSkip - 1;
720        }
721        else
722        {
723            printf("* unknown option: %s\n", argv[i]);
724            help( argv[0] );
725            return 0;
726        }
727    }
728    if (ICU_TRACE != UTRACE_OFF) {
729        utrace_setFunctions(NULL, TraceEntry, TraceExit, TraceData);
730        utrace_setLevel(ICU_TRACE);
731    }
732
733    return 1; /* total error count */
734}
735
736int T_CTEST_EXPORT2
737runTestRequest(const TestNode* root,
738             int argc,
739             const char* const argv[])
740{
741    /**
742     * This main will parse the l, v, h, n, and path arguments
743     */
744    const TestNode*    toRun;
745    int                i;
746    int                doList = FALSE;
747    int                subtreeOptionSeen = FALSE;
748
749    int                errorCount = 0;
750
751    toRun = root;
752
753    for( i=1; i<argc; i++)
754    {
755        if ( argv[i][0] == '/' )
756        {
757            printf("Selecting subtree '%s'\n", argv[i]);
758
759            if ( argv[i][1] == 0 )
760                toRun = root;
761            else
762                toRun = getTest(root, argv[i]);
763
764            if ( toRun == NULL )
765            {
766                printf("* Could not find any matching subtree\n");
767                return -1;
768            }
769
770            if( doList == TRUE)
771                showTests(toRun);
772            else
773                runTests(toRun);
774
775            errorCount += ERROR_COUNT;
776
777            subtreeOptionSeen = TRUE;
778        } else if ((strcmp( argv[i], "-a") == 0) || (strcmp(argv[i],"-all") == 0)) {
779            subtreeOptionSeen=FALSE;
780        } else if (strcmp( argv[i], "-l") == 0) {
781            doList = TRUE;
782        }
783        /* else option already handled by initArgs */
784    }
785
786    if( subtreeOptionSeen == FALSE) /* no other subtree given, run the default */
787    {
788        if( doList == TRUE)
789            showTests(toRun);
790        else
791            runTests(toRun);
792
793        errorCount += ERROR_COUNT;
794    }
795    else
796    {
797        if( ( doList == FALSE ) && ( errorCount > 0 ) )
798            printf(" Total errors: %d\n", errorCount );
799    }
800
801    REPEAT_TESTS_INIT = 1;
802
803    return errorCount; /* total error count */
804}
805
806/**
807 * Display program invocation arguments
808 */
809
810static void help ( const char *argv0 )
811{
812    printf("Usage: %s [ -l ] [ -v ] [ -verbose] [-a] [ -all] [-n] [ -no_err_msg]\n"
813           "    [ -h ] [-t_info | -t_error | -t_warn | -t_oc | -t_verbose] [-m n[-q] ]\n"
814           "    [ /path/to/test ]\n",
815            argv0);
816    printf("    -l  To get a list of test names\n");
817    printf("    -e  to do exhaustive testing\n");
818    printf("    -verbose To turn ON verbosity\n");
819    printf("    -v  To turn ON verbosity(same as -verbose)\n");
820    printf("    -h  To print this message\n");
821    printf("    -n  To turn OFF printing error messages\n");
822    printf("    -w  Don't fail on data-loading errs, just warn. Useful if\n"
823           "        user has reduced/changed the common set of ICU data \n");
824    printf("    -t_info | -t_error | -t_warn | -t_oc | -t_verbose  Enable ICU tracing\n");
825    printf("    -no_err_msg (same as -n) \n");
826    printf("    -m n[-q] Min-Max memory size that will cause an allocation failure.\n");
827    printf("        The default is the maximum value of size_t. Max is optional.\n");
828    printf("    -r  Repeat tests after calling u_cleanup \n");
829    printf("    [/subtest]  To run a subtest \n");
830    printf("    eg: to run just the utility tests type: cintltest /tsutil) \n");
831}
832
833