blob: 380a923f96d2ea867c45786b234a369685fa8012 [file] [log] [blame]
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001/*
2 * runtest.c: C program to run libxml2 regression tests without
3 * requiring make or Python, and reducing platform dependancies
4 * to a strict minimum.
5 *
6 * See Copyright for the status of this software.
7 *
8 * daniel@veillard.com
9 */
10
11#include <unistd.h>
12#include <string.h>
13#include <stdio.h>
14#include <glob.h>
15#include <sys/types.h>
16#include <sys/stat.h>
17#include <fcntl.h>
18#include <unistd.h>
19
20#include <libxml/parser.h>
21#include <libxml/tree.h>
Daniel Veillardc111c152005-06-27 08:22:10 +000022#ifdef LIBXML_READER_ENABLED
23#include <libxml/xmlreader.h>
24#endif
Daniel Veillard1b75c3b2005-06-26 21:49:08 +000025
Daniel Veillardfd110d22005-06-27 00:02:02 +000026typedef int (*functest) (const char *filename, const char *result,
Daniel Veillardc111c152005-06-27 08:22:10 +000027 const char *error, int options);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +000028
29typedef struct testDesc testDesc;
30typedef testDesc *testDescPtr;
31struct testDesc {
32 const char *desc; /* descripton of the test */
33 functest func; /* function implementing the test */
34 const char *in; /* glob to path for input files */
35 const char *out; /* output directory */
36 const char *suffix;/* suffix for output files */
Daniel Veillardfd110d22005-06-27 00:02:02 +000037 const char *err; /* suffix for error output files */
Daniel Veillardc111c152005-06-27 08:22:10 +000038 int options; /* parser options for the test */
Daniel Veillard1b75c3b2005-06-26 21:49:08 +000039};
40
41static int checkTestFile(const char *filename);
42/************************************************************************
43 * *
44 * Libxml2 specific routines *
45 * *
46 ************************************************************************/
47
48static long libxmlMemoryAllocatedBase = 0;
49static int extraMemoryFromResolver = 0;
50
51static int
52fatalError(void) {
53 fprintf(stderr, "Exitting tests on fatal error\n");
54 exit(1);
55}
56
57/*
58 * We need to trap calls to the resolver to not account memory for the catalog
59 * which is shared to the current running test. We also don't want to have
60 * network downloads modifying tests.
61 */
62static xmlParserInputPtr
63testExternalEntityLoader(const char *URL, const char *ID,
64 xmlParserCtxtPtr ctxt) {
65 xmlParserInputPtr ret;
66
67 if (checkTestFile(URL)) {
68 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
69 } else {
70 int memused = xmlMemUsed();
71 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
72 extraMemoryFromResolver += xmlMemUsed() - memused;
73 }
74
75 return(ret);
76}
77
Daniel Veillardfd110d22005-06-27 00:02:02 +000078/*
79 * Trapping the error messages at the generic level to grab the equivalent of
80 * stderr messages on CLI tools.
81 */
82static char testErrors[32769];
83static int testErrorsSize = 0;
84
85static void
Daniel Veillardc111c152005-06-27 08:22:10 +000086testErrorHandler(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
Daniel Veillardfd110d22005-06-27 00:02:02 +000087 va_list args;
88 int res;
89
90 if (testErrorsSize >= 32768)
91 return;
92 va_start(args, msg);
93 res = vsnprintf(&testErrors[testErrorsSize],
94 32768 - testErrorsSize,
95 msg, args);
96 va_end(args);
97 if (testErrorsSize + res >= 32768) {
98 /* buffer is full */
99 testErrorsSize = 32768;
100 testErrors[testErrorsSize] = 0;
101 } else {
102 testErrorsSize += res;
103 }
104 testErrors[testErrorsSize] = 0;
105}
106
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000107static void
108initializeLibxml2(void) {
109 xmlGetWarningsDefaultValue = 0;
110 xmlPedanticParserDefault(0);
111
112 xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
113 xmlInitParser();
114 xmlSetExternalEntityLoader(testExternalEntityLoader);
Daniel Veillardfd110d22005-06-27 00:02:02 +0000115 xmlSetGenericErrorFunc(NULL, testErrorHandler);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000116 libxmlMemoryAllocatedBase = xmlMemUsed();
117}
118
119
120/************************************************************************
121 * *
122 * File name and path utilities *
123 * *
124 ************************************************************************/
125
126static const char *baseFilename(const char *filename) {
127 const char *cur;
128 if (filename == NULL)
129 return(NULL);
130 cur = &filename[strlen(filename)];
131 while ((cur > filename) && (*cur != '/'))
132 cur--;
133 if (*cur == '/')
134 return(cur + 1);
135 return(cur);
136}
137
138static char *resultFilename(const char *filename, const char *out,
139 const char *suffix) {
140 const char *base;
141 char res[500];
142
143/*************
144 if ((filename[0] == 't') && (filename[1] == 'e') &&
145 (filename[2] == 's') && (filename[3] == 't') &&
146 (filename[4] == '/'))
147 filename = &filename[5];
148 *************/
149
150 base = baseFilename(filename);
151 if (suffix == NULL)
152 suffix = ".tmp";
153 if (out == NULL)
154 out = "";
155 snprintf(res, 499, "%s%s%s", out, base, suffix);
156 res[499] = 0;
157 return(strdup(res));
158}
159
160static int checkTestFile(const char *filename) {
161 struct stat buf;
162
163 if (stat(filename, &buf) == -1)
164 return(0);
165
166 if (!S_ISREG(buf.st_mode))
167 return(0);
168
169 return(1);
170}
171
172static int compareFiles(const char *r1, const char *r2) {
173 int res1, res2;
174 int fd1, fd2;
175 char bytes1[4096];
176 char bytes2[4096];
177
178 fd1 = open(r1, O_RDONLY);
179 if (fd1 < 0)
180 return(-1);
181 fd2 = open(r2, O_RDONLY);
182 if (fd2 < 0) {
183 close(fd1);
184 return(-1);
185 }
186 while (1) {
187 res1 = read(fd1, bytes1, 4096);
188 res2 = read(fd2, bytes2, 4096);
189 if (res1 != res2) {
190 close(fd1);
191 close(fd2);
192 return(1);
193 }
194 if (res1 == 0)
195 break;
196 if (memcmp(bytes1, bytes2, res1) != 0) {
197 close(fd1);
198 close(fd2);
199 return(1);
200 }
201 }
202 close(fd1);
203 close(fd2);
204 return(0);
205}
206
Daniel Veillardfd110d22005-06-27 00:02:02 +0000207static int compareFileMem(const char *filename, const char *mem, int size) {
208 int res;
209 int fd;
210 char bytes[4096];
211 int idx = 0;
212 struct stat info;
213
214 if (stat(filename, &info) < 0)
215 return(-1);
216 if (info.st_size != size)
217 return(-1);
218 fd = open(filename, O_RDONLY);
219 if (fd < 0)
220 return(-1);
221 while (idx < size) {
222 res = read(fd, bytes, 4096);
223 if (res <= 0)
224 break;
225 if (res + idx > size)
226 break;
227 if (memcmp(bytes, &mem[idx], res) != 0) {
228 close(fd);
229 return(1);
230 }
231 idx += res;
232 }
233 close(fd);
234 return(idx != size);
235}
236
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000237static int loadMem(const char *filename, const char **mem, int *size) {
238 int fd, res;
239 struct stat info;
240 char *base;
241 int siz = 0;
242 if (stat(filename, &info) < 0)
243 return(-1);
244 base = malloc(info.st_size + 1);
245 if (base == NULL)
246 return(-1);
247 if ((fd = open(filename, O_RDONLY)) < 0) {
248 free(base);
249 return(-1);
250 }
251 while ((res = read(fd, &base[siz], info.st_size - siz)) > 0) {
252 siz += res;
253 }
254 close(fd);
255 if (siz != info.st_size) {
256 free(base);
257 return(-1);
258 }
259 base[siz] = 0;
260 *mem = base;
261 *size = siz;
262 return(0);
263}
264
265static int unloadMem(const char *mem) {
266 free((char *)mem);
267 return(0);
268}
269
270/************************************************************************
271 * *
272 * Tests implementations *
273 * *
274 ************************************************************************/
275
276/**
277 * oldParseTest:
278 * @filename: the file to parse
279 * @result: the file with expected result
Daniel Veillardfd110d22005-06-27 00:02:02 +0000280 * @err: the file with error messages: unused
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000281 *
282 * Parse a file using the old xmlParseFile API, then serialize back
283 * reparse the result and serialize again, then check for deviation
284 * in serialization.
285 *
286 * Returns 0 in case of success, an error code otherwise
287 */
288static int
Daniel Veillardc111c152005-06-27 08:22:10 +0000289oldParseTest(const char *filename, const char *result,
290 const char *err ATTRIBUTE_UNUSED,
291 int options ATTRIBUTE_UNUSED) {
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000292 xmlDocPtr doc;
293 char *temp;
294 int res = 0;
295
296 /*
297 * base of the test, parse with the old API
298 */
299 doc = xmlParseFile(filename);
300 if (doc == NULL)
301 return(1);
302 temp = resultFilename(filename, "", ".res");
303 if (temp == NULL) {
304 fprintf(stderr, "Out of memory\n");
305 fatalError();
306 }
307 xmlSaveFile(temp, doc);
308 if (compareFiles(temp, result)) {
309 res = 1;
310 }
311 xmlFreeDoc(doc);
312
313 /*
314 * Parse the saved result to make sure the round trip is okay
315 */
316 doc = xmlParseFile(temp);
317 if (doc == NULL)
318 return(1);
319 xmlSaveFile(temp, doc);
320 if (compareFiles(temp, result)) {
321 res = 1;
322 }
323 xmlFreeDoc(doc);
324
325 unlink(temp);
326 free(temp);
327 return(res);
328}
329
330/**
331 * memParseTest:
332 * @filename: the file to parse
333 * @result: the file with expected result
Daniel Veillardfd110d22005-06-27 00:02:02 +0000334 * @err: the file with error messages: unused
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000335 *
336 * Parse a file using the old xmlReadMemory API, then serialize back
337 * reparse the result and serialize again, then check for deviation
338 * in serialization.
339 *
340 * Returns 0 in case of success, an error code otherwise
341 */
342static int
Daniel Veillardc111c152005-06-27 08:22:10 +0000343memParseTest(const char *filename, const char *result,
344 const char *err ATTRIBUTE_UNUSED,
345 int options ATTRIBUTE_UNUSED) {
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000346 xmlDocPtr doc;
347 const char *base;
Daniel Veillardfd110d22005-06-27 00:02:02 +0000348 int size, res;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000349
350 /*
351 * load and parse the memory
352 */
353 if (loadMem(filename, &base, &size) != 0) {
354 fprintf(stderr, "Failed to load %s\n", filename);
355 return(-1);
356 }
357
358 doc = xmlReadMemory(base, size, filename, NULL, 0);
359 unloadMem(base);
360 if (doc == NULL) {
361 return(1);
362 }
Daniel Veillardfd110d22005-06-27 00:02:02 +0000363 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000364 xmlFreeDoc(doc);
Daniel Veillardfd110d22005-06-27 00:02:02 +0000365 res = compareFileMem(result, base, size);
366 if ((base == NULL) || (res != 0)) {
367 if (base != NULL)
368 xmlFree((char *)base);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000369 fprintf(stderr, "Result for %s failed\n", filename);
370 return(-1);
371 }
Daniel Veillardfd110d22005-06-27 00:02:02 +0000372 xmlFree((char *)base);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000373 return(0);
374}
375
376/**
377 * noentParseTest:
378 * @filename: the file to parse
379 * @result: the file with expected result
Daniel Veillardfd110d22005-06-27 00:02:02 +0000380 * @err: the file with error messages: unused
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000381 *
382 * Parse a file with entity resolution, then serialize back
383 * reparse the result and serialize again, then check for deviation
384 * in serialization.
385 *
386 * Returns 0 in case of success, an error code otherwise
387 */
388static int
Daniel Veillardc111c152005-06-27 08:22:10 +0000389noentParseTest(const char *filename, const char *result,
390 const char *err ATTRIBUTE_UNUSED,
391 int options ATTRIBUTE_UNUSED) {
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000392 xmlDocPtr doc;
393 char *temp;
394 int res = 0;
395
396 /*
397 * base of the test, parse with the old API
398 */
399 doc = xmlReadFile(filename, NULL, XML_PARSE_NOENT);
400 if (doc == NULL)
401 return(1);
402 temp = resultFilename(filename, "", ".res");
403 if (temp == NULL) {
404 fprintf(stderr, "Out of memory\n");
405 fatalError();
406 }
407 xmlSaveFile(temp, doc);
408 if (compareFiles(temp, result)) {
409 res = 1;
410 }
411 xmlFreeDoc(doc);
412
413 /*
414 * Parse the saved result to make sure the round trip is okay
415 */
416 doc = xmlReadFile(filename, NULL, XML_PARSE_NOENT);
417 if (doc == NULL)
418 return(1);
419 xmlSaveFile(temp, doc);
420 if (compareFiles(temp, result)) {
421 res = 1;
422 }
423 xmlFreeDoc(doc);
424
425 unlink(temp);
426 free(temp);
427 return(res);
428}
429
Daniel Veillardfd110d22005-06-27 00:02:02 +0000430/**
Daniel Veillardc111c152005-06-27 08:22:10 +0000431 * errParseTest:
Daniel Veillardfd110d22005-06-27 00:02:02 +0000432 * @filename: the file to parse
433 * @result: the file with expected result
434 * @err: the file with error messages
435 *
436 * Parse a file using the xmlReadFile API and check for errors.
437 *
438 * Returns 0 in case of success, an error code otherwise
439 */
440static int
Daniel Veillardc111c152005-06-27 08:22:10 +0000441errParseTest(const char *filename, const char *result, const char *err,
442 int options ATTRIBUTE_UNUSED) {
Daniel Veillardfd110d22005-06-27 00:02:02 +0000443 xmlDocPtr doc;
444 const char *base;
445 int size, res;
446
447 xmlGetWarningsDefaultValue = 1;
448 doc = xmlReadFile(filename, NULL, 0);
449 if (doc == NULL) {
450 base = "";
451 size = 0;
452 } else {
453 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
454 }
455 xmlGetWarningsDefaultValue = 0;
456 res = compareFileMem(result, base, size);
457 if (doc != NULL) {
458 if (base != NULL)
459 xmlFree((char *)base);
460 xmlFreeDoc(doc);
461 }
462 if (res != 0) {
463 fprintf(stderr, "Result for %s failed\n", filename);
464 return(-1);
465 }
466 res = compareFileMem(err, testErrors, testErrorsSize);
467 if (res != 0) {
468 fprintf(stderr, "Error for %s failed\n", filename);
469 return(-1);
470 }
471
472 return(0);
473}
474
Daniel Veillardc111c152005-06-27 08:22:10 +0000475#ifdef LIBXML_READER_ENABLED
476static void processNode(FILE *out, xmlTextReaderPtr reader) {
477 const xmlChar *name, *value;
478 int type, empty;
479
480 type = xmlTextReaderNodeType(reader);
481 empty = xmlTextReaderIsEmptyElement(reader);
482
483 name = xmlTextReaderConstName(reader);
484 if (name == NULL)
485 name = BAD_CAST "--";
486
487 value = xmlTextReaderConstValue(reader);
488
489
490 fprintf(out, "%d %d %s %d %d",
491 xmlTextReaderDepth(reader),
492 type,
493 name,
494 empty,
495 xmlTextReaderHasValue(reader));
496 if (value == NULL)
497 fprintf(out, "\n");
498 else {
499 fprintf(out, " %s\n", value);
500 }
501#if 0
502#ifdef LIBXML_PATTERN_ENABLED
503 if (patternc) {
504 xmlChar *path = NULL;
505 int match = -1;
506
507 if (type == XML_READER_TYPE_ELEMENT) {
508 /* do the check only on element start */
509 match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader));
510
511 if (match) {
512 path = xmlGetNodePath(xmlTextReaderCurrentNode(reader));
513 fprintf(out, "Node %s matches pattern %s\n", path, pattern);
514 }
515 }
516 if (patstream != NULL) {
517 int ret;
518
519 if (type == XML_READER_TYPE_ELEMENT) {
520 ret = xmlStreamPush(patstream,
521 xmlTextReaderConstLocalName(reader),
522 xmlTextReaderConstNamespaceUri(reader));
523 if (ret < 0) {
524 fprintf(stderr, "xmlStreamPush() failure\n");
525 xmlFreeStreamCtxt(patstream);
526 patstream = NULL;
527 } else if (ret != match) {
528 if (path == NULL) {
529 path = xmlGetNodePath(
530 xmlTextReaderCurrentNode(reader));
531 }
532 fprintf(stderr,
533 "xmlPatternMatch and xmlStreamPush disagree\n");
534 fprintf(stderr,
535 " pattern %s node %s\n",
536 pattern, path);
537 }
538
539
540 }
541 if ((type == XML_READER_TYPE_END_ELEMENT) ||
542 ((type == XML_READER_TYPE_ELEMENT) && (empty))) {
543 ret = xmlStreamPop(patstream);
544 if (ret < 0) {
545 fprintf(stderr, "xmlStreamPop() failure\n");
546 xmlFreeStreamCtxt(patstream);
547 patstream = NULL;
548 }
549 }
550 }
551 if (path != NULL)
552 xmlFree(path);
553 }
554#endif
555#endif
556}
557/**
558 * streamParseTest:
559 * @filename: the file to parse
560 * @result: the file with expected result
561 * @err: the file with error messages
562 *
563 * Parse a file using the reader API and check for errors.
564 *
565 * Returns 0 in case of success, an error code otherwise
566 */
567static int
568streamParseTest(const char *filename, const char *result, const char *err,
569 int options) {
570 xmlTextReaderPtr reader;
571 int ret;
572 char *temp = NULL;
573 FILE *t = NULL;
574
575 if (result != NULL) {
576 temp = resultFilename(filename, "", ".res");
577 if (temp == NULL) {
578 fprintf(stderr, "Out of memory\n");
579 fatalError();
580 }
581 t = fopen(temp, "w");
582 if (t == NULL) {
583 fprintf(stderr, "Can't open temp file %s\n", temp);
584 free(temp);
585 return(-1);
586 }
587 }
588 xmlGetWarningsDefaultValue = 1;
589 reader = xmlReaderForFile(filename, NULL, options);
590 ret = xmlTextReaderRead(reader);
591 while (ret == 1) {
592 if (t != NULL)
593 processNode(t, reader);
594 ret = xmlTextReaderRead(reader);
595 }
596 if (ret != 0) {
597 testErrorHandler(NULL, "%s : failed to parse\n", filename);
598 }
599 xmlFreeTextReader(reader);
600 xmlGetWarningsDefaultValue = 0;
601 if (t != NULL) {
602 fclose(t);
603 ret = compareFiles(temp, result);
604 unlink(temp);
605 free(temp);
606 if (ret) {
607 fprintf(stderr, "Result for %s failed\n", filename);
608 return(-1);
609 }
610 }
611 if (err != NULL) {
612 ret = compareFileMem(err, testErrors, testErrorsSize);
613 if (ret != 0) {
614 fprintf(stderr, "Error for %s failed\n", filename);
615 return(-1);
616 }
617 }
618
619 return(0);
620}
621#endif
622
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000623/************************************************************************
624 * *
625 * Tests Descriptions *
626 * *
627 ************************************************************************/
628
629static
630testDesc testDescriptions[] = {
Daniel Veillardfd110d22005-06-27 00:02:02 +0000631 { "XML regression tests" ,
Daniel Veillardc111c152005-06-27 08:22:10 +0000632 oldParseTest, "./test/*", "result/", "", NULL,
633 0 },
Daniel Veillardfd110d22005-06-27 00:02:02 +0000634 { "XML regression tests on memory" ,
Daniel Veillardc111c152005-06-27 08:22:10 +0000635 memParseTest, "./test/*", "result/", "", NULL,
636 0 },
Daniel Veillardfd110d22005-06-27 00:02:02 +0000637 { "XML entity subst regression tests" ,
Daniel Veillardc111c152005-06-27 08:22:10 +0000638 noentParseTest, "./test/*", "result/noent/", "", NULL,
639 0 },
Daniel Veillardfd110d22005-06-27 00:02:02 +0000640 { "XML Namespaces regression tests",
Daniel Veillardc111c152005-06-27 08:22:10 +0000641 errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err",
642 0 },
Daniel Veillardfd110d22005-06-27 00:02:02 +0000643 { "Error cases regression tests",
Daniel Veillardc111c152005-06-27 08:22:10 +0000644 errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err",
645 0 },
646#ifdef LIBXML_READER_ENABLED
647 { "Error cases stream regression tests",
648 streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str",
649 0 },
650 { "Reader regression tests",
651 streamParseTest, "./test/*", "result/", ".rdr", NULL,
652 0 },
653 { "Reader entities substitution regression tests",
654 streamParseTest, "./test/*", "result/", ".rde", NULL,
655 XML_PARSE_NOENT },
656#endif
657 {NULL, NULL, NULL, NULL, NULL, NULL, 0}
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000658};
659
660/************************************************************************
661 * *
662 * The main driving the tests *
663 * *
664 ************************************************************************/
665
666static int
667launchTests(testDescPtr tst) {
668 int res = 0, err = 0;
669 size_t i;
670 char *result;
Daniel Veillardfd110d22005-06-27 00:02:02 +0000671 char *error;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000672 int mem, leak;
673
674 if (tst == NULL) return(-1);
675 if (tst->in != NULL) {
676 glob_t globbuf;
677
678 globbuf.gl_offs = 0;
679 glob(tst->in, GLOB_DOOFFS, NULL, &globbuf);
680 for (i = 0;i < globbuf.gl_pathc;i++) {
681 if (!checkTestFile(globbuf.gl_pathv[i]))
682 continue;
Daniel Veillardfd110d22005-06-27 00:02:02 +0000683 if (tst->suffix != NULL) {
684 result = resultFilename(globbuf.gl_pathv[i], tst->out,
685 tst->suffix);
686 if (result == NULL) {
687 fprintf(stderr, "Out of memory !\n");
688 fatalError();
689 }
690 } else {
691 result = NULL;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000692 }
Daniel Veillardfd110d22005-06-27 00:02:02 +0000693 if (tst->err != NULL) {
694 error = resultFilename(globbuf.gl_pathv[i], tst->out,
695 tst->err);
696 if (error == NULL) {
697 fprintf(stderr, "Out of memory !\n");
698 fatalError();
699 }
700 } else {
701 error = NULL;
702 }
703 if ((result) &&(!checkTestFile(result))) {
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000704 fprintf(stderr, "Missing result file %s\n", result);
Daniel Veillardfd110d22005-06-27 00:02:02 +0000705 } else if ((error) &&(!checkTestFile(error))) {
706 fprintf(stderr, "Missing error file %s\n", error);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000707 } else {
708 mem = xmlMemUsed();
709 extraMemoryFromResolver = 0;
Daniel Veillardfd110d22005-06-27 00:02:02 +0000710 testErrorsSize = 0;
711 testErrors[0] = 0;
Daniel Veillardc111c152005-06-27 08:22:10 +0000712 res = tst->func(globbuf.gl_pathv[i], result, error,
713 tst->options);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000714 if (res != 0) {
715 fprintf(stderr, "File %s generated an error\n",
716 globbuf.gl_pathv[i]);
717 err++;
718 }
719 else if (xmlMemUsed() != mem) {
Daniel Veillardfd110d22005-06-27 00:02:02 +0000720 xmlResetLastError();
721 if ((xmlMemUsed() != mem) &&
722 (extraMemoryFromResolver == 0)) {
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000723 fprintf(stderr, "File %s leaked %d bytes\n",
724 globbuf.gl_pathv[i], xmlMemUsed() - mem);
725 leak++;
726 err++;
727 }
728 }
Daniel Veillardfd110d22005-06-27 00:02:02 +0000729 testErrorsSize = 0;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000730 }
Daniel Veillardfd110d22005-06-27 00:02:02 +0000731 if (result)
732 free(result);
733 if (error)
734 free(error);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000735 }
736 } else {
Daniel Veillardfd110d22005-06-27 00:02:02 +0000737 testErrorsSize = 0;
738 testErrors[0] = 0;
739 extraMemoryFromResolver = 0;
Daniel Veillardc111c152005-06-27 08:22:10 +0000740 res = tst->func(NULL, NULL, NULL, tst->options);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000741 if (res != 0)
742 err++;
743 }
744 return(err);
745}
746
747int
Daniel Veillardc111c152005-06-27 08:22:10 +0000748main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000749 int i = 0, res, ret = 0;
750
751 initializeLibxml2();
752
753 for (i = 0; testDescriptions[i].func != NULL; i++) {
754 if (testDescriptions[i].desc != NULL)
755 printf("## %s\n", testDescriptions[i].desc);
756 res = launchTests(&testDescriptions[i]);
757 if (res != 0)
758 ret++;
759 }
760 xmlCleanupParser();
761 xmlMemoryDump();
762
763 return(ret);
764}