Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygentestrecurse.c
Go to the documentation of this file.
00001 /* 00002 * testrecurse.c: C program to run libxml2 regression tests checking entities 00003 * recursions 00004 * 00005 * To compile on Unixes: 00006 * cc -o testrecurse `xml2-config --cflags` testrecurse.c `xml2-config --libs` -lpthread 00007 * 00008 * See Copyright for the status of this software. 00009 * 00010 * daniel@veillard.com 00011 */ 00012 00013 #ifdef HAVE_CONFIG_H 00014 #include "libxml.h" 00015 #else 00016 #include <stdio.h> 00017 #endif 00018 00019 #if !defined(_WIN32) || defined(__CYGWIN__) 00020 #include <unistd.h> 00021 #endif 00022 #include <string.h> 00023 #include <sys/types.h> 00024 #include <sys/stat.h> 00025 #include <fcntl.h> 00026 00027 #include <libxml/parser.h> 00028 #include <libxml/tree.h> 00029 #include <libxml/uri.h> 00030 #ifdef LIBXML_READER_ENABLED 00031 #include <libxml/xmlreader.h> 00032 #endif 00033 00034 /* 00035 * O_BINARY is just for Windows compatibility - if it isn't defined 00036 * on this system, avoid any compilation error 00037 */ 00038 #ifdef O_BINARY 00039 #define RD_FLAGS O_RDONLY | O_BINARY 00040 #else 00041 #define RD_FLAGS O_RDONLY 00042 #endif 00043 00044 typedef int (*functest) (const char *filename, const char *result, 00045 const char *error, int options); 00046 00047 typedef struct testDesc testDesc; 00048 typedef testDesc *testDescPtr; 00049 struct testDesc { 00050 const char *desc; /* descripton of the test */ 00051 functest func; /* function implementing the test */ 00052 const char *in; /* glob to path for input files */ 00053 const char *out; /* output directory */ 00054 const char *suffix;/* suffix for output files */ 00055 const char *err; /* suffix for error output files */ 00056 int options; /* parser options for the test */ 00057 }; 00058 00059 static int checkTestFile(const char *filename); 00060 00061 00062 #if defined(_WIN32) && !defined(__CYGWIN__) 00063 00064 #include <windows.h> 00065 #include <io.h> 00066 00067 typedef struct 00068 { 00069 size_t gl_pathc; /* Count of paths matched so far */ 00070 char **gl_pathv; /* List of matched pathnames. */ 00071 size_t gl_offs; /* Slots to reserve in 'gl_pathv'. */ 00072 } glob_t; 00073 00074 #define GLOB_DOOFFS 0 00075 static int glob(const char *pattern, int flags, 00076 int errfunc(const char *epath, int eerrno), 00077 glob_t *pglob) { 00078 glob_t *ret; 00079 WIN32_FIND_DATA FindFileData; 00080 HANDLE hFind; 00081 unsigned int nb_paths = 0; 00082 char directory[500]; 00083 int len; 00084 00085 if ((pattern == NULL) || (pglob == NULL)) return(-1); 00086 00087 strncpy(directory, pattern, 499); 00088 for (len = strlen(directory);len >= 0;len--) { 00089 if (directory[len] == '/') { 00090 len++; 00091 directory[len] = 0; 00092 break; 00093 } 00094 } 00095 if (len <= 0) 00096 len = 0; 00097 00098 00099 ret = pglob; 00100 memset(ret, 0, sizeof(glob_t)); 00101 00102 hFind = FindFirstFileA(pattern, &FindFileData); 00103 if (hFind == INVALID_HANDLE_VALUE) 00104 return(0); 00105 nb_paths = 20; 00106 ret->gl_pathv = (char **) malloc(nb_paths * sizeof(char *)); 00107 if (ret->gl_pathv == NULL) { 00108 FindClose(hFind); 00109 return(-1); 00110 } 00111 strncpy(directory + len, FindFileData.cFileName, 499 - len); 00112 ret->gl_pathv[ret->gl_pathc] = strdup(directory); 00113 if (ret->gl_pathv[ret->gl_pathc] == NULL) 00114 goto done; 00115 ret->gl_pathc++; 00116 while(FindNextFileA(hFind, &FindFileData)) { 00117 if (FindFileData.cFileName[0] == '.') 00118 continue; 00119 if (ret->gl_pathc + 2 > nb_paths) { 00120 char **tmp = realloc(ret->gl_pathv, nb_paths * 2 * sizeof(char *)); 00121 if (tmp == NULL) 00122 break; 00123 ret->gl_pathv = tmp; 00124 nb_paths *= 2; 00125 } 00126 strncpy(directory + len, FindFileData.cFileName, 499 - len); 00127 ret->gl_pathv[ret->gl_pathc] = strdup(directory); 00128 if (ret->gl_pathv[ret->gl_pathc] == NULL) 00129 break; 00130 ret->gl_pathc++; 00131 } 00132 ret->gl_pathv[ret->gl_pathc] = NULL; 00133 00134 done: 00135 FindClose(hFind); 00136 return(0); 00137 } 00138 00139 00140 00141 static void globfree(glob_t *pglob) { 00142 unsigned int i; 00143 if (pglob == NULL) 00144 return; 00145 00146 for (i = 0;i < pglob->gl_pathc;i++) { 00147 if (pglob->gl_pathv[i] != NULL) 00148 free(pglob->gl_pathv[i]); 00149 } 00150 } 00151 #define vsnprintf _vsnprintf 00152 #define snprintf _snprintf 00153 #else 00154 #include <glob.h> 00155 #endif 00156 00157 /************************************************************************ 00158 * * 00159 * Huge document generator * 00160 * * 00161 ************************************************************************/ 00162 00163 #include <libxml/xmlIO.h> 00164 00165 00166 static const char *start = "<!DOCTYPE foo [\ 00167 <!ENTITY f 'some internal data'> \ 00168 <!ENTITY e '&f;&f;'> \ 00169 <!ENTITY d '&e;&e;'> \ 00170 ]> \ 00171 <foo>"; 00172 00173 static const char *segment = " <bar>&e; &f; &d;</bar>\n"; 00174 static const char *finish = "</foo>"; 00175 00176 static int curseg = 0; 00177 static const char *current; 00178 static int rlen; 00179 00188 static int 00189 hugeMatch(const char * URI) { 00190 if ((URI != NULL) && (!strncmp(URI, "huge:", 4))) 00191 return(1); 00192 return(0); 00193 } 00194 00204 static void * 00205 hugeOpen(const char * URI) { 00206 if ((URI == NULL) || (strncmp(URI, "huge:", 4))) 00207 return(NULL); 00208 rlen = strlen(start); 00209 current = start; 00210 return((void *) current); 00211 } 00212 00221 static int 00222 hugeClose(void * context) { 00223 if (context == NULL) return(-1); 00224 return(0); 00225 } 00226 00227 #define MAX_NODES 1000000 00228 00239 static int 00240 hugeRead(void *context, char *buffer, int len) 00241 { 00242 if ((context == NULL) || (buffer == NULL) || (len < 0)) 00243 return (-1); 00244 00245 if (len >= rlen) { 00246 if (curseg >= MAX_NODES + 1) { 00247 rlen = 0; 00248 return(0); 00249 } 00250 len = rlen; 00251 rlen = 0; 00252 memcpy(buffer, current, len); 00253 curseg ++; 00254 if (curseg == MAX_NODES) { 00255 fprintf(stderr, "\n"); 00256 rlen = strlen(finish); 00257 current = finish; 00258 } else { 00259 if (curseg % (MAX_NODES / 10) == 0) 00260 fprintf(stderr, "."); 00261 rlen = strlen(segment); 00262 current = segment; 00263 } 00264 } else { 00265 memcpy(buffer, current, len); 00266 rlen -= len; 00267 current += len; 00268 } 00269 return (len); 00270 } 00271 00272 /************************************************************************ 00273 * * 00274 * Libxml2 specific routines * 00275 * * 00276 ************************************************************************/ 00277 00278 static int nb_tests = 0; 00279 static int nb_errors = 0; 00280 static int nb_leaks = 0; 00281 static int extraMemoryFromResolver = 0; 00282 00283 static int 00284 fatalError(void) { 00285 fprintf(stderr, "Exitting tests on fatal error\n"); 00286 exit(1); 00287 } 00288 00289 /* 00290 * We need to trap calls to the resolver to not account memory for the catalog 00291 * which is shared to the current running test. We also don't want to have 00292 * network downloads modifying tests. 00293 */ 00294 static xmlParserInputPtr 00295 testExternalEntityLoader(const char *URL, const char *ID, 00296 xmlParserCtxtPtr ctxt) { 00297 xmlParserInputPtr ret; 00298 00299 if (checkTestFile(URL)) { 00300 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt); 00301 } else { 00302 int memused = xmlMemUsed(); 00303 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt); 00304 extraMemoryFromResolver += xmlMemUsed() - memused; 00305 } 00306 00307 return(ret); 00308 } 00309 00310 /* 00311 * Trapping the error messages at the generic level to grab the equivalent of 00312 * stderr messages on CLI tools. 00313 */ 00314 static char testErrors[32769]; 00315 static int testErrorsSize = 0; 00316 00317 static void XMLCDECL 00318 channel(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) { 00319 va_list args; 00320 int res; 00321 00322 if (testErrorsSize >= 32768) 00323 return; 00324 va_start(args, msg); 00325 res = vsnprintf(&testErrors[testErrorsSize], 00326 32768 - testErrorsSize, 00327 msg, args); 00328 va_end(args); 00329 if (testErrorsSize + res >= 32768) { 00330 /* buffer is full */ 00331 testErrorsSize = 32768; 00332 testErrors[testErrorsSize] = 0; 00333 } else { 00334 testErrorsSize += res; 00335 } 00336 testErrors[testErrorsSize] = 0; 00337 } 00338 00346 static void 00347 xmlParserPrintFileContextInternal(xmlParserInputPtr input , 00348 xmlGenericErrorFunc chanl, void *data ) { 00349 const xmlChar *cur, *base; 00350 unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */ 00351 xmlChar content[81]; /* space for 80 chars + line terminator */ 00352 xmlChar *ctnt; 00353 00354 if (input == NULL) return; 00355 cur = input->cur; 00356 base = input->base; 00357 /* skip backwards over any end-of-lines */ 00358 while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) { 00359 cur--; 00360 } 00361 n = 0; 00362 /* search backwards for beginning-of-line (to max buff size) */ 00363 while ((n++ < (sizeof(content)-1)) && (cur > base) && 00364 (*(cur) != '\n') && (*(cur) != '\r')) 00365 cur--; 00366 if ((*(cur) == '\n') || (*(cur) == '\r')) cur++; 00367 /* calculate the error position in terms of the current position */ 00368 col = input->cur - cur; 00369 /* search forward for end-of-line (to max buff size) */ 00370 n = 0; 00371 ctnt = content; 00372 /* copy selected text to our buffer */ 00373 while ((*cur != 0) && (*(cur) != '\n') && 00374 (*(cur) != '\r') && (n < sizeof(content)-1)) { 00375 *ctnt++ = *cur++; 00376 n++; 00377 } 00378 *ctnt = 0; 00379 /* print out the selected text */ 00380 chanl(data ,"%s\n", content); 00381 /* create blank line with problem pointer */ 00382 n = 0; 00383 ctnt = content; 00384 /* (leave buffer space for pointer + line terminator) */ 00385 while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) { 00386 if (*(ctnt) != '\t') 00387 *(ctnt) = ' '; 00388 ctnt++; 00389 } 00390 *ctnt++ = '^'; 00391 *ctnt = 0; 00392 chanl(data ,"%s\n", content); 00393 } 00394 00395 static void 00396 testStructuredErrorHandler(void *ctx ATTRIBUTE_UNUSED, xmlErrorPtr err) { 00397 char *file = NULL; 00398 int line = 0; 00399 int code = -1; 00400 int domain; 00401 void *data = NULL; 00402 const char *str; 00403 const xmlChar *name = NULL; 00404 xmlNodePtr node; 00405 xmlErrorLevel level; 00406 xmlParserInputPtr input = NULL; 00407 xmlParserInputPtr cur = NULL; 00408 xmlParserCtxtPtr ctxt = NULL; 00409 00410 if (err == NULL) 00411 return; 00412 00413 file = err->file; 00414 line = err->line; 00415 code = err->code; 00416 domain = err->domain; 00417 level = err->level; 00418 node = err->node; 00419 if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) || 00420 (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) || 00421 (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) { 00422 ctxt = err->ctxt; 00423 } 00424 str = err->message; 00425 00426 if (code == XML_ERR_OK) 00427 return; 00428 00429 if ((node != NULL) && (node->type == XML_ELEMENT_NODE)) 00430 name = node->name; 00431 00432 /* 00433 * Maintain the compatibility with the legacy error handling 00434 */ 00435 if (ctxt != NULL) { 00436 input = ctxt->input; 00437 if ((input != NULL) && (input->filename == NULL) && 00438 (ctxt->inputNr > 1)) { 00439 cur = input; 00440 input = ctxt->inputTab[ctxt->inputNr - 2]; 00441 } 00442 if (input != NULL) { 00443 if (input->filename) 00444 channel(data, "%s:%d: ", input->filename, input->line); 00445 else if ((line != 0) && (domain == XML_FROM_PARSER)) 00446 channel(data, "Entity: line %d: ", input->line); 00447 } 00448 } else { 00449 if (file != NULL) 00450 channel(data, "%s:%d: ", file, line); 00451 else if ((line != 0) && (domain == XML_FROM_PARSER)) 00452 channel(data, "Entity: line %d: ", line); 00453 } 00454 if (name != NULL) { 00455 channel(data, "element %s: ", name); 00456 } 00457 if (code == XML_ERR_OK) 00458 return; 00459 switch (domain) { 00460 case XML_FROM_PARSER: 00461 channel(data, "parser "); 00462 break; 00463 case XML_FROM_NAMESPACE: 00464 channel(data, "namespace "); 00465 break; 00466 case XML_FROM_DTD: 00467 case XML_FROM_VALID: 00468 channel(data, "validity "); 00469 break; 00470 case XML_FROM_HTML: 00471 channel(data, "HTML parser "); 00472 break; 00473 case XML_FROM_MEMORY: 00474 channel(data, "memory "); 00475 break; 00476 case XML_FROM_OUTPUT: 00477 channel(data, "output "); 00478 break; 00479 case XML_FROM_IO: 00480 channel(data, "I/O "); 00481 break; 00482 case XML_FROM_XINCLUDE: 00483 channel(data, "XInclude "); 00484 break; 00485 case XML_FROM_XPATH: 00486 channel(data, "XPath "); 00487 break; 00488 case XML_FROM_XPOINTER: 00489 channel(data, "parser "); 00490 break; 00491 case XML_FROM_REGEXP: 00492 channel(data, "regexp "); 00493 break; 00494 case XML_FROM_MODULE: 00495 channel(data, "module "); 00496 break; 00497 case XML_FROM_SCHEMASV: 00498 channel(data, "Schemas validity "); 00499 break; 00500 case XML_FROM_SCHEMASP: 00501 channel(data, "Schemas parser "); 00502 break; 00503 case XML_FROM_RELAXNGP: 00504 channel(data, "Relax-NG parser "); 00505 break; 00506 case XML_FROM_RELAXNGV: 00507 channel(data, "Relax-NG validity "); 00508 break; 00509 case XML_FROM_CATALOG: 00510 channel(data, "Catalog "); 00511 break; 00512 case XML_FROM_C14N: 00513 channel(data, "C14N "); 00514 break; 00515 case XML_FROM_XSLT: 00516 channel(data, "XSLT "); 00517 break; 00518 default: 00519 break; 00520 } 00521 if (code == XML_ERR_OK) 00522 return; 00523 switch (level) { 00524 case XML_ERR_NONE: 00525 channel(data, ": "); 00526 break; 00527 case XML_ERR_WARNING: 00528 channel(data, "warning : "); 00529 break; 00530 case XML_ERR_ERROR: 00531 channel(data, "error : "); 00532 break; 00533 case XML_ERR_FATAL: 00534 channel(data, "error : "); 00535 break; 00536 } 00537 if (code == XML_ERR_OK) 00538 return; 00539 if (str != NULL) { 00540 int len; 00541 len = xmlStrlen((const xmlChar *)str); 00542 if ((len > 0) && (str[len - 1] != '\n')) 00543 channel(data, "%s\n", str); 00544 else 00545 channel(data, "%s", str); 00546 } else { 00547 channel(data, "%s\n", "out of memory error"); 00548 } 00549 if (code == XML_ERR_OK) 00550 return; 00551 00552 if (ctxt != NULL) { 00553 xmlParserPrintFileContextInternal(input, channel, data); 00554 if (cur != NULL) { 00555 if (cur->filename) 00556 channel(data, "%s:%d: \n", cur->filename, cur->line); 00557 else if ((line != 0) && (domain == XML_FROM_PARSER)) 00558 channel(data, "Entity: line %d: \n", cur->line); 00559 xmlParserPrintFileContextInternal(cur, channel, data); 00560 } 00561 } 00562 if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) && 00563 (err->int1 < 100) && 00564 (err->int1 < xmlStrlen((const xmlChar *)err->str1))) { 00565 xmlChar buf[150]; 00566 int i; 00567 00568 channel(data, "%s\n", err->str1); 00569 for (i=0;i < err->int1;i++) 00570 buf[i] = ' '; 00571 buf[i++] = '^'; 00572 buf[i] = 0; 00573 channel(data, "%s\n", buf); 00574 } 00575 } 00576 00577 static void 00578 initializeLibxml2(void) { 00579 xmlGetWarningsDefaultValue = 0; 00580 xmlPedanticParserDefault(0); 00581 00582 xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup); 00583 xmlInitParser(); 00584 xmlSetExternalEntityLoader(testExternalEntityLoader); 00585 xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler); 00586 /* 00587 * register the new I/O handlers 00588 */ 00589 if (xmlRegisterInputCallbacks(hugeMatch, hugeOpen, 00590 hugeRead, hugeClose) < 0) { 00591 fprintf(stderr, "failed to register Huge handler\n"); 00592 exit(1); 00593 } 00594 } 00595 00596 /************************************************************************ 00597 * * 00598 * File name and path utilities * 00599 * * 00600 ************************************************************************/ 00601 00602 static const char *baseFilename(const char *filename) { 00603 const char *cur; 00604 if (filename == NULL) 00605 return(NULL); 00606 cur = &filename[strlen(filename)]; 00607 while ((cur > filename) && (*cur != '/')) 00608 cur--; 00609 if (*cur == '/') 00610 return(cur + 1); 00611 return(cur); 00612 } 00613 00614 static char *resultFilename(const char *filename, const char *out, 00615 const char *suffix) { 00616 const char *base; 00617 char res[500]; 00618 char suffixbuff[500]; 00619 00620 /************* 00621 if ((filename[0] == 't') && (filename[1] == 'e') && 00622 (filename[2] == 's') && (filename[3] == 't') && 00623 (filename[4] == '/')) 00624 filename = &filename[5]; 00625 *************/ 00626 00627 base = baseFilename(filename); 00628 if (suffix == NULL) 00629 suffix = ".tmp"; 00630 if (out == NULL) 00631 out = ""; 00632 00633 strncpy(suffixbuff,suffix,499); 00634 #ifdef VMS 00635 if(strstr(base,".") && suffixbuff[0]=='.') 00636 suffixbuff[0]='_'; 00637 #endif 00638 00639 snprintf(res, 499, "%s%s%s", out, base, suffixbuff); 00640 res[499] = 0; 00641 return(strdup(res)); 00642 } 00643 00644 static int checkTestFile(const char *filename) { 00645 struct stat buf; 00646 00647 if (stat(filename, &buf) == -1) 00648 return(0); 00649 00650 #if defined(_WIN32) && !defined(__CYGWIN__) 00651 if (!(buf.st_mode & _S_IFREG)) 00652 return(0); 00653 #else 00654 if (!S_ISREG(buf.st_mode)) 00655 return(0); 00656 #endif 00657 00658 return(1); 00659 } 00660 00661 00662 00663 /************************************************************************ 00664 * * 00665 * Test to detect or not recursive entities * 00666 * * 00667 ************************************************************************/ 00679 static int 00680 recursiveDetectTest(const char *filename, 00681 const char *result ATTRIBUTE_UNUSED, 00682 const char *err ATTRIBUTE_UNUSED, 00683 int options ATTRIBUTE_UNUSED) { 00684 xmlDocPtr doc; 00685 xmlParserCtxtPtr ctxt; 00686 int res = 0; 00687 int mem; 00688 00689 nb_tests++; 00690 00691 ctxt = xmlNewParserCtxt(); 00692 mem = xmlMemUsed(); 00693 /* 00694 * base of the test, parse with the old API 00695 */ 00696 doc = xmlCtxtReadFile(ctxt, filename, NULL, 00697 XML_PARSE_NOENT | XML_PARSE_DTDLOAD); 00698 if ((doc != NULL) || (ctxt->lastError.code != XML_ERR_ENTITY_LOOP)) { 00699 fprintf(stderr, "Failed to detect recursion in %s\n", filename); 00700 xmlFreeParserCtxt(ctxt); 00701 xmlFreeDoc(doc); 00702 return(1); 00703 } 00704 xmlFreeParserCtxt(ctxt); 00705 00706 return(res); 00707 } 00708 00720 static int 00721 notRecursiveDetectTest(const char *filename, 00722 const char *result ATTRIBUTE_UNUSED, 00723 const char *err ATTRIBUTE_UNUSED, 00724 int options ATTRIBUTE_UNUSED) { 00725 xmlDocPtr doc; 00726 xmlParserCtxtPtr ctxt; 00727 int res = 0; 00728 int mem; 00729 00730 nb_tests++; 00731 00732 ctxt = xmlNewParserCtxt(); 00733 mem = xmlMemUsed(); 00734 /* 00735 * base of the test, parse with the old API 00736 */ 00737 doc = xmlCtxtReadFile(ctxt, filename, NULL, 00738 XML_PARSE_NOENT | XML_PARSE_DTDLOAD); 00739 if (doc == NULL) { 00740 fprintf(stderr, "Failed to parse correct file %s\n", filename); 00741 xmlFreeParserCtxt(ctxt); 00742 return(1); 00743 } 00744 xmlFreeDoc(doc); 00745 xmlFreeParserCtxt(ctxt); 00746 00747 return(res); 00748 } 00749 00750 #ifdef LIBXML_READER_ENABLED 00751 00762 static int 00763 notRecursiveHugeTest(const char *filename ATTRIBUTE_UNUSED, 00764 const char *result ATTRIBUTE_UNUSED, 00765 const char *err ATTRIBUTE_UNUSED, 00766 int options ATTRIBUTE_UNUSED) { 00767 xmlTextReaderPtr reader; 00768 int res = 0; 00769 int ret; 00770 00771 nb_tests++; 00772 00773 reader = xmlReaderForFile("huge:test" , NULL, 00774 XML_PARSE_NOENT | XML_PARSE_DTDLOAD); 00775 if (reader == NULL) { 00776 fprintf(stderr, "Failed to open huge:test\n"); 00777 return(1); 00778 } 00779 ret = xmlTextReaderRead(reader); 00780 while (ret == 1) { 00781 ret = xmlTextReaderRead(reader); 00782 } 00783 if (ret != 0) { 00784 fprintf(stderr, "Failed to parser huge:test with entities\n"); 00785 res = 1; 00786 } 00787 xmlFreeTextReader(reader); 00788 00789 return(res); 00790 } 00791 #endif 00792 00793 /************************************************************************ 00794 * * 00795 * Tests Descriptions * 00796 * * 00797 ************************************************************************/ 00798 00799 static 00800 testDesc testDescriptions[] = { 00801 { "Parsing recursive test cases" , 00802 recursiveDetectTest, "./test/recurse/lol*.xml", NULL, NULL, NULL, 00803 0 }, 00804 { "Parsing non-recursive test cases" , 00805 notRecursiveDetectTest, "./test/recurse/good*.xml", NULL, NULL, NULL, 00806 0 }, 00807 #ifdef LIBXML_READER_ENABLED 00808 { "Parsing non-recursive huge case" , 00809 notRecursiveHugeTest, NULL, NULL, NULL, NULL, 00810 0 }, 00811 #endif 00812 {NULL, NULL, NULL, NULL, NULL, NULL, 0} 00813 }; 00814 00815 /************************************************************************ 00816 * * 00817 * The main code driving the tests * 00818 * * 00819 ************************************************************************/ 00820 00821 static int 00822 launchTests(testDescPtr tst) { 00823 int res = 0, err = 0; 00824 size_t i; 00825 char *result; 00826 char *error; 00827 int mem; 00828 00829 if (tst == NULL) return(-1); 00830 if (tst->in != NULL) { 00831 glob_t globbuf; 00832 00833 globbuf.gl_offs = 0; 00834 glob(tst->in, GLOB_DOOFFS, NULL, &globbuf); 00835 for (i = 0;i < globbuf.gl_pathc;i++) { 00836 if (!checkTestFile(globbuf.gl_pathv[i])) 00837 continue; 00838 if (tst->suffix != NULL) { 00839 result = resultFilename(globbuf.gl_pathv[i], tst->out, 00840 tst->suffix); 00841 if (result == NULL) { 00842 fprintf(stderr, "Out of memory !\n"); 00843 fatalError(); 00844 } 00845 } else { 00846 result = NULL; 00847 } 00848 if (tst->err != NULL) { 00849 error = resultFilename(globbuf.gl_pathv[i], tst->out, 00850 tst->err); 00851 if (error == NULL) { 00852 fprintf(stderr, "Out of memory !\n"); 00853 fatalError(); 00854 } 00855 } else { 00856 error = NULL; 00857 } 00858 if ((result) &&(!checkTestFile(result))) { 00859 fprintf(stderr, "Missing result file %s\n", result); 00860 } else if ((error) &&(!checkTestFile(error))) { 00861 fprintf(stderr, "Missing error file %s\n", error); 00862 } else { 00863 mem = xmlMemUsed(); 00864 extraMemoryFromResolver = 0; 00865 testErrorsSize = 0; 00866 testErrors[0] = 0; 00867 res = tst->func(globbuf.gl_pathv[i], result, error, 00868 tst->options | XML_PARSE_COMPACT); 00869 xmlResetLastError(); 00870 if (res != 0) { 00871 fprintf(stderr, "File %s generated an error\n", 00872 globbuf.gl_pathv[i]); 00873 nb_errors++; 00874 err++; 00875 } 00876 else if (xmlMemUsed() != mem) { 00877 if ((xmlMemUsed() != mem) && 00878 (extraMemoryFromResolver == 0)) { 00879 fprintf(stderr, "File %s leaked %d bytes\n", 00880 globbuf.gl_pathv[i], xmlMemUsed() - mem); 00881 nb_leaks++; 00882 err++; 00883 } 00884 } 00885 testErrorsSize = 0; 00886 } 00887 if (result) 00888 free(result); 00889 if (error) 00890 free(error); 00891 } 00892 globfree(&globbuf); 00893 } else { 00894 testErrorsSize = 0; 00895 testErrors[0] = 0; 00896 extraMemoryFromResolver = 0; 00897 res = tst->func(NULL, NULL, NULL, tst->options); 00898 if (res != 0) { 00899 nb_errors++; 00900 err++; 00901 } 00902 } 00903 return(err); 00904 } 00905 00906 static int verbose = 0; 00907 static int tests_quiet = 0; 00908 00909 static int 00910 runtest(int i) { 00911 int ret = 0, res; 00912 int old_errors, old_tests, old_leaks; 00913 00914 old_errors = nb_errors; 00915 old_tests = nb_tests; 00916 old_leaks = nb_leaks; 00917 if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL)) 00918 printf("## %s\n", testDescriptions[i].desc); 00919 res = launchTests(&testDescriptions[i]); 00920 if (res != 0) 00921 ret++; 00922 if (verbose) { 00923 if ((nb_errors == old_errors) && (nb_leaks == old_leaks)) 00924 printf("Ran %d tests, no errors\n", nb_tests - old_tests); 00925 else 00926 printf("Ran %d tests, %d errors, %d leaks\n", 00927 nb_tests - old_tests, 00928 nb_errors - old_errors, 00929 nb_leaks - old_leaks); 00930 } 00931 return(ret); 00932 } 00933 00934 int 00935 main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) { 00936 int i, a, ret = 0; 00937 int subset = 0; 00938 00939 initializeLibxml2(); 00940 00941 for (a = 1; a < argc;a++) { 00942 if (!strcmp(argv[a], "-v")) 00943 verbose = 1; 00944 else if (!strcmp(argv[a], "-quiet")) 00945 tests_quiet = 1; 00946 else { 00947 for (i = 0; testDescriptions[i].func != NULL; i++) { 00948 if (strstr(testDescriptions[i].desc, argv[a])) { 00949 ret += runtest(i); 00950 subset++; 00951 } 00952 } 00953 } 00954 } 00955 if (subset == 0) { 00956 for (i = 0; testDescriptions[i].func != NULL; i++) { 00957 ret += runtest(i); 00958 } 00959 } 00960 if ((nb_errors == 0) && (nb_leaks == 0)) { 00961 ret = 0; 00962 printf("Total %d tests, no errors\n", 00963 nb_tests); 00964 } else { 00965 ret = 1; 00966 printf("Total %d tests, %d errors, %d leaks\n", 00967 nb_tests, nb_errors, nb_leaks); 00968 } 00969 xmlCleanupParser(); 00970 xmlMemoryDump(); 00971 00972 return(ret); 00973 } Generated on Fri May 25 2012 04:33:10 for ReactOS by
1.7.6.1
|