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