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