VirtualBox

source: vbox/trunk/src/libs/libxml2-2.13.2/testrecurse.c@ 105945

Last change on this file since 105945 was 105420, checked in by vboxsync, 5 months ago

libxml2-2.12.6: Applied and adjusted our libxml2 changes to 2.12.6. bugref:10730

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette