Annotation of embedaddon/libxml2/testrecurse.c, revision 1.1
1.1 ! misho 1: /*
! 2: * testrecurse.c: C program to run libxml2 regression tests checking entities
! 3: * recursions
! 4: *
! 5: * To compile on Unixes:
! 6: * cc -o testrecurse `xml2-config --cflags` testrecurse.c `xml2-config --libs` -lpthread
! 7: *
! 8: * See Copyright for the status of this software.
! 9: *
! 10: * daniel@veillard.com
! 11: */
! 12:
! 13: #ifdef HAVE_CONFIG_H
! 14: #include "libxml.h"
! 15: #else
! 16: #include <stdio.h>
! 17: #endif
! 18:
! 19: #if !defined(_WIN32) || defined(__CYGWIN__)
! 20: #include <unistd.h>
! 21: #endif
! 22: #include <string.h>
! 23: #include <sys/types.h>
! 24: #include <sys/stat.h>
! 25: #include <fcntl.h>
! 26:
! 27: #include <libxml/parser.h>
! 28: #include <libxml/tree.h>
! 29: #include <libxml/uri.h>
! 30: #ifdef LIBXML_READER_ENABLED
! 31: #include <libxml/xmlreader.h>
! 32: #endif
! 33:
! 34: /*
! 35: * O_BINARY is just for Windows compatibility - if it isn't defined
! 36: * on this system, avoid any compilation error
! 37: */
! 38: #ifdef O_BINARY
! 39: #define RD_FLAGS O_RDONLY | O_BINARY
! 40: #else
! 41: #define RD_FLAGS O_RDONLY
! 42: #endif
! 43:
! 44: typedef int (*functest) (const char *filename, const char *result,
! 45: const char *error, int options);
! 46:
! 47: typedef struct testDesc testDesc;
! 48: typedef testDesc *testDescPtr;
! 49: struct testDesc {
! 50: const char *desc; /* descripton of the test */
! 51: functest func; /* function implementing the test */
! 52: const char *in; /* glob to path for input files */
! 53: const char *out; /* output directory */
! 54: const char *suffix;/* suffix for output files */
! 55: const char *err; /* suffix for error output files */
! 56: int options; /* parser options for the test */
! 57: };
! 58:
! 59: static int checkTestFile(const char *filename);
! 60:
! 61:
! 62: #if defined(_WIN32) && !defined(__CYGWIN__)
! 63:
! 64: #include <windows.h>
! 65: #include <io.h>
! 66:
! 67: typedef struct
! 68: {
! 69: size_t gl_pathc; /* Count of paths matched so far */
! 70: char **gl_pathv; /* List of matched pathnames. */
! 71: size_t gl_offs; /* Slots to reserve in 'gl_pathv'. */
! 72: } glob_t;
! 73:
! 74: #define GLOB_DOOFFS 0
! 75: static int glob(const char *pattern, int flags,
! 76: int errfunc(const char *epath, int eerrno),
! 77: glob_t *pglob) {
! 78: glob_t *ret;
! 79: WIN32_FIND_DATA FindFileData;
! 80: HANDLE hFind;
! 81: unsigned int nb_paths = 0;
! 82: char directory[500];
! 83: int len;
! 84:
! 85: if ((pattern == NULL) || (pglob == NULL)) return(-1);
! 86:
! 87: strncpy(directory, pattern, 499);
! 88: for (len = strlen(directory);len >= 0;len--) {
! 89: if (directory[len] == '/') {
! 90: len++;
! 91: directory[len] = 0;
! 92: break;
! 93: }
! 94: }
! 95: if (len <= 0)
! 96: len = 0;
! 97:
! 98:
! 99: ret = pglob;
! 100: memset(ret, 0, sizeof(glob_t));
! 101:
! 102: hFind = FindFirstFileA(pattern, &FindFileData);
! 103: if (hFind == INVALID_HANDLE_VALUE)
! 104: return(0);
! 105: nb_paths = 20;
! 106: ret->gl_pathv = (char **) malloc(nb_paths * sizeof(char *));
! 107: if (ret->gl_pathv == NULL) {
! 108: FindClose(hFind);
! 109: return(-1);
! 110: }
! 111: strncpy(directory + len, FindFileData.cFileName, 499 - len);
! 112: ret->gl_pathv[ret->gl_pathc] = strdup(directory);
! 113: if (ret->gl_pathv[ret->gl_pathc] == NULL)
! 114: goto done;
! 115: ret->gl_pathc++;
! 116: while(FindNextFileA(hFind, &FindFileData)) {
! 117: if (FindFileData.cFileName[0] == '.')
! 118: continue;
! 119: if (ret->gl_pathc + 2 > nb_paths) {
! 120: char **tmp = realloc(ret->gl_pathv, nb_paths * 2 * sizeof(char *));
! 121: if (tmp == NULL)
! 122: break;
! 123: ret->gl_pathv = tmp;
! 124: nb_paths *= 2;
! 125: }
! 126: strncpy(directory + len, FindFileData.cFileName, 499 - len);
! 127: ret->gl_pathv[ret->gl_pathc] = strdup(directory);
! 128: if (ret->gl_pathv[ret->gl_pathc] == NULL)
! 129: break;
! 130: ret->gl_pathc++;
! 131: }
! 132: ret->gl_pathv[ret->gl_pathc] = NULL;
! 133:
! 134: done:
! 135: FindClose(hFind);
! 136: return(0);
! 137: }
! 138:
! 139:
! 140:
! 141: static void globfree(glob_t *pglob) {
! 142: unsigned int i;
! 143: if (pglob == NULL)
! 144: return;
! 145:
! 146: for (i = 0;i < pglob->gl_pathc;i++) {
! 147: if (pglob->gl_pathv[i] != NULL)
! 148: free(pglob->gl_pathv[i]);
! 149: }
! 150: }
! 151: #define vsnprintf _vsnprintf
! 152: #define snprintf _snprintf
! 153: #else
! 154: #include <glob.h>
! 155: #endif
! 156:
! 157: /************************************************************************
! 158: * *
! 159: * Huge document generator *
! 160: * *
! 161: ************************************************************************/
! 162:
! 163: #include <libxml/xmlIO.h>
! 164:
! 165:
! 166: static const char *start = "<!DOCTYPE foo [\
! 167: <!ENTITY f 'some internal data'> \
! 168: <!ENTITY e '&f;&f;'> \
! 169: <!ENTITY d '&e;&e;'> \
! 170: ]> \
! 171: <foo>";
! 172:
! 173: static const char *segment = " <bar>&e; &f; &d;</bar>\n";
! 174: static const char *finish = "</foo>";
! 175:
! 176: static int curseg = 0;
! 177: static const char *current;
! 178: static int rlen;
! 179:
! 180: /**
! 181: * hugeMatch:
! 182: * @URI: an URI to test
! 183: *
! 184: * Check for an huge: query
! 185: *
! 186: * Returns 1 if yes and 0 if another Input module should be used
! 187: */
! 188: static int
! 189: hugeMatch(const char * URI) {
! 190: if ((URI != NULL) && (!strncmp(URI, "huge:", 4)))
! 191: return(1);
! 192: return(0);
! 193: }
! 194:
! 195: /**
! 196: * hugeOpen:
! 197: * @URI: an URI to test
! 198: *
! 199: * Return a pointer to the huge: query handler, in this example simply
! 200: * the current pointer...
! 201: *
! 202: * Returns an Input context or NULL in case or error
! 203: */
! 204: static void *
! 205: hugeOpen(const char * URI) {
! 206: if ((URI == NULL) || (strncmp(URI, "huge:", 4)))
! 207: return(NULL);
! 208: rlen = strlen(start);
! 209: current = start;
! 210: return((void *) current);
! 211: }
! 212:
! 213: /**
! 214: * hugeClose:
! 215: * @context: the read context
! 216: *
! 217: * Close the huge: query handler
! 218: *
! 219: * Returns 0 or -1 in case of error
! 220: */
! 221: static int
! 222: hugeClose(void * context) {
! 223: if (context == NULL) return(-1);
! 224: return(0);
! 225: }
! 226:
! 227: #define MAX_NODES 1000000
! 228:
! 229: /**
! 230: * hugeRead:
! 231: * @context: the read context
! 232: * @buffer: where to store data
! 233: * @len: number of bytes to read
! 234: *
! 235: * Implement an huge: query read.
! 236: *
! 237: * Returns the number of bytes read or -1 in case of error
! 238: */
! 239: static int
! 240: hugeRead(void *context, char *buffer, int len)
! 241: {
! 242: if ((context == NULL) || (buffer == NULL) || (len < 0))
! 243: return (-1);
! 244:
! 245: if (len >= rlen) {
! 246: if (curseg >= MAX_NODES + 1) {
! 247: rlen = 0;
! 248: return(0);
! 249: }
! 250: len = rlen;
! 251: rlen = 0;
! 252: memcpy(buffer, current, len);
! 253: curseg ++;
! 254: if (curseg == MAX_NODES) {
! 255: fprintf(stderr, "\n");
! 256: rlen = strlen(finish);
! 257: current = finish;
! 258: } else {
! 259: if (curseg % (MAX_NODES / 10) == 0)
! 260: fprintf(stderr, ".");
! 261: rlen = strlen(segment);
! 262: current = segment;
! 263: }
! 264: } else {
! 265: memcpy(buffer, current, len);
! 266: rlen -= len;
! 267: current += len;
! 268: }
! 269: return (len);
! 270: }
! 271:
! 272: /************************************************************************
! 273: * *
! 274: * Libxml2 specific routines *
! 275: * *
! 276: ************************************************************************/
! 277:
! 278: static int nb_tests = 0;
! 279: static int nb_errors = 0;
! 280: static int nb_leaks = 0;
! 281: static int extraMemoryFromResolver = 0;
! 282:
! 283: static int
! 284: fatalError(void) {
! 285: fprintf(stderr, "Exitting tests on fatal error\n");
! 286: exit(1);
! 287: }
! 288:
! 289: /*
! 290: * We need to trap calls to the resolver to not account memory for the catalog
! 291: * which is shared to the current running test. We also don't want to have
! 292: * network downloads modifying tests.
! 293: */
! 294: static xmlParserInputPtr
! 295: testExternalEntityLoader(const char *URL, const char *ID,
! 296: xmlParserCtxtPtr ctxt) {
! 297: xmlParserInputPtr ret;
! 298:
! 299: if (checkTestFile(URL)) {
! 300: ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
! 301: } else {
! 302: int memused = xmlMemUsed();
! 303: ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
! 304: extraMemoryFromResolver += xmlMemUsed() - memused;
! 305: }
! 306:
! 307: return(ret);
! 308: }
! 309:
! 310: /*
! 311: * Trapping the error messages at the generic level to grab the equivalent of
! 312: * stderr messages on CLI tools.
! 313: */
! 314: static char testErrors[32769];
! 315: static int testErrorsSize = 0;
! 316:
! 317: static void XMLCDECL
! 318: channel(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
! 319: va_list args;
! 320: int res;
! 321:
! 322: if (testErrorsSize >= 32768)
! 323: return;
! 324: va_start(args, msg);
! 325: res = vsnprintf(&testErrors[testErrorsSize],
! 326: 32768 - testErrorsSize,
! 327: msg, args);
! 328: va_end(args);
! 329: if (testErrorsSize + res >= 32768) {
! 330: /* buffer is full */
! 331: testErrorsSize = 32768;
! 332: testErrors[testErrorsSize] = 0;
! 333: } else {
! 334: testErrorsSize += res;
! 335: }
! 336: testErrors[testErrorsSize] = 0;
! 337: }
! 338:
! 339: /**
! 340: * xmlParserPrintFileContext:
! 341: * @input: an xmlParserInputPtr input
! 342: *
! 343: * Displays current context within the input content for error tracking
! 344: */
! 345:
! 346: static void
! 347: xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
! 348: xmlGenericErrorFunc chanl, void *data ) {
! 349: const xmlChar *cur, *base;
! 350: unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */
! 351: xmlChar content[81]; /* space for 80 chars + line terminator */
! 352: xmlChar *ctnt;
! 353:
! 354: if (input == NULL) return;
! 355: cur = input->cur;
! 356: base = input->base;
! 357: /* skip backwards over any end-of-lines */
! 358: while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
! 359: cur--;
! 360: }
! 361: n = 0;
! 362: /* search backwards for beginning-of-line (to max buff size) */
! 363: while ((n++ < (sizeof(content)-1)) && (cur > base) &&
! 364: (*(cur) != '\n') && (*(cur) != '\r'))
! 365: cur--;
! 366: if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
! 367: /* calculate the error position in terms of the current position */
! 368: col = input->cur - cur;
! 369: /* search forward for end-of-line (to max buff size) */
! 370: n = 0;
! 371: ctnt = content;
! 372: /* copy selected text to our buffer */
! 373: while ((*cur != 0) && (*(cur) != '\n') &&
! 374: (*(cur) != '\r') && (n < sizeof(content)-1)) {
! 375: *ctnt++ = *cur++;
! 376: n++;
! 377: }
! 378: *ctnt = 0;
! 379: /* print out the selected text */
! 380: chanl(data ,"%s\n", content);
! 381: /* create blank line with problem pointer */
! 382: n = 0;
! 383: ctnt = content;
! 384: /* (leave buffer space for pointer + line terminator) */
! 385: while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
! 386: if (*(ctnt) != '\t')
! 387: *(ctnt) = ' ';
! 388: ctnt++;
! 389: }
! 390: *ctnt++ = '^';
! 391: *ctnt = 0;
! 392: chanl(data ,"%s\n", content);
! 393: }
! 394:
! 395: static void
! 396: testStructuredErrorHandler(void *ctx ATTRIBUTE_UNUSED, xmlErrorPtr err) {
! 397: char *file = NULL;
! 398: int line = 0;
! 399: int code = -1;
! 400: int domain;
! 401: void *data = NULL;
! 402: const char *str;
! 403: const xmlChar *name = NULL;
! 404: xmlNodePtr node;
! 405: xmlErrorLevel level;
! 406: xmlParserInputPtr input = NULL;
! 407: xmlParserInputPtr cur = NULL;
! 408: xmlParserCtxtPtr ctxt = NULL;
! 409:
! 410: if (err == NULL)
! 411: return;
! 412:
! 413: file = err->file;
! 414: line = err->line;
! 415: code = err->code;
! 416: domain = err->domain;
! 417: level = err->level;
! 418: node = err->node;
! 419: if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
! 420: (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
! 421: (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
! 422: ctxt = err->ctxt;
! 423: }
! 424: str = err->message;
! 425:
! 426: if (code == XML_ERR_OK)
! 427: return;
! 428:
! 429: if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
! 430: name = node->name;
! 431:
! 432: /*
! 433: * Maintain the compatibility with the legacy error handling
! 434: */
! 435: if (ctxt != NULL) {
! 436: input = ctxt->input;
! 437: if ((input != NULL) && (input->filename == NULL) &&
! 438: (ctxt->inputNr > 1)) {
! 439: cur = input;
! 440: input = ctxt->inputTab[ctxt->inputNr - 2];
! 441: }
! 442: if (input != NULL) {
! 443: if (input->filename)
! 444: channel(data, "%s:%d: ", input->filename, input->line);
! 445: else if ((line != 0) && (domain == XML_FROM_PARSER))
! 446: channel(data, "Entity: line %d: ", input->line);
! 447: }
! 448: } else {
! 449: if (file != NULL)
! 450: channel(data, "%s:%d: ", file, line);
! 451: else if ((line != 0) && (domain == XML_FROM_PARSER))
! 452: channel(data, "Entity: line %d: ", line);
! 453: }
! 454: if (name != NULL) {
! 455: channel(data, "element %s: ", name);
! 456: }
! 457: if (code == XML_ERR_OK)
! 458: return;
! 459: switch (domain) {
! 460: case XML_FROM_PARSER:
! 461: channel(data, "parser ");
! 462: break;
! 463: case XML_FROM_NAMESPACE:
! 464: channel(data, "namespace ");
! 465: break;
! 466: case XML_FROM_DTD:
! 467: case XML_FROM_VALID:
! 468: channel(data, "validity ");
! 469: break;
! 470: case XML_FROM_HTML:
! 471: channel(data, "HTML parser ");
! 472: break;
! 473: case XML_FROM_MEMORY:
! 474: channel(data, "memory ");
! 475: break;
! 476: case XML_FROM_OUTPUT:
! 477: channel(data, "output ");
! 478: break;
! 479: case XML_FROM_IO:
! 480: channel(data, "I/O ");
! 481: break;
! 482: case XML_FROM_XINCLUDE:
! 483: channel(data, "XInclude ");
! 484: break;
! 485: case XML_FROM_XPATH:
! 486: channel(data, "XPath ");
! 487: break;
! 488: case XML_FROM_XPOINTER:
! 489: channel(data, "parser ");
! 490: break;
! 491: case XML_FROM_REGEXP:
! 492: channel(data, "regexp ");
! 493: break;
! 494: case XML_FROM_MODULE:
! 495: channel(data, "module ");
! 496: break;
! 497: case XML_FROM_SCHEMASV:
! 498: channel(data, "Schemas validity ");
! 499: break;
! 500: case XML_FROM_SCHEMASP:
! 501: channel(data, "Schemas parser ");
! 502: break;
! 503: case XML_FROM_RELAXNGP:
! 504: channel(data, "Relax-NG parser ");
! 505: break;
! 506: case XML_FROM_RELAXNGV:
! 507: channel(data, "Relax-NG validity ");
! 508: break;
! 509: case XML_FROM_CATALOG:
! 510: channel(data, "Catalog ");
! 511: break;
! 512: case XML_FROM_C14N:
! 513: channel(data, "C14N ");
! 514: break;
! 515: case XML_FROM_XSLT:
! 516: channel(data, "XSLT ");
! 517: break;
! 518: default:
! 519: break;
! 520: }
! 521: if (code == XML_ERR_OK)
! 522: return;
! 523: switch (level) {
! 524: case XML_ERR_NONE:
! 525: channel(data, ": ");
! 526: break;
! 527: case XML_ERR_WARNING:
! 528: channel(data, "warning : ");
! 529: break;
! 530: case XML_ERR_ERROR:
! 531: channel(data, "error : ");
! 532: break;
! 533: case XML_ERR_FATAL:
! 534: channel(data, "error : ");
! 535: break;
! 536: }
! 537: if (code == XML_ERR_OK)
! 538: return;
! 539: if (str != NULL) {
! 540: int len;
! 541: len = xmlStrlen((const xmlChar *)str);
! 542: if ((len > 0) && (str[len - 1] != '\n'))
! 543: channel(data, "%s\n", str);
! 544: else
! 545: channel(data, "%s", str);
! 546: } else {
! 547: channel(data, "%s\n", "out of memory error");
! 548: }
! 549: if (code == XML_ERR_OK)
! 550: return;
! 551:
! 552: if (ctxt != NULL) {
! 553: xmlParserPrintFileContextInternal(input, channel, data);
! 554: if (cur != NULL) {
! 555: if (cur->filename)
! 556: channel(data, "%s:%d: \n", cur->filename, cur->line);
! 557: else if ((line != 0) && (domain == XML_FROM_PARSER))
! 558: channel(data, "Entity: line %d: \n", cur->line);
! 559: xmlParserPrintFileContextInternal(cur, channel, data);
! 560: }
! 561: }
! 562: if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
! 563: (err->int1 < 100) &&
! 564: (err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
! 565: xmlChar buf[150];
! 566: int i;
! 567:
! 568: channel(data, "%s\n", err->str1);
! 569: for (i=0;i < err->int1;i++)
! 570: buf[i] = ' ';
! 571: buf[i++] = '^';
! 572: buf[i] = 0;
! 573: channel(data, "%s\n", buf);
! 574: }
! 575: }
! 576:
! 577: static void
! 578: initializeLibxml2(void) {
! 579: xmlGetWarningsDefaultValue = 0;
! 580: xmlPedanticParserDefault(0);
! 581:
! 582: xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
! 583: xmlInitParser();
! 584: xmlSetExternalEntityLoader(testExternalEntityLoader);
! 585: xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
! 586: /*
! 587: * register the new I/O handlers
! 588: */
! 589: if (xmlRegisterInputCallbacks(hugeMatch, hugeOpen,
! 590: hugeRead, hugeClose) < 0) {
! 591: fprintf(stderr, "failed to register Huge handler\n");
! 592: exit(1);
! 593: }
! 594: }
! 595:
! 596: /************************************************************************
! 597: * *
! 598: * File name and path utilities *
! 599: * *
! 600: ************************************************************************/
! 601:
! 602: static const char *baseFilename(const char *filename) {
! 603: const char *cur;
! 604: if (filename == NULL)
! 605: return(NULL);
! 606: cur = &filename[strlen(filename)];
! 607: while ((cur > filename) && (*cur != '/'))
! 608: cur--;
! 609: if (*cur == '/')
! 610: return(cur + 1);
! 611: return(cur);
! 612: }
! 613:
! 614: static char *resultFilename(const char *filename, const char *out,
! 615: const char *suffix) {
! 616: const char *base;
! 617: char res[500];
! 618: char suffixbuff[500];
! 619:
! 620: /*************
! 621: if ((filename[0] == 't') && (filename[1] == 'e') &&
! 622: (filename[2] == 's') && (filename[3] == 't') &&
! 623: (filename[4] == '/'))
! 624: filename = &filename[5];
! 625: *************/
! 626:
! 627: base = baseFilename(filename);
! 628: if (suffix == NULL)
! 629: suffix = ".tmp";
! 630: if (out == NULL)
! 631: out = "";
! 632:
! 633: strncpy(suffixbuff,suffix,499);
! 634: #ifdef VMS
! 635: if(strstr(base,".") && suffixbuff[0]=='.')
! 636: suffixbuff[0]='_';
! 637: #endif
! 638:
! 639: snprintf(res, 499, "%s%s%s", out, base, suffixbuff);
! 640: res[499] = 0;
! 641: return(strdup(res));
! 642: }
! 643:
! 644: static int checkTestFile(const char *filename) {
! 645: struct stat buf;
! 646:
! 647: if (stat(filename, &buf) == -1)
! 648: return(0);
! 649:
! 650: #if defined(_WIN32) && !defined(__CYGWIN__)
! 651: if (!(buf.st_mode & _S_IFREG))
! 652: return(0);
! 653: #else
! 654: if (!S_ISREG(buf.st_mode))
! 655: return(0);
! 656: #endif
! 657:
! 658: return(1);
! 659: }
! 660:
! 661:
! 662:
! 663: /************************************************************************
! 664: * *
! 665: * Test to detect or not recursive entities *
! 666: * *
! 667: ************************************************************************/
! 668: /**
! 669: * recursiveDetectTest:
! 670: * @filename: the file to parse
! 671: * @result: the file with expected result
! 672: * @err: the file with error messages: unused
! 673: *
! 674: * Parse a file loading DTD and replacing entities check it fails for
! 675: * lol cases
! 676: *
! 677: * Returns 0 in case of success, an error code otherwise
! 678: */
! 679: static int
! 680: recursiveDetectTest(const char *filename,
! 681: const char *result ATTRIBUTE_UNUSED,
! 682: const char *err ATTRIBUTE_UNUSED,
! 683: int options ATTRIBUTE_UNUSED) {
! 684: xmlDocPtr doc;
! 685: xmlParserCtxtPtr ctxt;
! 686: int res = 0;
! 687: int mem;
! 688:
! 689: nb_tests++;
! 690:
! 691: ctxt = xmlNewParserCtxt();
! 692: mem = xmlMemUsed();
! 693: /*
! 694: * base of the test, parse with the old API
! 695: */
! 696: doc = xmlCtxtReadFile(ctxt, filename, NULL,
! 697: XML_PARSE_NOENT | XML_PARSE_DTDLOAD);
! 698: if ((doc != NULL) || (ctxt->lastError.code != XML_ERR_ENTITY_LOOP)) {
! 699: fprintf(stderr, "Failed to detect recursion in %s\n", filename);
! 700: xmlFreeParserCtxt(ctxt);
! 701: xmlFreeDoc(doc);
! 702: return(1);
! 703: }
! 704: xmlFreeParserCtxt(ctxt);
! 705:
! 706: return(res);
! 707: }
! 708:
! 709: /**
! 710: * notRecursiveDetectTest:
! 711: * @filename: the file to parse
! 712: * @result: the file with expected result
! 713: * @err: the file with error messages: unused
! 714: *
! 715: * Parse a file loading DTD and replacing entities check it works for
! 716: * good cases
! 717: *
! 718: * Returns 0 in case of success, an error code otherwise
! 719: */
! 720: static int
! 721: notRecursiveDetectTest(const char *filename,
! 722: const char *result ATTRIBUTE_UNUSED,
! 723: const char *err ATTRIBUTE_UNUSED,
! 724: int options ATTRIBUTE_UNUSED) {
! 725: xmlDocPtr doc;
! 726: xmlParserCtxtPtr ctxt;
! 727: int res = 0;
! 728: int mem;
! 729:
! 730: nb_tests++;
! 731:
! 732: ctxt = xmlNewParserCtxt();
! 733: mem = xmlMemUsed();
! 734: /*
! 735: * base of the test, parse with the old API
! 736: */
! 737: doc = xmlCtxtReadFile(ctxt, filename, NULL,
! 738: XML_PARSE_NOENT | XML_PARSE_DTDLOAD);
! 739: if (doc == NULL) {
! 740: fprintf(stderr, "Failed to parse correct file %s\n", filename);
! 741: xmlFreeParserCtxt(ctxt);
! 742: return(1);
! 743: }
! 744: xmlFreeDoc(doc);
! 745: xmlFreeParserCtxt(ctxt);
! 746:
! 747: return(res);
! 748: }
! 749:
! 750: #ifdef LIBXML_READER_ENABLED
! 751: /**
! 752: * notRecursiveHugeTest:
! 753: * @filename: the file to parse
! 754: * @result: the file with expected result
! 755: * @err: the file with error messages: unused
! 756: *
! 757: * Parse a memory generated file
! 758: * good cases
! 759: *
! 760: * Returns 0 in case of success, an error code otherwise
! 761: */
! 762: static int
! 763: notRecursiveHugeTest(const char *filename ATTRIBUTE_UNUSED,
! 764: const char *result ATTRIBUTE_UNUSED,
! 765: const char *err ATTRIBUTE_UNUSED,
! 766: int options ATTRIBUTE_UNUSED) {
! 767: xmlTextReaderPtr reader;
! 768: int res = 0;
! 769: int ret;
! 770:
! 771: nb_tests++;
! 772:
! 773: reader = xmlReaderForFile("huge:test" , NULL,
! 774: XML_PARSE_NOENT | XML_PARSE_DTDLOAD);
! 775: if (reader == NULL) {
! 776: fprintf(stderr, "Failed to open huge:test\n");
! 777: return(1);
! 778: }
! 779: ret = xmlTextReaderRead(reader);
! 780: while (ret == 1) {
! 781: ret = xmlTextReaderRead(reader);
! 782: }
! 783: if (ret != 0) {
! 784: fprintf(stderr, "Failed to parser huge:test with entities\n");
! 785: res = 1;
! 786: }
! 787: xmlFreeTextReader(reader);
! 788:
! 789: return(res);
! 790: }
! 791: #endif
! 792:
! 793: /************************************************************************
! 794: * *
! 795: * Tests Descriptions *
! 796: * *
! 797: ************************************************************************/
! 798:
! 799: static
! 800: testDesc testDescriptions[] = {
! 801: { "Parsing recursive test cases" ,
! 802: recursiveDetectTest, "./test/recurse/lol*.xml", NULL, NULL, NULL,
! 803: 0 },
! 804: { "Parsing non-recursive test cases" ,
! 805: notRecursiveDetectTest, "./test/recurse/good*.xml", NULL, NULL, NULL,
! 806: 0 },
! 807: #ifdef LIBXML_READER_ENABLED
! 808: { "Parsing non-recursive huge case" ,
! 809: notRecursiveHugeTest, NULL, NULL, NULL, NULL,
! 810: 0 },
! 811: #endif
! 812: {NULL, NULL, NULL, NULL, NULL, NULL, 0}
! 813: };
! 814:
! 815: /************************************************************************
! 816: * *
! 817: * The main code driving the tests *
! 818: * *
! 819: ************************************************************************/
! 820:
! 821: static int
! 822: launchTests(testDescPtr tst) {
! 823: int res = 0, err = 0;
! 824: size_t i;
! 825: char *result;
! 826: char *error;
! 827: int mem;
! 828:
! 829: if (tst == NULL) return(-1);
! 830: if (tst->in != NULL) {
! 831: glob_t globbuf;
! 832:
! 833: globbuf.gl_offs = 0;
! 834: glob(tst->in, GLOB_DOOFFS, NULL, &globbuf);
! 835: for (i = 0;i < globbuf.gl_pathc;i++) {
! 836: if (!checkTestFile(globbuf.gl_pathv[i]))
! 837: continue;
! 838: if (tst->suffix != NULL) {
! 839: result = resultFilename(globbuf.gl_pathv[i], tst->out,
! 840: tst->suffix);
! 841: if (result == NULL) {
! 842: fprintf(stderr, "Out of memory !\n");
! 843: fatalError();
! 844: }
! 845: } else {
! 846: result = NULL;
! 847: }
! 848: if (tst->err != NULL) {
! 849: error = resultFilename(globbuf.gl_pathv[i], tst->out,
! 850: tst->err);
! 851: if (error == NULL) {
! 852: fprintf(stderr, "Out of memory !\n");
! 853: fatalError();
! 854: }
! 855: } else {
! 856: error = NULL;
! 857: }
! 858: if ((result) &&(!checkTestFile(result))) {
! 859: fprintf(stderr, "Missing result file %s\n", result);
! 860: } else if ((error) &&(!checkTestFile(error))) {
! 861: fprintf(stderr, "Missing error file %s\n", error);
! 862: } else {
! 863: mem = xmlMemUsed();
! 864: extraMemoryFromResolver = 0;
! 865: testErrorsSize = 0;
! 866: testErrors[0] = 0;
! 867: res = tst->func(globbuf.gl_pathv[i], result, error,
! 868: tst->options | XML_PARSE_COMPACT);
! 869: xmlResetLastError();
! 870: if (res != 0) {
! 871: fprintf(stderr, "File %s generated an error\n",
! 872: globbuf.gl_pathv[i]);
! 873: nb_errors++;
! 874: err++;
! 875: }
! 876: else if (xmlMemUsed() != mem) {
! 877: if ((xmlMemUsed() != mem) &&
! 878: (extraMemoryFromResolver == 0)) {
! 879: fprintf(stderr, "File %s leaked %d bytes\n",
! 880: globbuf.gl_pathv[i], xmlMemUsed() - mem);
! 881: nb_leaks++;
! 882: err++;
! 883: }
! 884: }
! 885: testErrorsSize = 0;
! 886: }
! 887: if (result)
! 888: free(result);
! 889: if (error)
! 890: free(error);
! 891: }
! 892: globfree(&globbuf);
! 893: } else {
! 894: testErrorsSize = 0;
! 895: testErrors[0] = 0;
! 896: extraMemoryFromResolver = 0;
! 897: res = tst->func(NULL, NULL, NULL, tst->options);
! 898: if (res != 0) {
! 899: nb_errors++;
! 900: err++;
! 901: }
! 902: }
! 903: return(err);
! 904: }
! 905:
! 906: static int verbose = 0;
! 907: static int tests_quiet = 0;
! 908:
! 909: static int
! 910: runtest(int i) {
! 911: int ret = 0, res;
! 912: int old_errors, old_tests, old_leaks;
! 913:
! 914: old_errors = nb_errors;
! 915: old_tests = nb_tests;
! 916: old_leaks = nb_leaks;
! 917: if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
! 918: printf("## %s\n", testDescriptions[i].desc);
! 919: res = launchTests(&testDescriptions[i]);
! 920: if (res != 0)
! 921: ret++;
! 922: if (verbose) {
! 923: if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
! 924: printf("Ran %d tests, no errors\n", nb_tests - old_tests);
! 925: else
! 926: printf("Ran %d tests, %d errors, %d leaks\n",
! 927: nb_tests - old_tests,
! 928: nb_errors - old_errors,
! 929: nb_leaks - old_leaks);
! 930: }
! 931: return(ret);
! 932: }
! 933:
! 934: int
! 935: main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
! 936: int i, a, ret = 0;
! 937: int subset = 0;
! 938:
! 939: initializeLibxml2();
! 940:
! 941: for (a = 1; a < argc;a++) {
! 942: if (!strcmp(argv[a], "-v"))
! 943: verbose = 1;
! 944: else if (!strcmp(argv[a], "-quiet"))
! 945: tests_quiet = 1;
! 946: else {
! 947: for (i = 0; testDescriptions[i].func != NULL; i++) {
! 948: if (strstr(testDescriptions[i].desc, argv[a])) {
! 949: ret += runtest(i);
! 950: subset++;
! 951: }
! 952: }
! 953: }
! 954: }
! 955: if (subset == 0) {
! 956: for (i = 0; testDescriptions[i].func != NULL; i++) {
! 957: ret += runtest(i);
! 958: }
! 959: }
! 960: if ((nb_errors == 0) && (nb_leaks == 0)) {
! 961: ret = 0;
! 962: printf("Total %d tests, no errors\n",
! 963: nb_tests);
! 964: } else {
! 965: ret = 1;
! 966: printf("Total %d tests, %d errors, %d leaks\n",
! 967: nb_tests, nb_errors, nb_leaks);
! 968: }
! 969: xmlCleanupParser();
! 970: xmlMemoryDump();
! 971:
! 972: return(ret);
! 973: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>