intl/icu/source/tools/ctestfw/ctest.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial