blob: 3bd0f18d5be6ffae5a391b1c0246df8b496e95ea [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
Daniel Veillardc9352532005-07-04 14:25:34 +000011#if !defined(_WIN32) || defined(__CYGWIN__)
Daniel Veillard1b75c3b2005-06-26 21:49:08 +000012#include <unistd.h>
Daniel Veillardc9352532005-07-04 14:25:34 +000013#endif
Daniel Veillard1b75c3b2005-06-26 21:49:08 +000014#include <string.h>
15#include <stdio.h>
16#include <glob.h>
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <fcntl.h>
Daniel Veillard1b75c3b2005-06-26 21:49:08 +000020
21#include <libxml/parser.h>
22#include <libxml/tree.h>
Daniel Veillard30564042005-06-28 07:30:41 +000023#include <libxml/uri.h>
Daniel Veillard6b6d6802005-07-03 21:00:34 +000024
25#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardc111c152005-06-27 08:22:10 +000026#ifdef LIBXML_READER_ENABLED
27#include <libxml/xmlreader.h>
28#endif
Daniel Veillard1b75c3b2005-06-26 21:49:08 +000029
Daniel Veillard970adf52005-06-27 16:40:10 +000030#ifdef LIBXML_XINCLUDE_ENABLED
31#include <libxml/xinclude.h>
32#endif
33
34#ifdef LIBXML_XPATH_ENABLED
35#include <libxml/xpath.h>
36#include <libxml/xpathInternals.h>
37#ifdef LIBXML_XPTR_ENABLED
38#include <libxml/xpointer.h>
39#endif
40#endif
41
Daniel Veillardf2e066a2005-06-30 13:04:44 +000042#ifdef LIBXML_SCHEMAS_ENABLED
43#include <libxml/relaxng.h>
44#include <libxml/xmlschemas.h>
45#include <libxml/xmlschemastypes.h>
46#endif
47
48#ifdef LIBXML_PATTERN_ENABLED
49#include <libxml/pattern.h>
50#endif
51
52#ifdef LIBXML_C14N_ENABLED
53#include <libxml/c14n.h>
54#endif
55
Daniel Veillardfc319af2005-06-27 12:44:55 +000056#ifdef LIBXML_HTML_ENABLED
57#include <libxml/HTMLparser.h>
58#include <libxml/HTMLtree.h>
59
60/*
61 * pseudo flag for the unification of HTML and XML tests
62 */
63#define XML_PARSE_HTML 1 << 24
64#endif
65
Daniel Veillardf2e066a2005-06-30 13:04:44 +000066#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
67#include <libxml/globals.h>
68#include <libxml/threads.h>
69#include <libxml/parser.h>
70#include <libxml/catalog.h>
71#include <string.h>
Daniel Veillardf2e066a2005-06-30 13:04:44 +000072#endif
73
Daniel Veillardfd110d22005-06-27 00:02:02 +000074typedef int (*functest) (const char *filename, const char *result,
Daniel Veillardc111c152005-06-27 08:22:10 +000075 const char *error, int options);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +000076
77typedef struct testDesc testDesc;
78typedef testDesc *testDescPtr;
79struct testDesc {
80 const char *desc; /* descripton of the test */
81 functest func; /* function implementing the test */
82 const char *in; /* glob to path for input files */
83 const char *out; /* output directory */
84 const char *suffix;/* suffix for output files */
Daniel Veillardfd110d22005-06-27 00:02:02 +000085 const char *err; /* suffix for error output files */
Daniel Veillardc111c152005-06-27 08:22:10 +000086 int options; /* parser options for the test */
Daniel Veillard1b75c3b2005-06-26 21:49:08 +000087};
88
89static int checkTestFile(const char *filename);
90/************************************************************************
91 * *
92 * Libxml2 specific routines *
93 * *
94 ************************************************************************/
95
Daniel Veillardf2e066a2005-06-30 13:04:44 +000096static int nb_tests = 0;
97static int nb_errors = 0;
98static int nb_leaks = 0;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +000099static long libxmlMemoryAllocatedBase = 0;
100static int extraMemoryFromResolver = 0;
101
102static int
103fatalError(void) {
104 fprintf(stderr, "Exitting tests on fatal error\n");
105 exit(1);
106}
107
108/*
109 * We need to trap calls to the resolver to not account memory for the catalog
110 * which is shared to the current running test. We also don't want to have
111 * network downloads modifying tests.
112 */
113static xmlParserInputPtr
114testExternalEntityLoader(const char *URL, const char *ID,
115 xmlParserCtxtPtr ctxt) {
116 xmlParserInputPtr ret;
117
118 if (checkTestFile(URL)) {
119 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
120 } else {
121 int memused = xmlMemUsed();
122 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
123 extraMemoryFromResolver += xmlMemUsed() - memused;
124 }
125
126 return(ret);
127}
128
Daniel Veillardfd110d22005-06-27 00:02:02 +0000129/*
130 * Trapping the error messages at the generic level to grab the equivalent of
131 * stderr messages on CLI tools.
132 */
133static char testErrors[32769];
134static int testErrorsSize = 0;
135
136static void
Daniel Veillardc111c152005-06-27 08:22:10 +0000137testErrorHandler(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
Daniel Veillardfd110d22005-06-27 00:02:02 +0000138 va_list args;
139 int res;
140
141 if (testErrorsSize >= 32768)
142 return;
143 va_start(args, msg);
144 res = vsnprintf(&testErrors[testErrorsSize],
145 32768 - testErrorsSize,
146 msg, args);
147 va_end(args);
148 if (testErrorsSize + res >= 32768) {
149 /* buffer is full */
150 testErrorsSize = 32768;
151 testErrors[testErrorsSize] = 0;
152 } else {
153 testErrorsSize += res;
154 }
155 testErrors[testErrorsSize] = 0;
156}
157
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000158static void
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000159channel(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
160 va_list args;
161 int res;
162
163 if (testErrorsSize >= 32768)
164 return;
165 va_start(args, msg);
166 res = vsnprintf(&testErrors[testErrorsSize],
167 32768 - testErrorsSize,
168 msg, args);
169 va_end(args);
170 if (testErrorsSize + res >= 32768) {
171 /* buffer is full */
172 testErrorsSize = 32768;
173 testErrors[testErrorsSize] = 0;
174 } else {
175 testErrorsSize += res;
176 }
177 testErrors[testErrorsSize] = 0;
178}
179
180/**
181 * xmlParserPrintFileContext:
182 * @input: an xmlParserInputPtr input
183 *
184 * Displays current context within the input content for error tracking
185 */
186
187static void
188xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
189 xmlGenericErrorFunc chanl, void *data ) {
190 const xmlChar *cur, *base;
191 unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */
192 xmlChar content[81]; /* space for 80 chars + line terminator */
193 xmlChar *ctnt;
194
195 if (input == NULL) return;
196 cur = input->cur;
197 base = input->base;
198 /* skip backwards over any end-of-lines */
199 while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
200 cur--;
201 }
202 n = 0;
203 /* search backwards for beginning-of-line (to max buff size) */
204 while ((n++ < (sizeof(content)-1)) && (cur > base) &&
205 (*(cur) != '\n') && (*(cur) != '\r'))
206 cur--;
207 if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
208 /* calculate the error position in terms of the current position */
209 col = input->cur - cur;
210 /* search forward for end-of-line (to max buff size) */
211 n = 0;
212 ctnt = content;
213 /* copy selected text to our buffer */
214 while ((*cur != 0) && (*(cur) != '\n') &&
215 (*(cur) != '\r') && (n < sizeof(content)-1)) {
216 *ctnt++ = *cur++;
217 n++;
218 }
219 *ctnt = 0;
220 /* print out the selected text */
221 chanl(data ,"%s\n", content);
222 /* create blank line with problem pointer */
223 n = 0;
224 ctnt = content;
225 /* (leave buffer space for pointer + line terminator) */
226 while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
227 if (*(ctnt) != '\t')
228 *(ctnt) = ' ';
229 ctnt++;
230 }
231 *ctnt++ = '^';
232 *ctnt = 0;
233 chanl(data ,"%s\n", content);
234}
235
236static void
237testStructuredErrorHandler(void *ctx ATTRIBUTE_UNUSED, xmlErrorPtr err) {
238 char *file = NULL;
239 int line = 0;
240 int code = -1;
241 int domain;
242 void *data = NULL;
243 const char *str;
244 const xmlChar *name = NULL;
245 xmlNodePtr node;
246 xmlErrorLevel level;
247 xmlParserInputPtr input = NULL;
248 xmlParserInputPtr cur = NULL;
249 xmlParserCtxtPtr ctxt = NULL;
250
251 if (err == NULL)
252 return;
253
254 file = err->file;
255 line = err->line;
256 code = err->code;
257 domain = err->domain;
258 level = err->level;
259 node = err->node;
260 if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
261 (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
262 (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
263 ctxt = err->ctxt;
264 }
265 str = err->message;
266
267 if (code == XML_ERR_OK)
268 return;
269
270 if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
271 name = node->name;
272
273 /*
274 * Maintain the compatibility with the legacy error handling
275 */
276 if (ctxt != NULL) {
277 input = ctxt->input;
278 if ((input != NULL) && (input->filename == NULL) &&
279 (ctxt->inputNr > 1)) {
280 cur = input;
281 input = ctxt->inputTab[ctxt->inputNr - 2];
282 }
283 if (input != NULL) {
284 if (input->filename)
285 channel(data, "%s:%d: ", input->filename, input->line);
286 else if ((line != 0) && (domain == XML_FROM_PARSER))
287 channel(data, "Entity: line %d: ", input->line);
288 }
289 } else {
290 if (file != NULL)
291 channel(data, "%s:%d: ", file, line);
292 else if ((line != 0) && (domain == XML_FROM_PARSER))
293 channel(data, "Entity: line %d: ", line);
294 }
295 if (name != NULL) {
296 channel(data, "element %s: ", name);
297 }
298 if (code == XML_ERR_OK)
299 return;
300 switch (domain) {
301 case XML_FROM_PARSER:
302 channel(data, "parser ");
303 break;
304 case XML_FROM_NAMESPACE:
305 channel(data, "namespace ");
306 break;
307 case XML_FROM_DTD:
308 case XML_FROM_VALID:
309 channel(data, "validity ");
310 break;
311 case XML_FROM_HTML:
312 channel(data, "HTML parser ");
313 break;
314 case XML_FROM_MEMORY:
315 channel(data, "memory ");
316 break;
317 case XML_FROM_OUTPUT:
318 channel(data, "output ");
319 break;
320 case XML_FROM_IO:
321 channel(data, "I/O ");
322 break;
323 case XML_FROM_XINCLUDE:
324 channel(data, "XInclude ");
325 break;
326 case XML_FROM_XPATH:
327 channel(data, "XPath ");
328 break;
329 case XML_FROM_XPOINTER:
330 channel(data, "parser ");
331 break;
332 case XML_FROM_REGEXP:
333 channel(data, "regexp ");
334 break;
335 case XML_FROM_MODULE:
336 channel(data, "module ");
337 break;
338 case XML_FROM_SCHEMASV:
339 channel(data, "Schemas validity ");
340 break;
341 case XML_FROM_SCHEMASP:
342 channel(data, "Schemas parser ");
343 break;
344 case XML_FROM_RELAXNGP:
345 channel(data, "Relax-NG parser ");
346 break;
347 case XML_FROM_RELAXNGV:
348 channel(data, "Relax-NG validity ");
349 break;
350 case XML_FROM_CATALOG:
351 channel(data, "Catalog ");
352 break;
353 case XML_FROM_C14N:
354 channel(data, "C14N ");
355 break;
356 case XML_FROM_XSLT:
357 channel(data, "XSLT ");
358 break;
359 default:
360 break;
361 }
362 if (code == XML_ERR_OK)
363 return;
364 switch (level) {
365 case XML_ERR_NONE:
366 channel(data, ": ");
367 break;
368 case XML_ERR_WARNING:
369 channel(data, "warning : ");
370 break;
371 case XML_ERR_ERROR:
372 channel(data, "error : ");
373 break;
374 case XML_ERR_FATAL:
375 channel(data, "error : ");
376 break;
377 }
378 if (code == XML_ERR_OK)
379 return;
380 if (str != NULL) {
381 int len;
382 len = xmlStrlen((const xmlChar *)str);
383 if ((len > 0) && (str[len - 1] != '\n'))
384 channel(data, "%s\n", str);
385 else
386 channel(data, "%s", str);
387 } else {
388 channel(data, "%s\n", "out of memory error");
389 }
390 if (code == XML_ERR_OK)
391 return;
392
393 if (ctxt != NULL) {
394 xmlParserPrintFileContextInternal(input, channel, data);
395 if (cur != NULL) {
396 if (cur->filename)
397 channel(data, "%s:%d: \n", cur->filename, cur->line);
398 else if ((line != 0) && (domain == XML_FROM_PARSER))
399 channel(data, "Entity: line %d: \n", cur->line);
400 xmlParserPrintFileContextInternal(cur, channel, data);
401 }
402 }
403 if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
404 (err->int1 < 100) &&
405 (err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
406 xmlChar buf[150];
407 int i;
408
409 channel(data, "%s\n", err->str1);
410 for (i=0;i < err->int1;i++)
411 buf[i] = ' ';
412 buf[i++] = '^';
413 buf[i] = 0;
414 channel(data, "%s\n", buf);
415 }
416}
417
418static void
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000419initializeLibxml2(void) {
420 xmlGetWarningsDefaultValue = 0;
421 xmlPedanticParserDefault(0);
422
423 xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
424 xmlInitParser();
425 xmlSetExternalEntityLoader(testExternalEntityLoader);
Daniel Veillardf2e066a2005-06-30 13:04:44 +0000426 xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
427#ifdef LIBXML_SCHEMAS_ENABLED
428 xmlSchemaInitTypes();
429 xmlRelaxNGInitTypes();
430#endif
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000431 libxmlMemoryAllocatedBase = xmlMemUsed();
432}
433
434
435/************************************************************************
436 * *
437 * File name and path utilities *
438 * *
439 ************************************************************************/
440
441static const char *baseFilename(const char *filename) {
442 const char *cur;
443 if (filename == NULL)
444 return(NULL);
445 cur = &filename[strlen(filename)];
446 while ((cur > filename) && (*cur != '/'))
447 cur--;
448 if (*cur == '/')
449 return(cur + 1);
450 return(cur);
451}
452
453static char *resultFilename(const char *filename, const char *out,
454 const char *suffix) {
455 const char *base;
456 char res[500];
457
458/*************
459 if ((filename[0] == 't') && (filename[1] == 'e') &&
460 (filename[2] == 's') && (filename[3] == 't') &&
461 (filename[4] == '/'))
462 filename = &filename[5];
463 *************/
464
465 base = baseFilename(filename);
466 if (suffix == NULL)
467 suffix = ".tmp";
468 if (out == NULL)
469 out = "";
470 snprintf(res, 499, "%s%s%s", out, base, suffix);
471 res[499] = 0;
472 return(strdup(res));
473}
474
475static int checkTestFile(const char *filename) {
476 struct stat buf;
477
478 if (stat(filename, &buf) == -1)
479 return(0);
480
481 if (!S_ISREG(buf.st_mode))
482 return(0);
483
484 return(1);
485}
486
487static int compareFiles(const char *r1, const char *r2) {
488 int res1, res2;
489 int fd1, fd2;
490 char bytes1[4096];
491 char bytes2[4096];
492
493 fd1 = open(r1, O_RDONLY);
494 if (fd1 < 0)
495 return(-1);
496 fd2 = open(r2, O_RDONLY);
497 if (fd2 < 0) {
498 close(fd1);
499 return(-1);
500 }
501 while (1) {
502 res1 = read(fd1, bytes1, 4096);
503 res2 = read(fd2, bytes2, 4096);
504 if (res1 != res2) {
505 close(fd1);
506 close(fd2);
507 return(1);
508 }
509 if (res1 == 0)
510 break;
511 if (memcmp(bytes1, bytes2, res1) != 0) {
512 close(fd1);
513 close(fd2);
514 return(1);
515 }
516 }
517 close(fd1);
518 close(fd2);
519 return(0);
520}
521
Daniel Veillardfd110d22005-06-27 00:02:02 +0000522static int compareFileMem(const char *filename, const char *mem, int size) {
523 int res;
524 int fd;
525 char bytes[4096];
526 int idx = 0;
527 struct stat info;
528
529 if (stat(filename, &info) < 0)
530 return(-1);
531 if (info.st_size != size)
532 return(-1);
533 fd = open(filename, O_RDONLY);
534 if (fd < 0)
535 return(-1);
536 while (idx < size) {
537 res = read(fd, bytes, 4096);
538 if (res <= 0)
539 break;
540 if (res + idx > size)
541 break;
542 if (memcmp(bytes, &mem[idx], res) != 0) {
543 close(fd);
544 return(1);
545 }
546 idx += res;
547 }
548 close(fd);
549 return(idx != size);
550}
551
Daniel Veillard1b75c3b2005-06-26 21:49:08 +0000552static int loadMem(const char *filename, const char **mem, int *size) {
553 int fd, res;
554 struct stat info;
555 char *base;
556 int siz = 0;
557 if (stat(filename, &info) < 0)
558 return(-1);
559 base = malloc(info.st_size + 1);
560 if (base == NULL)
561 return(-1);
562 if ((fd = open(filename, O_RDONLY)) < 0) {
563 free(base);
564 return(-1);
565 }
566 while ((res = read(fd, &base[siz], info.st_size - siz)) > 0) {
567 siz += res;
568 }
569 close(fd);
570 if (siz != info.st_size) {
571 free(base);
572 return(-1);
573 }
574 base[siz] = 0;
575 *mem = base;
576 *size = siz;
577 return(0);
578}
579
580static int unloadMem(const char *mem) {
581 free((char *)mem);
582 return(0);
583}
584
585/************************************************************************
586 * *
587 * Tests implementations *
588 * *
589 ************************************************************************/
590
Daniel Veillard4a5a9642005-06-27 10:40:55 +0000591/************************************************************************
592 * *
593 * Parse to SAX based tests *
594 * *
595 ************************************************************************/
596
597FILE *SAXdebug = NULL;
598
599/*
600 * empty SAX block
601 */
602xmlSAXHandler emptySAXHandlerStruct = {
603 NULL, /* internalSubset */
604 NULL, /* isStandalone */
605 NULL, /* hasInternalSubset */
606 NULL, /* hasExternalSubset */
607 NULL, /* resolveEntity */
608 NULL, /* getEntity */
609 NULL, /* entityDecl */
610 NULL, /* notationDecl */
611 NULL, /* attributeDecl */
612 NULL, /* elementDecl */
613 NULL, /* unparsedEntityDecl */
614 NULL, /* setDocumentLocator */
615 NULL, /* startDocument */
616 NULL, /* endDocument */
617 NULL, /* startElement */
618 NULL, /* endElement */
619 NULL, /* reference */
620 NULL, /* characters */
621 NULL, /* ignorableWhitespace */
622 NULL, /* processingInstruction */
623 NULL, /* comment */
624 NULL, /* xmlParserWarning */
625 NULL, /* xmlParserError */
626 NULL, /* xmlParserError */
627 NULL, /* getParameterEntity */
628 NULL, /* cdataBlock; */
629 NULL, /* externalSubset; */
630 1,
631 NULL,
632 NULL, /* startElementNs */
633 NULL, /* endElementNs */
634 NULL /* xmlStructuredErrorFunc */
635};
636
637static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct;
638int callbacks = 0;
639int quiet = 0;
640
641/**
642 * isStandaloneDebug:
643 * @ctxt: An XML parser context
644 *
645 * Is this document tagged standalone ?
646 *
647 * Returns 1 if true
648 */
649static int
650isStandaloneDebug(void *ctx ATTRIBUTE_UNUSED)
651{
652 callbacks++;
653 if (quiet)
654 return(0);
655 fprintf(SAXdebug, "SAX.isStandalone()\n");
656 return(0);
657}
658
659/**
660 * hasInternalSubsetDebug:
661 * @ctxt: An XML parser context
662 *
663 * Does this document has an internal subset
664 *
665 * Returns 1 if true
666 */
667static int
668hasInternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
669{
670 callbacks++;
671 if (quiet)
672 return(0);
673 fprintf(SAXdebug, "SAX.hasInternalSubset()\n");
674 return(0);
675}
676
677/**
678 * hasExternalSubsetDebug:
679 * @ctxt: An XML parser context
680 *
681 * Does this document has an external subset
682 *
683 * Returns 1 if true
684 */
685static int
686hasExternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
687{
688 callbacks++;
689 if (quiet)
690 return(0);
691 fprintf(SAXdebug, "SAX.hasExternalSubset()\n");
692 return(0);
693}
694
695/**
696 * internalSubsetDebug:
697 * @ctxt: An XML parser context
698 *
699 * Does this document has an internal subset
700 */
701static void
702internalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
703 const xmlChar *ExternalID, const xmlChar *SystemID)
704{
705 callbacks++;
706 if (quiet)
707 return;
708 fprintf(SAXdebug, "SAX.internalSubset(%s,", name);
709 if (ExternalID == NULL)
710 fprintf(SAXdebug, " ,");
711 else
712 fprintf(SAXdebug, " %s,", ExternalID);
713 if (SystemID == NULL)
714 fprintf(SAXdebug, " )\n");
715 else
716 fprintf(SAXdebug, " %s)\n", SystemID);
717}
718
719/**
720 * externalSubsetDebug:
721 * @ctxt: An XML parser context
722 *
723 * Does this document has an external subset
724 */
725static void
726externalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
727 const xmlChar *ExternalID, const xmlChar *SystemID)
728{
729 callbacks++;
730 if (quiet)
731 return;
732 fprintf(SAXdebug, "SAX.externalSubset(%s,", name);
733 if (ExternalID == NULL)
734 fprintf(SAXdebug, " ,");
735 else
736 fprintf(SAXdebug, " %s,", ExternalID);
737 if (SystemID == NULL)
738 fprintf(SAXdebug, " )\n");
739 else
740 fprintf(SAXdebug, " %s)\n", SystemID);
741}
742
743/**
744 * resolveEntityDebug:
745 * @ctxt: An XML parser context
746 * @publicId: The public ID of the entity
747 * @systemId: The system ID of the entity
748 *
749 * Special entity resolver, better left to the parser, it has
750 * more context than the application layer.
751 * The default behaviour is to NOT resolve the entities, in that case
752 * the ENTITY_REF nodes are built in the structure (and the parameter
753 * values).
754 *
755 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
756 */
757static xmlParserInputPtr
758resolveEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *publicId, const xmlChar *systemId)
759{
760 callbacks++;
761 if (quiet)
762 return(NULL);
763 /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
764
765
766 fprintf(SAXdebug, "SAX.resolveEntity(");
767 if (publicId != NULL)
768 fprintf(SAXdebug, "%s", (char *)publicId);
769 else
770 fprintf(SAXdebug, " ");
771 if (systemId != NULL)
772 fprintf(SAXdebug, ", %s)\n", (char *)systemId);
773 else
774 fprintf(SAXdebug, ", )\n");
775/*********
776 if (systemId != NULL) {
777 return(xmlNewInputFromFile(ctxt, (char *) systemId));
778 }
779 *********/
780 return(NULL);
781}
782
783/**
784 * getEntityDebug:
785 * @ctxt: An XML parser context
786 * @name: The entity name
787 *
788 * Get an entity by name
789 *
790 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
791 */
792static xmlEntityPtr
793getEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
794{
795 callbacks++;
796 if (quiet)
797 return(NULL);
798 fprintf(SAXdebug, "SAX.getEntity(%s)\n", name);
799 return(NULL);
800}
801
802/**
803 * getParameterEntityDebug:
804 * @ctxt: An XML parser context
805 * @name: The entity name
806 *
807 * Get a parameter entity by name
808 *
809 * Returns the xmlParserInputPtr
810 */
811static xmlEntityPtr
812getParameterEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
813{
814 callbacks++;
815 if (quiet)
816 return(NULL);
817 fprintf(SAXdebug, "SAX.getParameterEntity(%s)\n", name);
818 return(NULL);
819}
820
821
822/**
823 * entityDeclDebug:
824 * @ctxt: An XML parser context
825 * @name: the entity name
826 * @type: the entity type
827 * @publicId: The public ID of the entity
828 * @systemId: The system ID of the entity
829 * @content: the entity value (without processing).
830 *
831 * An entity definition has been parsed
832 */
833static void
834entityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
835 const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
836{
837const xmlChar *nullstr = BAD_CAST "(null)";
838 /* not all libraries handle printing null pointers nicely */
839 if (publicId == NULL)
840 publicId = nullstr;
841 if (systemId == NULL)
842 systemId = nullstr;
843 if (content == NULL)
844 content = (xmlChar *)nullstr;
845 callbacks++;
846 if (quiet)
847 return;
848 fprintf(SAXdebug, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
849 name, type, publicId, systemId, content);
850}
851
852/**
853 * attributeDeclDebug:
854 * @ctxt: An XML parser context
855 * @name: the attribute name
856 * @type: the attribute type
857 *
858 * An attribute definition has been parsed
859 */
860static void
861attributeDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar * elem,
862 const xmlChar * name, int type, int def,
863 const xmlChar * defaultValue, xmlEnumerationPtr tree)
864{
865 callbacks++;
866 if (quiet)
867 return;
868 if (defaultValue == NULL)
869 fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, NULL, ...)\n",
870 elem, name, type, def);
871 else
872 fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
873 elem, name, type, def, defaultValue);
874 xmlFreeEnumeration(tree);
875}
876
877/**
878 * elementDeclDebug:
879 * @ctxt: An XML parser context
880 * @name: the element name
881 * @type: the element type
882 * @content: the element value (without processing).
883 *
884 * An element definition has been parsed
885 */
886static void
887elementDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
888 xmlElementContentPtr content ATTRIBUTE_UNUSED)
889{
890 callbacks++;
891 if (quiet)
892 return;
893 fprintf(SAXdebug, "SAX.elementDecl(%s, %d, ...)\n",
894 name, type);
895}
896
897/**
898 * notationDeclDebug:
899 * @ctxt: An XML parser context
900 * @name: The name of the notation
901 * @publicId: The public ID of the entity
902 * @systemId: The system ID of the entity
903 *
904 * What to do when a notation declaration has been parsed.
905 */
906static void
907notationDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
908 const xmlChar *publicId, const xmlChar *systemId)
909{
910 callbacks++;
911 if (quiet)
912 return;
913 fprintf(SAXdebug, "SAX.notationDecl(%s, %s, %s)\n",
914 (char *) name, (char *) publicId, (char *) systemId);
915}
916
917/**
918 * unparsedEntityDeclDebug:
919 * @ctxt: An XML parser context
920 * @name: The name of the entity
921 * @publicId: The public ID of the entity
922 * @systemId: The system ID of the entity
923 * @notationName: the name of the notation
924 *
925 * What to do when an unparsed entity declaration is parsed
926 */
927static void
928unparsedEntityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
929 const xmlChar *publicId, const xmlChar *systemId,
930 const xmlChar *notationName)
931{
932const xmlChar *nullstr = BAD_CAST "(null)";
933
934 if (publicId == NULL)
935 publicId = nullstr;
936 if (systemId == NULL)
937 systemId = nullstr;
938 if (notationName == NULL)
939 notationName = nullstr;
940 callbacks++;
941 if (quiet)
942 return;
943 fprintf(SAXdebug, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
944 (char *) name, (char *) publicId, (char *) systemId,
945 (char *) notationName);
946}
947
948/**
949 * setDocumentLocatorDebug:
950 * @ctxt: An XML parser context
951 * @loc: A SAX Locator
952 *
953 * Receive the document locator at startup, actually xmlDefaultSAXLocator
954 * Everything is available on the context, so this is useless in our case.
955 */
956static void
957setDocumentLocatorDebug(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
958{
959 callbacks++;
960 if (quiet)
961 return;
962 fprintf(SAXdebug, "SAX.setDocumentLocator()\n");
963}
964
965/**
966 * startDocumentDebug:
967 * @ctxt: An XML parser context
968 *
969 * called when the document start being processed.
970 */
971static void
972startDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
973{
974 callbacks++;
975 if (quiet)
976 return;
977 fprintf(SAXdebug, "SAX.startDocument()\n");
978}
979
980/**
981 * endDocumentDebug:
982 * @ctxt: An XML parser context
983 *
984 * called when the document end has been detected.
985 */
986static void
987endDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
988{
989 callbacks++;
990 if (quiet)
991 return;
992 fprintf(SAXdebug, "SAX.endDocument()\n");
993}
994
995/**
996 * startElementDebug:
997 * @ctxt: An XML parser context
998 * @name: The element name
999 *
1000 * called when an opening tag has been processed.
1001 */
1002static void
1003startElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
1004{
1005 int i;
1006
1007 callbacks++;
1008 if (quiet)
1009 return;
1010 fprintf(SAXdebug, "SAX.startElement(%s", (char *) name);
1011 if (atts != NULL) {
1012 for (i = 0;(atts[i] != NULL);i++) {
1013 fprintf(SAXdebug, ", %s='", atts[i++]);
1014 if (atts[i] != NULL)
1015 fprintf(SAXdebug, "%s'", atts[i]);
1016 }
1017 }
1018 fprintf(SAXdebug, ")\n");
1019}
1020
1021/**
1022 * endElementDebug:
1023 * @ctxt: An XML parser context
1024 * @name: The element name
1025 *
1026 * called when the end of an element has been detected.
1027 */
1028static void
1029endElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
1030{
1031 callbacks++;
1032 if (quiet)
1033 return;
1034 fprintf(SAXdebug, "SAX.endElement(%s)\n", (char *) name);
1035}
1036
1037/**
1038 * charactersDebug:
1039 * @ctxt: An XML parser context
1040 * @ch: a xmlChar string
1041 * @len: the number of xmlChar
1042 *
1043 * receiving some chars from the parser.
1044 * Question: how much at a time ???
1045 */
1046static void
1047charactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1048{
1049 char output[40];
1050 int i;
1051
1052 callbacks++;
1053 if (quiet)
1054 return;
1055 for (i = 0;(i<len) && (i < 30);i++)
1056 output[i] = ch[i];
1057 output[i] = 0;
1058
1059 fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len);
1060}
1061
1062/**
1063 * referenceDebug:
1064 * @ctxt: An XML parser context
1065 * @name: The entity name
1066 *
1067 * called when an entity reference is detected.
1068 */
1069static void
1070referenceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
1071{
1072 callbacks++;
1073 if (quiet)
1074 return;
1075 fprintf(SAXdebug, "SAX.reference(%s)\n", name);
1076}
1077
1078/**
1079 * ignorableWhitespaceDebug:
1080 * @ctxt: An XML parser context
1081 * @ch: a xmlChar string
1082 * @start: the first char in the string
1083 * @len: the number of xmlChar
1084 *
1085 * receiving some ignorable whitespaces from the parser.
1086 * Question: how much at a time ???
1087 */
1088static void
1089ignorableWhitespaceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1090{
1091 char output[40];
1092 int i;
1093
1094 callbacks++;
1095 if (quiet)
1096 return;
1097 for (i = 0;(i<len) && (i < 30);i++)
1098 output[i] = ch[i];
1099 output[i] = 0;
1100 fprintf(SAXdebug, "SAX.ignorableWhitespace(%s, %d)\n", output, len);
1101}
1102
1103/**
1104 * processingInstructionDebug:
1105 * @ctxt: An XML parser context
1106 * @target: the target name
1107 * @data: the PI data's
1108 * @len: the number of xmlChar
1109 *
1110 * A processing instruction has been parsed.
1111 */
1112static void
1113processingInstructionDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *target,
1114 const xmlChar *data)
1115{
1116 callbacks++;
1117 if (quiet)
1118 return;
1119 if (data != NULL)
1120 fprintf(SAXdebug, "SAX.processingInstruction(%s, %s)\n",
1121 (char *) target, (char *) data);
1122 else
1123 fprintf(SAXdebug, "SAX.processingInstruction(%s, NULL)\n",
1124 (char *) target);
1125}
1126
1127/**
1128 * cdataBlockDebug:
1129 * @ctx: the user data (XML parser context)
1130 * @value: The pcdata content
1131 * @len: the block length
1132 *
1133 * called when a pcdata block has been parsed
1134 */
1135static void
1136cdataBlockDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value, int len)
1137{
1138 callbacks++;
1139 if (quiet)
1140 return;
1141 fprintf(SAXdebug, "SAX.pcdata(%.20s, %d)\n",
1142 (char *) value, len);
1143}
1144
1145/**
1146 * commentDebug:
1147 * @ctxt: An XML parser context
1148 * @value: the comment content
1149 *
1150 * A comment has been parsed.
1151 */
1152static void
1153commentDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value)
1154{
1155 callbacks++;
1156 if (quiet)
1157 return;
1158 fprintf(SAXdebug, "SAX.comment(%s)\n", value);
1159}
1160
1161/**
1162 * warningDebug:
1163 * @ctxt: An XML parser context
1164 * @msg: the message to display/transmit
1165 * @...: extra parameters for the message display
1166 *
1167 * Display and format a warning messages, gives file, line, position and
1168 * extra parameters.
1169 */
1170static void
1171warningDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1172{
1173 va_list args;
1174
1175 callbacks++;
1176 if (quiet)
1177 return;
1178 va_start(args, msg);
1179 fprintf(SAXdebug, "SAX.warning: ");
1180 vfprintf(SAXdebug, msg, args);
1181 va_end(args);
1182}
1183
1184/**
1185 * errorDebug:
1186 * @ctxt: An XML parser context
1187 * @msg: the message to display/transmit
1188 * @...: extra parameters for the message display
1189 *
1190 * Display and format a error messages, gives file, line, position and
1191 * extra parameters.
1192 */
1193static void
1194errorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1195{
1196 va_list args;
1197
1198 callbacks++;
1199 if (quiet)
1200 return;
1201 va_start(args, msg);
1202 fprintf(SAXdebug, "SAX.error: ");
1203 vfprintf(SAXdebug, msg, args);
1204 va_end(args);
1205}
1206
1207/**
1208 * fatalErrorDebug:
1209 * @ctxt: An XML parser context
1210 * @msg: the message to display/transmit
1211 * @...: extra parameters for the message display
1212 *
1213 * Display and format a fatalError messages, gives file, line, position and
1214 * extra parameters.
1215 */
1216static void
1217fatalErrorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1218{
1219 va_list args;
1220
1221 callbacks++;
1222 if (quiet)
1223 return;
1224 va_start(args, msg);
1225 fprintf(SAXdebug, "SAX.fatalError: ");
1226 vfprintf(SAXdebug, msg, args);
1227 va_end(args);
1228}
1229
1230xmlSAXHandler debugSAXHandlerStruct = {
1231 internalSubsetDebug,
1232 isStandaloneDebug,
1233 hasInternalSubsetDebug,
1234 hasExternalSubsetDebug,
1235 resolveEntityDebug,
1236 getEntityDebug,
1237 entityDeclDebug,
1238 notationDeclDebug,
1239 attributeDeclDebug,
1240 elementDeclDebug,
1241 unparsedEntityDeclDebug,
1242 setDocumentLocatorDebug,
1243 startDocumentDebug,
1244 endDocumentDebug,
1245 startElementDebug,
1246 endElementDebug,
1247 referenceDebug,
1248 charactersDebug,
1249 ignorableWhitespaceDebug,
1250 processingInstructionDebug,
1251 commentDebug,
1252 warningDebug,
1253 errorDebug,
1254 fatalErrorDebug,
1255 getParameterEntityDebug,
1256 cdataBlockDebug,
1257 externalSubsetDebug,
1258 1,
1259 NULL,
1260 NULL,
1261 NULL,
1262 NULL
1263};
1264
1265xmlSAXHandlerPtr debugSAXHandler = &debugSAXHandlerStruct;
1266
1267/*
1268 * SAX2 specific callbacks
1269 */
1270/**
1271 * startElementNsDebug:
1272 * @ctxt: An XML parser context
1273 * @name: The element name
1274 *
1275 * called when an opening tag has been processed.
1276 */
1277static void
1278startElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
1279 const xmlChar *localname,
1280 const xmlChar *prefix,
1281 const xmlChar *URI,
1282 int nb_namespaces,
1283 const xmlChar **namespaces,
1284 int nb_attributes,
1285 int nb_defaulted,
1286 const xmlChar **attributes)
1287{
1288 int i;
1289
1290 callbacks++;
1291 if (quiet)
1292 return;
1293 fprintf(SAXdebug, "SAX.startElementNs(%s", (char *) localname);
1294 if (prefix == NULL)
1295 fprintf(SAXdebug, ", NULL");
1296 else
1297 fprintf(SAXdebug, ", %s", (char *) prefix);
1298 if (URI == NULL)
1299 fprintf(SAXdebug, ", NULL");
1300 else
1301 fprintf(SAXdebug, ", '%s'", (char *) URI);
1302 fprintf(SAXdebug, ", %d", nb_namespaces);
1303
1304 if (namespaces != NULL) {
1305 for (i = 0;i < nb_namespaces * 2;i++) {
1306 fprintf(SAXdebug, ", xmlns");
1307 if (namespaces[i] != NULL)
1308 fprintf(SAXdebug, ":%s", namespaces[i]);
1309 i++;
1310 fprintf(SAXdebug, "='%s'", namespaces[i]);
1311 }
1312 }
1313 fprintf(SAXdebug, ", %d, %d", nb_attributes, nb_defaulted);
1314 if (attributes != NULL) {
1315 for (i = 0;i < nb_attributes * 5;i += 5) {
1316 if (attributes[i + 1] != NULL)
1317 fprintf(SAXdebug, ", %s:%s='", attributes[i + 1], attributes[i]);
1318 else
1319 fprintf(SAXdebug, ", %s='", attributes[i]);
1320 fprintf(SAXdebug, "%.4s...', %d", attributes[i + 3],
1321 (int)(attributes[i + 4] - attributes[i + 3]));
1322 }
1323 }
1324 fprintf(SAXdebug, ")\n");
1325}
1326
1327/**
1328 * endElementDebug:
1329 * @ctxt: An XML parser context
1330 * @name: The element name
1331 *
1332 * called when the end of an element has been detected.
1333 */
1334static void
1335endElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
1336 const xmlChar *localname,
1337 const xmlChar *prefix,
1338 const xmlChar *URI)
1339{
1340 callbacks++;
1341 if (quiet)
1342 return;
1343 fprintf(SAXdebug, "SAX.endElementNs(%s", (char *) localname);
1344 if (prefix == NULL)
1345 fprintf(SAXdebug, ", NULL");
1346 else
1347 fprintf(SAXdebug, ", %s", (char *) prefix);
1348 if (URI == NULL)
1349 fprintf(SAXdebug, ", NULL)\n");
1350 else
1351 fprintf(SAXdebug, ", '%s')\n", (char *) URI);
1352}
1353
1354xmlSAXHandler debugSAX2HandlerStruct = {
1355 internalSubsetDebug,
1356 isStandaloneDebug,
1357 hasInternalSubsetDebug,
1358 hasExternalSubsetDebug,
1359 resolveEntityDebug,
1360 getEntityDebug,
1361 entityDeclDebug,
1362 notationDeclDebug,
1363 attributeDeclDebug,
1364 elementDeclDebug,
1365 unparsedEntityDeclDebug,
1366 setDocumentLocatorDebug,
1367 startDocumentDebug,
1368 endDocumentDebug,
1369 NULL,
1370 NULL,
1371 referenceDebug,
1372 charactersDebug,
1373 ignorableWhitespaceDebug,
1374 processingInstructionDebug,
1375 commentDebug,
1376 warningDebug,
1377 errorDebug,
1378 fatalErrorDebug,
1379 getParameterEntityDebug,
1380 cdataBlockDebug,
1381 externalSubsetDebug,
1382 XML_SAX2_MAGIC,
1383 NULL,
1384 startElementNsDebug,
1385 endElementNsDebug,
1386 NULL
1387};
1388
1389xmlSAXHandlerPtr debugSAX2Handler = &debugSAX2HandlerStruct;
1390
Daniel Veillard6b6d6802005-07-03 21:00:34 +00001391#ifdef LIBXML_HTML_ENABLED
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001392/**
Daniel Veillardfc319af2005-06-27 12:44:55 +00001393 * htmlstartElementDebug:
1394 * @ctxt: An XML parser context
1395 * @name: The element name
1396 *
1397 * called when an opening tag has been processed.
1398 */
1399static void
1400htmlstartElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
1401{
1402 int i;
1403
1404 fprintf(SAXdebug, "SAX.startElement(%s", (char *) name);
1405 if (atts != NULL) {
1406 for (i = 0;(atts[i] != NULL);i++) {
1407 fprintf(SAXdebug, ", %s", atts[i++]);
1408 if (atts[i] != NULL) {
1409 unsigned char output[40];
1410 const unsigned char *att = atts[i];
1411 int outlen, attlen;
1412 fprintf(SAXdebug, "='");
1413 while ((attlen = strlen((char*)att)) > 0) {
1414 outlen = sizeof output - 1;
1415 htmlEncodeEntities(output, &outlen, att, &attlen, '\'');
1416 output[outlen] = 0;
1417 fprintf(SAXdebug, "%s", (char *) output);
1418 att += attlen;
1419 }
1420 fprintf(SAXdebug, "'");
1421 }
1422 }
1423 }
1424 fprintf(SAXdebug, ")\n");
1425}
1426
1427/**
1428 * htmlcharactersDebug:
1429 * @ctxt: An XML parser context
1430 * @ch: a xmlChar string
1431 * @len: the number of xmlChar
1432 *
1433 * receiving some chars from the parser.
1434 * Question: how much at a time ???
1435 */
1436static void
1437htmlcharactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1438{
1439 unsigned char output[40];
1440 int inlen = len, outlen = 30;
1441
1442 htmlEncodeEntities(output, &outlen, ch, &inlen, 0);
1443 output[outlen] = 0;
1444
1445 fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len);
1446}
1447
1448/**
1449 * htmlcdataDebug:
1450 * @ctxt: An XML parser context
1451 * @ch: a xmlChar string
1452 * @len: the number of xmlChar
1453 *
1454 * receiving some cdata chars from the parser.
1455 * Question: how much at a time ???
1456 */
1457static void
1458htmlcdataDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1459{
1460 unsigned char output[40];
1461 int inlen = len, outlen = 30;
1462
1463 htmlEncodeEntities(output, &outlen, ch, &inlen, 0);
1464 output[outlen] = 0;
1465
1466 fprintf(SAXdebug, "SAX.cdata(%s, %d)\n", output, len);
1467}
1468
1469xmlSAXHandler debugHTMLSAXHandlerStruct = {
1470 internalSubsetDebug,
1471 isStandaloneDebug,
1472 hasInternalSubsetDebug,
1473 hasExternalSubsetDebug,
1474 resolveEntityDebug,
1475 getEntityDebug,
1476 entityDeclDebug,
1477 notationDeclDebug,
1478 attributeDeclDebug,
1479 elementDeclDebug,
1480 unparsedEntityDeclDebug,
1481 setDocumentLocatorDebug,
1482 startDocumentDebug,
1483 endDocumentDebug,
1484 htmlstartElementDebug,
1485 endElementDebug,
1486 referenceDebug,
1487 htmlcharactersDebug,
1488 ignorableWhitespaceDebug,
1489 processingInstructionDebug,
1490 commentDebug,
1491 warningDebug,
1492 errorDebug,
1493 fatalErrorDebug,
1494 getParameterEntityDebug,
1495 htmlcdataDebug,
1496 externalSubsetDebug,
1497 1,
1498 NULL,
1499 NULL,
1500 NULL,
1501 NULL
1502};
1503
1504xmlSAXHandlerPtr debugHTMLSAXHandler = &debugHTMLSAXHandlerStruct;
Daniel Veillard6b6d6802005-07-03 21:00:34 +00001505#endif /* LIBXML_HTML_ENABLED */
1506
1507#ifdef LIBXML_SAX1_ENABLED
Daniel Veillardfc319af2005-06-27 12:44:55 +00001508/**
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001509 * saxParseTest:
1510 * @filename: the file to parse
1511 * @result: the file with expected result
1512 * @err: the file with error messages
1513 *
1514 * Parse a file using the SAX API and check for errors.
1515 *
1516 * Returns 0 in case of success, an error code otherwise
1517 */
1518static int
Daniel Veillardfc319af2005-06-27 12:44:55 +00001519saxParseTest(const char *filename, const char *result,
1520 const char *err ATTRIBUTE_UNUSED,
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001521 int options) {
1522 int ret;
1523 char *temp;
1524
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001525 nb_tests++;
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001526 temp = resultFilename(filename, "", ".res");
1527 if (temp == NULL) {
1528 fprintf(stderr, "out of memory\n");
1529 fatalError();
1530 }
1531 SAXdebug = fopen(temp, "w");
1532 if (SAXdebug == NULL) {
1533 fprintf(stderr, "Failed to write to %s\n", temp);
1534 free(temp);
1535 return(-1);
1536 }
1537
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001538 /* for SAX we really want the callbacks though the context handlers */
1539 xmlSetStructuredErrorFunc(NULL, NULL);
1540 xmlSetGenericErrorFunc(NULL, testErrorHandler);
1541
Daniel Veillardfc319af2005-06-27 12:44:55 +00001542#ifdef LIBXML_HTML_ENABLED
1543 if (options & XML_PARSE_HTML) {
1544 htmlSAXParseFile(filename, NULL, emptySAXHandler, NULL);
1545 ret = 0;
1546 } else
1547#endif
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001548 ret = xmlSAXUserParseFile(emptySAXHandler, NULL, filename);
1549 if (ret == XML_WAR_UNDECLARED_ENTITY) {
1550 fprintf(SAXdebug, "xmlSAXUserParseFile returned error %d\n", ret);
1551 ret = 0;
1552 }
1553 if (ret != 0) {
1554 fprintf(stderr, "Failed to parse %s\n", filename);
1555 return(1);
1556 }
Daniel Veillardfc319af2005-06-27 12:44:55 +00001557#ifdef LIBXML_HTML_ENABLED
1558 if (options & XML_PARSE_HTML) {
1559 htmlSAXParseFile(filename, NULL, debugHTMLSAXHandler, NULL);
1560 ret = 0;
1561 } else
1562#endif
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001563 if (options & XML_PARSE_SAX1) {
1564 ret = xmlSAXUserParseFile(debugSAXHandler, NULL, filename);
1565 } else {
1566 ret = xmlSAXUserParseFile(debugSAX2Handler, NULL, filename);
1567 }
1568 if (ret == XML_WAR_UNDECLARED_ENTITY) {
1569 fprintf(SAXdebug, "xmlSAXUserParseFile returned error %d\n", ret);
1570 ret = 0;
1571 }
1572 fclose(SAXdebug);
1573 if (compareFiles(temp, result)) {
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001574 fprintf(stderr, "Got a difference for %s\n", filename);
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001575 ret = 1;
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001576 } else
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001577 unlink(temp);
1578 free(temp);
1579
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001580 /* switch back to structured error handling */
1581 xmlSetGenericErrorFunc(NULL, NULL);
1582 xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
1583
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001584 return(ret);
1585}
Daniel Veillard6b6d6802005-07-03 21:00:34 +00001586#endif
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001587
1588/************************************************************************
1589 * *
1590 * Parse to tree based tests *
1591 * *
1592 ************************************************************************/
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001593/**
1594 * oldParseTest:
1595 * @filename: the file to parse
1596 * @result: the file with expected result
Daniel Veillardfd110d22005-06-27 00:02:02 +00001597 * @err: the file with error messages: unused
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001598 *
1599 * Parse a file using the old xmlParseFile API, then serialize back
1600 * reparse the result and serialize again, then check for deviation
1601 * in serialization.
1602 *
1603 * Returns 0 in case of success, an error code otherwise
1604 */
1605static int
Daniel Veillardc111c152005-06-27 08:22:10 +00001606oldParseTest(const char *filename, const char *result,
1607 const char *err ATTRIBUTE_UNUSED,
1608 int options ATTRIBUTE_UNUSED) {
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001609 xmlDocPtr doc;
1610 char *temp;
1611 int res = 0;
1612
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001613 nb_tests++;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001614 /*
1615 * base of the test, parse with the old API
1616 */
Daniel Veillard6b6d6802005-07-03 21:00:34 +00001617#ifdef LIBXML_SAX1_ENABLED
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001618 doc = xmlParseFile(filename);
Daniel Veillard6b6d6802005-07-03 21:00:34 +00001619#else
1620 doc = xmlReadFile(filename, NULL, 0);
1621#endif
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001622 if (doc == NULL)
1623 return(1);
1624 temp = resultFilename(filename, "", ".res");
1625 if (temp == NULL) {
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001626 fprintf(stderr, "out of memory\n");
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001627 fatalError();
1628 }
1629 xmlSaveFile(temp, doc);
1630 if (compareFiles(temp, result)) {
1631 res = 1;
1632 }
1633 xmlFreeDoc(doc);
1634
1635 /*
1636 * Parse the saved result to make sure the round trip is okay
1637 */
Daniel Veillard6b6d6802005-07-03 21:00:34 +00001638#ifdef LIBXML_SAX1_ENABLED
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001639 doc = xmlParseFile(temp);
Daniel Veillard6b6d6802005-07-03 21:00:34 +00001640#else
1641 doc = xmlReadFile(temp, NULL, 0);
1642#endif
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001643 if (doc == NULL)
1644 return(1);
1645 xmlSaveFile(temp, doc);
1646 if (compareFiles(temp, result)) {
1647 res = 1;
1648 }
1649 xmlFreeDoc(doc);
1650
1651 unlink(temp);
1652 free(temp);
1653 return(res);
1654}
1655
Daniel Veillardfc319af2005-06-27 12:44:55 +00001656#ifdef LIBXML_PUSH_ENABLED
1657/**
1658 * pushParseTest:
1659 * @filename: the file to parse
1660 * @result: the file with expected result
1661 * @err: the file with error messages: unused
1662 *
1663 * Parse a file using the Push API, then serialize back
1664 * to check for content.
1665 *
1666 * Returns 0 in case of success, an error code otherwise
1667 */
1668static int
1669pushParseTest(const char *filename, const char *result,
1670 const char *err ATTRIBUTE_UNUSED,
1671 int options) {
1672 xmlParserCtxtPtr ctxt;
1673 xmlDocPtr doc;
1674 const char *base;
1675 int size, res;
1676 int cur = 0;
1677
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001678 nb_tests++;
Daniel Veillardfc319af2005-06-27 12:44:55 +00001679 /*
1680 * load the document in memory and work from there.
1681 */
1682 if (loadMem(filename, &base, &size) != 0) {
1683 fprintf(stderr, "Failed to load %s\n", filename);
1684 return(-1);
1685 }
1686
1687#ifdef LIBXML_HTML_ENABLED
1688 if (options & XML_PARSE_HTML)
1689 ctxt = htmlCreatePushParserCtxt(NULL, NULL, base + cur, 4, filename,
1690 XML_CHAR_ENCODING_NONE);
1691 else
1692#endif
1693 ctxt = xmlCreatePushParserCtxt(NULL, NULL, base + cur, 4, filename);
1694 xmlCtxtUseOptions(ctxt, options);
1695 cur += 4;
1696 while (cur < size) {
1697 if (cur + 1024 >= size) {
1698#ifdef LIBXML_HTML_ENABLED
1699 if (options & XML_PARSE_HTML)
1700 htmlParseChunk(ctxt, base + cur, size - cur, 1);
1701 else
1702#endif
1703 xmlParseChunk(ctxt, base + cur, size - cur, 1);
1704 break;
1705 } else {
1706#ifdef LIBXML_HTML_ENABLED
1707 if (options & XML_PARSE_HTML)
1708 htmlParseChunk(ctxt, base + cur, 1024, 0);
1709 else
1710#endif
1711 xmlParseChunk(ctxt, base + cur, 1024, 0);
1712 cur += 1024;
1713 }
1714 }
1715 doc = ctxt->myDoc;
1716#ifdef LIBXML_HTML_ENABLED
1717 if (options & XML_PARSE_HTML)
1718 res = 1;
1719 else
1720#endif
1721 res = ctxt->wellFormed;
1722 xmlFreeParserCtxt(ctxt);
1723 free((char *)base);
1724 if (!res) {
1725 xmlFreeDoc(doc);
1726 fprintf(stderr, "Failed to parse %s\n", filename);
1727 return(-1);
1728 }
1729#ifdef LIBXML_HTML_ENABLED
1730 if (options & XML_PARSE_HTML)
1731 htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1732 else
1733#endif
1734 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1735 xmlFreeDoc(doc);
1736 res = compareFileMem(result, base, size);
1737 if ((base == NULL) || (res != 0)) {
1738 if (base != NULL)
1739 xmlFree((char *)base);
1740 fprintf(stderr, "Result for %s failed\n", filename);
1741 return(-1);
1742 }
1743 xmlFree((char *)base);
1744 if (err != NULL) {
1745 res = compareFileMem(err, testErrors, testErrorsSize);
1746 if (res != 0) {
1747 fprintf(stderr, "Error for %s failed\n", filename);
1748 return(-1);
1749 }
1750 }
1751 return(0);
1752}
1753#endif
1754
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001755/**
1756 * memParseTest:
1757 * @filename: the file to parse
1758 * @result: the file with expected result
Daniel Veillardfd110d22005-06-27 00:02:02 +00001759 * @err: the file with error messages: unused
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001760 *
1761 * Parse a file using the old xmlReadMemory API, then serialize back
1762 * reparse the result and serialize again, then check for deviation
1763 * in serialization.
1764 *
1765 * Returns 0 in case of success, an error code otherwise
1766 */
1767static int
Daniel Veillardc111c152005-06-27 08:22:10 +00001768memParseTest(const char *filename, const char *result,
1769 const char *err ATTRIBUTE_UNUSED,
1770 int options ATTRIBUTE_UNUSED) {
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001771 xmlDocPtr doc;
1772 const char *base;
Daniel Veillardfd110d22005-06-27 00:02:02 +00001773 int size, res;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001774
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001775 nb_tests++;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001776 /*
1777 * load and parse the memory
1778 */
1779 if (loadMem(filename, &base, &size) != 0) {
1780 fprintf(stderr, "Failed to load %s\n", filename);
1781 return(-1);
1782 }
1783
1784 doc = xmlReadMemory(base, size, filename, NULL, 0);
1785 unloadMem(base);
1786 if (doc == NULL) {
1787 return(1);
1788 }
Daniel Veillardfd110d22005-06-27 00:02:02 +00001789 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001790 xmlFreeDoc(doc);
Daniel Veillardfd110d22005-06-27 00:02:02 +00001791 res = compareFileMem(result, base, size);
1792 if ((base == NULL) || (res != 0)) {
1793 if (base != NULL)
1794 xmlFree((char *)base);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001795 fprintf(stderr, "Result for %s failed\n", filename);
1796 return(-1);
1797 }
Daniel Veillardfd110d22005-06-27 00:02:02 +00001798 xmlFree((char *)base);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001799 return(0);
1800}
1801
1802/**
1803 * noentParseTest:
1804 * @filename: the file to parse
1805 * @result: the file with expected result
Daniel Veillardfd110d22005-06-27 00:02:02 +00001806 * @err: the file with error messages: unused
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001807 *
1808 * Parse a file with entity resolution, then serialize back
1809 * reparse the result and serialize again, then check for deviation
1810 * in serialization.
1811 *
1812 * Returns 0 in case of success, an error code otherwise
1813 */
1814static int
Daniel Veillardc111c152005-06-27 08:22:10 +00001815noentParseTest(const char *filename, const char *result,
1816 const char *err ATTRIBUTE_UNUSED,
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001817 int options) {
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001818 xmlDocPtr doc;
1819 char *temp;
1820 int res = 0;
1821
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001822 nb_tests++;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001823 /*
1824 * base of the test, parse with the old API
1825 */
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001826 doc = xmlReadFile(filename, NULL, options);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001827 if (doc == NULL)
1828 return(1);
1829 temp = resultFilename(filename, "", ".res");
1830 if (temp == NULL) {
1831 fprintf(stderr, "Out of memory\n");
1832 fatalError();
1833 }
1834 xmlSaveFile(temp, doc);
1835 if (compareFiles(temp, result)) {
1836 res = 1;
1837 }
1838 xmlFreeDoc(doc);
1839
1840 /*
1841 * Parse the saved result to make sure the round trip is okay
1842 */
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001843 doc = xmlReadFile(filename, NULL, options);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00001844 if (doc == NULL)
1845 return(1);
1846 xmlSaveFile(temp, doc);
1847 if (compareFiles(temp, result)) {
1848 res = 1;
1849 }
1850 xmlFreeDoc(doc);
1851
1852 unlink(temp);
1853 free(temp);
1854 return(res);
1855}
1856
Daniel Veillardfd110d22005-06-27 00:02:02 +00001857/**
Daniel Veillardc111c152005-06-27 08:22:10 +00001858 * errParseTest:
Daniel Veillardfd110d22005-06-27 00:02:02 +00001859 * @filename: the file to parse
1860 * @result: the file with expected result
1861 * @err: the file with error messages
1862 *
1863 * Parse a file using the xmlReadFile API and check for errors.
1864 *
1865 * Returns 0 in case of success, an error code otherwise
1866 */
1867static int
Daniel Veillardc111c152005-06-27 08:22:10 +00001868errParseTest(const char *filename, const char *result, const char *err,
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001869 int options) {
Daniel Veillardfd110d22005-06-27 00:02:02 +00001870 xmlDocPtr doc;
Daniel Veillard970adf52005-06-27 16:40:10 +00001871 const char *base = NULL;
Daniel Veillarddbee0f12005-06-27 13:42:57 +00001872 int size, res = 0;
Daniel Veillardfd110d22005-06-27 00:02:02 +00001873
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001874 nb_tests++;
Daniel Veillardfc319af2005-06-27 12:44:55 +00001875#ifdef LIBXML_HTML_ENABLED
1876 if (options & XML_PARSE_HTML) {
1877 doc = htmlReadFile(filename, NULL, options);
1878 } else
1879#endif
Daniel Veillard970adf52005-06-27 16:40:10 +00001880#ifdef LIBXML_XINCLUDE_ENABLED
1881 if (options & XML_PARSE_XINCLUDE) {
1882 doc = xmlReadFile(filename, NULL, options);
1883 xmlXIncludeProcessFlags(doc, options);
1884 } else
1885#endif
Daniel Veillardfc319af2005-06-27 12:44:55 +00001886 {
1887 xmlGetWarningsDefaultValue = 1;
1888 doc = xmlReadFile(filename, NULL, options);
1889 }
Daniel Veillardfd110d22005-06-27 00:02:02 +00001890 xmlGetWarningsDefaultValue = 0;
Daniel Veillarddbee0f12005-06-27 13:42:57 +00001891 if (result) {
1892 if (doc == NULL) {
1893 base = "";
1894 size = 0;
1895 } else {
1896#ifdef LIBXML_HTML_ENABLED
1897 if (options & XML_PARSE_HTML) {
1898 htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1899 } else
1900#endif
1901 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1902 }
1903 res = compareFileMem(result, base, size);
1904 }
Daniel Veillardfd110d22005-06-27 00:02:02 +00001905 if (doc != NULL) {
1906 if (base != NULL)
1907 xmlFree((char *)base);
1908 xmlFreeDoc(doc);
1909 }
1910 if (res != 0) {
1911 fprintf(stderr, "Result for %s failed\n", filename);
1912 return(-1);
1913 }
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001914 if (err != NULL) {
1915 res = compareFileMem(err, testErrors, testErrorsSize);
1916 if (res != 0) {
1917 fprintf(stderr, "Error for %s failed\n", filename);
1918 return(-1);
1919 }
Daniel Veillarddbee0f12005-06-27 13:42:57 +00001920 } else if (options & XML_PARSE_DTDVALID) {
1921 if (testErrorsSize != 0)
1922 fprintf(stderr, "Validation for %s failed\n", filename);
Daniel Veillardfd110d22005-06-27 00:02:02 +00001923 }
1924
1925 return(0);
1926}
1927
Daniel Veillardc111c152005-06-27 08:22:10 +00001928#ifdef LIBXML_READER_ENABLED
Daniel Veillard4a5a9642005-06-27 10:40:55 +00001929/************************************************************************
1930 * *
1931 * Reader based tests *
1932 * *
1933 ************************************************************************/
1934
Daniel Veillardc111c152005-06-27 08:22:10 +00001935static void processNode(FILE *out, xmlTextReaderPtr reader) {
1936 const xmlChar *name, *value;
1937 int type, empty;
1938
1939 type = xmlTextReaderNodeType(reader);
1940 empty = xmlTextReaderIsEmptyElement(reader);
1941
1942 name = xmlTextReaderConstName(reader);
1943 if (name == NULL)
1944 name = BAD_CAST "--";
1945
1946 value = xmlTextReaderConstValue(reader);
1947
1948
1949 fprintf(out, "%d %d %s %d %d",
1950 xmlTextReaderDepth(reader),
1951 type,
1952 name,
1953 empty,
1954 xmlTextReaderHasValue(reader));
1955 if (value == NULL)
1956 fprintf(out, "\n");
1957 else {
1958 fprintf(out, " %s\n", value);
1959 }
Daniel Veillardc111c152005-06-27 08:22:10 +00001960}
Daniel Veillardc111c152005-06-27 08:22:10 +00001961static int
Daniel Veillardc950d702005-06-27 09:15:06 +00001962streamProcessTest(const char *filename, const char *result, const char *err,
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001963 xmlTextReaderPtr reader, const char *rng) {
Daniel Veillardc111c152005-06-27 08:22:10 +00001964 int ret;
1965 char *temp = NULL;
1966 FILE *t = NULL;
1967
Daniel Veillardc950d702005-06-27 09:15:06 +00001968 if (reader == NULL)
1969 return(-1);
1970
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001971 nb_tests++;
Daniel Veillardc111c152005-06-27 08:22:10 +00001972 if (result != NULL) {
1973 temp = resultFilename(filename, "", ".res");
1974 if (temp == NULL) {
1975 fprintf(stderr, "Out of memory\n");
1976 fatalError();
1977 }
1978 t = fopen(temp, "w");
1979 if (t == NULL) {
1980 fprintf(stderr, "Can't open temp file %s\n", temp);
1981 free(temp);
1982 return(-1);
1983 }
1984 }
Daniel Veillard95175012005-07-03 16:09:51 +00001985#ifdef LIBXML_SCHEMAS_ENABLED
Daniel Veillardf2e066a2005-06-30 13:04:44 +00001986 if (rng != NULL) {
1987 ret = xmlTextReaderRelaxNGValidate(reader, rng);
1988 if (ret < 0) {
1989 testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n",
1990 rng);
1991 fclose(t);
1992 unlink(temp);
1993 free(temp);
1994 return(0);
1995 }
1996 }
Daniel Veillard95175012005-07-03 16:09:51 +00001997#endif
Daniel Veillardc111c152005-06-27 08:22:10 +00001998 xmlGetWarningsDefaultValue = 1;
Daniel Veillardc111c152005-06-27 08:22:10 +00001999 ret = xmlTextReaderRead(reader);
2000 while (ret == 1) {
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002001 if ((t != NULL) && (rng == NULL))
Daniel Veillardc111c152005-06-27 08:22:10 +00002002 processNode(t, reader);
2003 ret = xmlTextReaderRead(reader);
2004 }
2005 if (ret != 0) {
2006 testErrorHandler(NULL, "%s : failed to parse\n", filename);
2007 }
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002008 if (rng != NULL) {
2009 if (xmlTextReaderIsValid(reader) != 1) {
2010 testErrorHandler(NULL, "%s fails to validate\n", filename);
2011 } else {
2012 testErrorHandler(NULL, "%s validates\n", filename);
2013 }
2014 }
Daniel Veillardc111c152005-06-27 08:22:10 +00002015 xmlGetWarningsDefaultValue = 0;
2016 if (t != NULL) {
2017 fclose(t);
2018 ret = compareFiles(temp, result);
2019 unlink(temp);
2020 free(temp);
2021 if (ret) {
2022 fprintf(stderr, "Result for %s failed\n", filename);
2023 return(-1);
2024 }
2025 }
2026 if (err != NULL) {
2027 ret = compareFileMem(err, testErrors, testErrorsSize);
2028 if (ret != 0) {
2029 fprintf(stderr, "Error for %s failed\n", filename);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002030 printf("%s", testErrors);
Daniel Veillardc111c152005-06-27 08:22:10 +00002031 return(-1);
2032 }
2033 }
2034
2035 return(0);
2036}
Daniel Veillardc950d702005-06-27 09:15:06 +00002037
2038/**
2039 * streamParseTest:
2040 * @filename: the file to parse
2041 * @result: the file with expected result
2042 * @err: the file with error messages
2043 *
2044 * Parse a file using the reader API and check for errors.
2045 *
2046 * Returns 0 in case of success, an error code otherwise
2047 */
2048static int
2049streamParseTest(const char *filename, const char *result, const char *err,
2050 int options) {
2051 xmlTextReaderPtr reader;
2052 int ret;
2053
2054 reader = xmlReaderForFile(filename, NULL, options);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002055 ret = streamProcessTest(filename, result, err, reader, NULL);
Daniel Veillardc950d702005-06-27 09:15:06 +00002056 xmlFreeTextReader(reader);
2057 return(ret);
2058}
2059
2060/**
2061 * walkerParseTest:
2062 * @filename: the file to parse
2063 * @result: the file with expected result
2064 * @err: the file with error messages
2065 *
2066 * Parse a file using the walker, i.e. a reader built from a atree.
2067 *
2068 * Returns 0 in case of success, an error code otherwise
2069 */
2070static int
2071walkerParseTest(const char *filename, const char *result, const char *err,
2072 int options) {
2073 xmlDocPtr doc;
2074 xmlTextReaderPtr reader;
2075 int ret;
2076
2077 doc = xmlReadFile(filename, NULL, options);
2078 if (doc == NULL) {
2079 fprintf(stderr, "Failed to parse %s\n", filename);
2080 return(-1);
2081 }
2082 reader = xmlReaderWalker(doc);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002083 ret = streamProcessTest(filename, result, err, reader, NULL);
Daniel Veillardc950d702005-06-27 09:15:06 +00002084 xmlFreeTextReader(reader);
2085 xmlFreeDoc(doc);
2086 return(ret);
2087}
2088
2089/**
2090 * streamMemParseTest:
2091 * @filename: the file to parse
2092 * @result: the file with expected result
2093 * @err: the file with error messages
2094 *
2095 * Parse a file using the reader API from memory and check for errors.
2096 *
2097 * Returns 0 in case of success, an error code otherwise
2098 */
2099static int
2100streamMemParseTest(const char *filename, const char *result, const char *err,
2101 int options) {
2102 xmlTextReaderPtr reader;
2103 int ret;
2104 const char *base;
2105 int size;
2106
2107 /*
2108 * load and parse the memory
2109 */
2110 if (loadMem(filename, &base, &size) != 0) {
2111 fprintf(stderr, "Failed to load %s\n", filename);
2112 return(-1);
2113 }
2114 reader = xmlReaderForMemory(base, size, filename, NULL, options);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002115 ret = streamProcessTest(filename, result, err, reader, NULL);
Daniel Veillardc950d702005-06-27 09:15:06 +00002116 free((char *)base);
2117 xmlFreeTextReader(reader);
2118 return(ret);
2119}
Daniel Veillardc111c152005-06-27 08:22:10 +00002120#endif
2121
Daniel Veillard970adf52005-06-27 16:40:10 +00002122#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard39e5c892005-07-03 22:48:50 +00002123#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard970adf52005-06-27 16:40:10 +00002124/************************************************************************
2125 * *
Daniel Veillard30564042005-06-28 07:30:41 +00002126 * XPath and XPointer based tests *
Daniel Veillard970adf52005-06-27 16:40:10 +00002127 * *
2128 ************************************************************************/
2129
2130FILE *xpathOutput;
2131xmlDocPtr xpathDocument;
2132
2133static void
2134testXPath(const char *str, int xptr, int expr) {
2135 xmlXPathObjectPtr res;
2136 xmlXPathContextPtr ctxt;
2137
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002138 nb_tests++;
Daniel Veillard970adf52005-06-27 16:40:10 +00002139#if defined(LIBXML_XPTR_ENABLED)
2140 if (xptr) {
2141 ctxt = xmlXPtrNewContext(xpathDocument, NULL, NULL);
2142 res = xmlXPtrEval(BAD_CAST str, ctxt);
2143 } else {
2144#endif
2145 ctxt = xmlXPathNewContext(xpathDocument);
2146 ctxt->node = xmlDocGetRootElement(xpathDocument);
2147 if (expr)
2148 res = xmlXPathEvalExpression(BAD_CAST str, ctxt);
2149 else {
2150 /* res = xmlXPathEval(BAD_CAST str, ctxt); */
2151 xmlXPathCompExprPtr comp;
2152
2153 comp = xmlXPathCompile(BAD_CAST str);
2154 if (comp != NULL) {
2155 res = xmlXPathCompiledEval(comp, ctxt);
2156 xmlXPathFreeCompExpr(comp);
2157 } else
2158 res = NULL;
2159 }
2160#if defined(LIBXML_XPTR_ENABLED)
2161 }
2162#endif
2163 xmlXPathDebugDumpObject(xpathOutput, res, 0);
2164 xmlXPathFreeObject(res);
2165 xmlXPathFreeContext(ctxt);
2166}
Daniel Veillard54a203c2005-06-27 22:29:56 +00002167
Daniel Veillard970adf52005-06-27 16:40:10 +00002168/**
2169 * xpathExprTest:
2170 * @filename: the file to parse
2171 * @result: the file with expected result
2172 * @err: the file with error messages
2173 *
2174 * Parse a file containing XPath standalone expressions and evaluate them
2175 *
2176 * Returns 0 in case of success, an error code otherwise
2177 */
2178static int
Daniel Veillard54a203c2005-06-27 22:29:56 +00002179xpathCommonTest(const char *filename, const char *result,
2180 int xptr, int expr) {
Daniel Veillard970adf52005-06-27 16:40:10 +00002181 FILE *input;
2182 char expression[5000];
2183 int len, ret = 0;
2184 char *temp;
2185
2186 temp = resultFilename(filename, "", ".res");
2187 if (temp == NULL) {
2188 fprintf(stderr, "Out of memory\n");
2189 fatalError();
2190 }
2191 xpathOutput = fopen(temp, "w");
2192 if (xpathOutput == NULL) {
2193 fprintf(stderr, "failed to open output file %s\n", temp);
2194 free(temp);
2195 return(-1);
2196 }
2197
2198 input = fopen(filename, "r");
2199 if (input == NULL) {
2200 xmlGenericError(xmlGenericErrorContext,
2201 "Cannot open %s for reading\n", filename);
2202 free(temp);
2203 return(-1);
2204 }
2205 while (fgets(expression, 4500, input) != NULL) {
2206 len = strlen(expression);
2207 len--;
2208 while ((len >= 0) &&
2209 ((expression[len] == '\n') || (expression[len] == '\t') ||
2210 (expression[len] == '\r') || (expression[len] == ' '))) len--;
2211 expression[len + 1] = 0;
2212 if (len >= 0) {
2213 fprintf(xpathOutput,
2214 "\n========================\nExpression: %s\n",
2215 expression) ;
Daniel Veillard54a203c2005-06-27 22:29:56 +00002216 testXPath(expression, xptr, expr);
Daniel Veillard970adf52005-06-27 16:40:10 +00002217 }
2218 }
2219
2220 fclose(input);
2221 fclose(xpathOutput);
2222 if (result != NULL) {
2223 ret = compareFiles(temp, result);
2224 if (ret) {
2225 fprintf(stderr, "Result for %s failed\n", filename);
2226 }
2227 }
2228
2229 unlink(temp);
2230 free(temp);
2231 return(ret);
2232}
Daniel Veillard54a203c2005-06-27 22:29:56 +00002233
2234/**
2235 * xpathExprTest:
2236 * @filename: the file to parse
2237 * @result: the file with expected result
2238 * @err: the file with error messages
2239 *
2240 * Parse a file containing XPath standalone expressions and evaluate them
2241 *
2242 * Returns 0 in case of success, an error code otherwise
2243 */
2244static int
2245xpathExprTest(const char *filename, const char *result,
2246 const char *err ATTRIBUTE_UNUSED,
2247 int options ATTRIBUTE_UNUSED) {
2248 return(xpathCommonTest(filename, result, 0, 1));
2249}
2250
2251/**
2252 * xpathDocTest:
2253 * @filename: the file to parse
2254 * @result: the file with expected result
2255 * @err: the file with error messages
2256 *
2257 * Parse a file containing XPath expressions and evaluate them against
2258 * a set of corresponding documents.
2259 *
2260 * Returns 0 in case of success, an error code otherwise
2261 */
2262static int
2263xpathDocTest(const char *filename,
2264 const char *resul ATTRIBUTE_UNUSED,
2265 const char *err ATTRIBUTE_UNUSED,
2266 int options) {
2267
2268 char pattern[500];
2269 char result[500];
2270 glob_t globbuf;
2271 size_t i;
2272 int ret = 0, res;
2273
2274 xpathDocument = xmlReadFile(filename, NULL,
2275 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2276 if (xpathDocument == NULL) {
2277 fprintf(stderr, "Failed to load %s\n", filename);
2278 return(-1);
2279 }
2280
2281 snprintf(pattern, 499, "./test/XPath/tests/%s*", baseFilename(filename));
2282 pattern[499] = 0;
2283 globbuf.gl_offs = 0;
2284 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2285 for (i = 0;i < globbuf.gl_pathc;i++) {
2286 snprintf(result, 499, "result/XPath/tests/%s",
2287 baseFilename(globbuf.gl_pathv[i]));
2288 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 0, 0);
2289 if (res != 0)
2290 ret = res;
2291 }
2292 globfree(&globbuf);
2293
2294 xmlFreeDoc(xpathDocument);
2295 return(ret);
2296}
2297
2298#ifdef LIBXML_XPTR_ENABLED
2299/**
2300 * xptrDocTest:
2301 * @filename: the file to parse
2302 * @result: the file with expected result
2303 * @err: the file with error messages
2304 *
2305 * Parse a file containing XPath expressions and evaluate them against
2306 * a set of corresponding documents.
2307 *
2308 * Returns 0 in case of success, an error code otherwise
2309 */
2310static int
2311xptrDocTest(const char *filename,
2312 const char *resul ATTRIBUTE_UNUSED,
2313 const char *err ATTRIBUTE_UNUSED,
2314 int options) {
2315
2316 char pattern[500];
2317 char result[500];
2318 glob_t globbuf;
2319 size_t i;
2320 int ret = 0, res;
2321
2322 xpathDocument = xmlReadFile(filename, NULL,
2323 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2324 if (xpathDocument == NULL) {
2325 fprintf(stderr, "Failed to load %s\n", filename);
2326 return(-1);
2327 }
2328
2329 snprintf(pattern, 499, "./test/XPath/xptr/%s*", baseFilename(filename));
2330 pattern[499] = 0;
2331 globbuf.gl_offs = 0;
2332 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2333 for (i = 0;i < globbuf.gl_pathc;i++) {
2334 snprintf(result, 499, "result/XPath/xptr/%s",
2335 baseFilename(globbuf.gl_pathv[i]));
2336 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 1, 0);
2337 if (res != 0)
2338 ret = res;
2339 }
2340 globfree(&globbuf);
2341
2342 xmlFreeDoc(xpathDocument);
2343 return(ret);
2344}
2345#endif /* LIBXML_XPTR_ENABLED */
Daniel Veillard48dec9d2005-06-27 22:56:11 +00002346
2347/**
2348 * xmlidDocTest:
2349 * @filename: the file to parse
2350 * @result: the file with expected result
2351 * @err: the file with error messages
2352 *
2353 * Parse a file containing xml:id and check for errors and verify
2354 * that XPath queries will work on them as expected.
2355 *
2356 * Returns 0 in case of success, an error code otherwise
2357 */
2358static int
2359xmlidDocTest(const char *filename,
2360 const char *result,
2361 const char *err,
2362 int options) {
2363
2364 int res = 0;
2365 int ret = 0;
2366 char *temp;
2367
2368 xpathDocument = xmlReadFile(filename, NULL,
2369 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2370 if (xpathDocument == NULL) {
2371 fprintf(stderr, "Failed to load %s\n", filename);
2372 return(-1);
2373 }
2374
2375 temp = resultFilename(filename, "", ".res");
2376 if (temp == NULL) {
2377 fprintf(stderr, "Out of memory\n");
2378 fatalError();
2379 }
2380 xpathOutput = fopen(temp, "w");
2381 if (xpathOutput == NULL) {
2382 fprintf(stderr, "failed to open output file %s\n", temp);
2383 xmlFreeDoc(xpathDocument);
2384 free(temp);
2385 return(-1);
2386 }
2387
2388 testXPath("id('bar')", 0, 0);
2389
2390 fclose(xpathOutput);
2391 if (result != NULL) {
2392 ret = compareFiles(temp, result);
2393 if (ret) {
2394 fprintf(stderr, "Result for %s failed\n", filename);
2395 res = 1;
2396 }
2397 }
2398
2399 unlink(temp);
2400 free(temp);
2401 xmlFreeDoc(xpathDocument);
2402
2403 if (err != NULL) {
2404 ret = compareFileMem(err, testErrors, testErrorsSize);
2405 if (ret != 0) {
2406 fprintf(stderr, "Error for %s failed\n", filename);
2407 res = 1;
2408 }
2409 }
2410 return(res);
2411}
2412
Daniel Veillard39e5c892005-07-03 22:48:50 +00002413#endif /* LIBXML_DEBUG_ENABLED */
Daniel Veillard970adf52005-06-27 16:40:10 +00002414#endif /* XPATH */
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00002415/************************************************************************
2416 * *
Daniel Veillard30564042005-06-28 07:30:41 +00002417 * URI based tests *
2418 * *
2419 ************************************************************************/
2420
2421static void
2422handleURI(const char *str, const char *base, FILE *o) {
2423 int ret;
2424 xmlURIPtr uri;
2425 xmlChar *res = NULL, *parsed = NULL;
2426
2427 uri = xmlCreateURI();
2428
2429 if (base == NULL) {
2430 ret = xmlParseURIReference(uri, str);
2431 if (ret != 0)
2432 fprintf(o, "%s : error %d\n", str, ret);
2433 else {
2434 xmlNormalizeURIPath(uri->path);
2435 xmlPrintURI(o, uri);
2436 fprintf(o, "\n");
2437 }
2438 } else {
2439 res = xmlBuildURI((xmlChar *)str, (xmlChar *) base);
2440 if (res != NULL) {
2441 fprintf(o, "%s\n", (char *) res);
2442 }
2443 else
2444 fprintf(o, "::ERROR::\n");
2445 }
2446 if (res != NULL)
2447 xmlFree(res);
2448 if (parsed != NULL)
2449 xmlFree(parsed);
2450 xmlFreeURI(uri);
2451}
2452
2453/**
2454 * uriCommonTest:
2455 * @filename: the file to parse
2456 * @result: the file with expected result
2457 * @err: the file with error messages
2458 *
2459 * Parse a file containing URI and check for errors
2460 *
2461 * Returns 0 in case of success, an error code otherwise
2462 */
2463static int
2464uriCommonTest(const char *filename,
2465 const char *result,
2466 const char *err,
2467 const char *base) {
2468 char *temp;
2469 FILE *o, *f;
2470 char str[1024];
2471 int res = 0, i, ret;
2472
2473 temp = resultFilename(filename, "", ".res");
2474 if (temp == NULL) {
2475 fprintf(stderr, "Out of memory\n");
2476 fatalError();
2477 }
2478 o = fopen(temp, "w");
2479 if (o == NULL) {
2480 fprintf(stderr, "failed to open output file %s\n", temp);
2481 free(temp);
2482 return(-1);
2483 }
2484 f = fopen(filename, "r");
2485 if (f == NULL) {
2486 fprintf(stderr, "failed to open input file %s\n", filename);
2487 fclose(o);
2488 unlink(temp);
2489 free(temp);
2490 return(-1);
2491 }
2492
2493 while (1) {
2494 /*
2495 * read one line in string buffer.
2496 */
2497 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
2498 break;
2499
2500 /*
2501 * remove the ending spaces
2502 */
2503 i = strlen(str);
2504 while ((i > 0) &&
2505 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
2506 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
2507 i--;
2508 str[i] = 0;
2509 }
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002510 nb_tests++;
Daniel Veillard30564042005-06-28 07:30:41 +00002511 handleURI(str, base, o);
2512 }
2513
2514 fclose(f);
2515 fclose(o);
2516
2517 if (result != NULL) {
2518 ret = compareFiles(temp, result);
2519 if (ret) {
2520 fprintf(stderr, "Result for %s failed\n", filename);
2521 res = 1;
2522 }
2523 }
2524 if (err != NULL) {
2525 ret = compareFileMem(err, testErrors, testErrorsSize);
2526 if (ret != 0) {
2527 fprintf(stderr, "Error for %s failed\n", filename);
2528 res = 1;
2529 }
2530 }
2531
2532 unlink(temp);
2533 free(temp);
2534 return(res);
2535}
2536
2537/**
2538 * uriParseTest:
2539 * @filename: the file to parse
2540 * @result: the file with expected result
2541 * @err: the file with error messages
2542 *
2543 * Parse a file containing URI and check for errors
2544 *
2545 * Returns 0 in case of success, an error code otherwise
2546 */
2547static int
2548uriParseTest(const char *filename,
2549 const char *result,
2550 const char *err,
2551 int options ATTRIBUTE_UNUSED) {
2552 return(uriCommonTest(filename, result, err, NULL));
2553}
2554
2555/**
2556 * uriBaseTest:
2557 * @filename: the file to parse
2558 * @result: the file with expected result
2559 * @err: the file with error messages
2560 *
2561 * Parse a file containing URI, compose them against a fixed base and
2562 * check for errors
2563 *
2564 * Returns 0 in case of success, an error code otherwise
2565 */
2566static int
2567uriBaseTest(const char *filename,
2568 const char *result,
2569 const char *err,
2570 int options ATTRIBUTE_UNUSED) {
2571 return(uriCommonTest(filename, result, err,
2572 "http://foo.com/path/to/index.html?orig#help"));
2573}
2574
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002575#ifdef LIBXML_SCHEMAS_ENABLED
2576/************************************************************************
2577 * *
2578 * Schemas tests *
2579 * *
2580 ************************************************************************/
2581static int
2582schemasOneTest(const char *sch,
2583 const char *filename,
2584 const char *result,
2585 const char *err,
2586 int options,
2587 xmlSchemaPtr schemas) {
2588 xmlDocPtr doc;
2589 xmlSchemaValidCtxtPtr ctxt;
2590 int ret = 0;
2591 char *temp;
2592 FILE *schemasOutput;
2593
2594 doc = xmlReadFile(filename, NULL, options);
2595 if (doc == NULL) {
2596 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
2597 return(-1);
2598 }
2599
2600 temp = resultFilename(result, "", ".res");
2601 if (temp == NULL) {
2602 fprintf(stderr, "Out of memory\n");
2603 fatalError();
2604 }
2605 schemasOutput = fopen(temp, "w");
2606 if (schemasOutput == NULL) {
2607 fprintf(stderr, "failed to open output file %s\n", temp);
2608 xmlFreeDoc(doc);
2609 free(temp);
2610 return(-1);
2611 }
2612
2613 ctxt = xmlSchemaNewValidCtxt(schemas);
2614 xmlSchemaSetValidErrors(ctxt,
2615 (xmlSchemaValidityErrorFunc) testErrorHandler,
2616 (xmlSchemaValidityWarningFunc) testErrorHandler,
2617 ctxt);
2618 ret = xmlSchemaValidateDoc(ctxt, doc);
2619 if (ret == 0) {
2620 fprintf(schemasOutput, "%s validates\n", filename);
2621 } else if (ret > 0) {
2622 fprintf(schemasOutput, "%s fails to validate\n", filename);
2623 } else {
2624 fprintf(schemasOutput, "%s validation generated an internal error\n",
2625 filename);
2626 }
2627 fclose(schemasOutput);
2628 if (result) {
2629 if (compareFiles(temp, result)) {
2630 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
2631 ret = 1;
2632 }
2633 }
2634 unlink(temp);
2635 free(temp);
2636
2637 if (err != NULL) {
2638 if (compareFileMem(err, testErrors, testErrorsSize)) {
2639 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
2640 ret = 1;
2641 }
2642 }
2643
2644
2645 xmlSchemaFreeValidCtxt(ctxt);
2646 xmlFreeDoc(doc);
2647 return(ret);
2648}
2649/**
2650 * schemasTest:
2651 * @filename: the schemas file
2652 * @result: the file with expected result
2653 * @err: the file with error messages
2654 *
2655 * Parse a file containing URI, compose them against a fixed base and
2656 * check for errors
2657 *
2658 * Returns 0 in case of success, an error code otherwise
2659 */
2660static int
2661schemasTest(const char *filename,
2662 const char *resul ATTRIBUTE_UNUSED,
2663 const char *errr ATTRIBUTE_UNUSED,
2664 int options) {
2665 const char *base = baseFilename(filename);
2666 const char *base2;
2667 const char *instance;
2668 xmlSchemaParserCtxtPtr ctxt;
2669 xmlSchemaPtr schemas;
2670 int res = 0, len, ret;
2671 char pattern[500];
2672 char prefix[500];
2673 char result[500];
2674 char err[500];
2675 glob_t globbuf;
2676 size_t i;
2677 char count = 0;
2678
2679 /* first compile the schemas if possible */
2680 ctxt = xmlSchemaNewParserCtxt(filename);
2681 xmlSchemaSetParserErrors(ctxt,
2682 (xmlSchemaValidityErrorFunc) testErrorHandler,
2683 (xmlSchemaValidityWarningFunc) testErrorHandler,
2684 ctxt);
2685 schemas = xmlSchemaParse(ctxt);
2686 xmlSchemaFreeParserCtxt(ctxt);
2687
2688 /*
2689 * most of the mess is about the output filenames generated by the Makefile
2690 */
2691 len = strlen(base);
2692 if ((len > 499) || (len < 5)) {
2693 xmlSchemaFree(schemas);
2694 return(-1);
2695 }
2696 len -= 4; /* remove trailing .xsd */
2697 if (base[len - 2] == '_') {
2698 len -= 2; /* remove subtest number */
2699 }
2700 if (base[len - 2] == '_') {
2701 len -= 2; /* remove subtest number */
2702 }
2703 memcpy(prefix, base, len);
2704 prefix[len] = 0;
2705
2706 snprintf(pattern, 499, "./test/schemas/%s_?.xml", prefix);
2707 pattern[499] = 0;
2708
2709 if (base[len] == '_') {
2710 len += 2;
2711 memcpy(prefix, base, len);
2712 prefix[len] = 0;
2713 }
2714
2715 globbuf.gl_offs = 0;
2716 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2717 for (i = 0;i < globbuf.gl_pathc;i++) {
2718 testErrorsSize = 0;
2719 testErrors[0] = 0;
2720 instance = globbuf.gl_pathv[i];
2721 base2 = baseFilename(instance);
2722 len = strlen(base2);
2723 if ((len > 6) && (base2[len - 6] == '_')) {
2724 count = base2[len - 5];
2725 snprintf(result, 499, "result/schemas/%s_%c",
2726 prefix, count);
2727 result[499] = 0;
2728 snprintf(err, 499, "result/schemas/%s_%c.err",
2729 prefix, count);
2730 err[499] = 0;
2731 } else {
2732 fprintf(stderr, "don't know how to process %s\n", instance);
2733 continue;
2734 }
2735 if (schemas == NULL) {
2736 } else {
2737 nb_tests++;
2738 ret = schemasOneTest(filename, instance, result, err,
2739 options, schemas);
2740 if (res != 0)
2741 ret = res;
2742 }
2743 }
2744 globfree(&globbuf);
2745 xmlSchemaFree(schemas);
2746
2747 return(res);
2748}
2749
2750/************************************************************************
2751 * *
2752 * Schemas tests *
2753 * *
2754 ************************************************************************/
2755static int
2756rngOneTest(const char *sch,
2757 const char *filename,
2758 const char *result,
2759 const char *err,
2760 int options,
2761 xmlRelaxNGPtr schemas) {
2762 xmlDocPtr doc;
2763 xmlRelaxNGValidCtxtPtr ctxt;
2764 int ret = 0;
2765 char *temp;
2766 FILE *schemasOutput;
2767
2768 doc = xmlReadFile(filename, NULL, options);
2769 if (doc == NULL) {
2770 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
2771 return(-1);
2772 }
2773
2774 temp = resultFilename(result, "", ".res");
2775 if (temp == NULL) {
2776 fprintf(stderr, "Out of memory\n");
2777 fatalError();
2778 }
2779 schemasOutput = fopen(temp, "w");
2780 if (schemasOutput == NULL) {
2781 fprintf(stderr, "failed to open output file %s\n", temp);
2782 xmlFreeDoc(doc);
2783 free(temp);
2784 return(-1);
2785 }
2786
2787 ctxt = xmlRelaxNGNewValidCtxt(schemas);
2788 xmlRelaxNGSetValidErrors(ctxt,
2789 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
2790 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
2791 ctxt);
2792 ret = xmlRelaxNGValidateDoc(ctxt, doc);
2793 if (ret == 0) {
2794 testErrorHandler(NULL, "%s validates\n", filename);
2795 } else if (ret > 0) {
2796 testErrorHandler(NULL, "%s fails to validate\n", filename);
2797 } else {
2798 testErrorHandler(NULL, "%s validation generated an internal error\n",
2799 filename);
2800 }
2801 fclose(schemasOutput);
2802 if (result) {
2803 if (compareFiles(temp, result)) {
2804 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
2805 ret = 1;
2806 }
2807 }
2808 unlink(temp);
2809 free(temp);
2810
2811 if (err != NULL) {
2812 if (compareFileMem(err, testErrors, testErrorsSize)) {
2813 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
2814 ret = 1;
2815 printf("%s", testErrors);
2816 }
2817 }
2818
2819
2820 xmlRelaxNGFreeValidCtxt(ctxt);
2821 xmlFreeDoc(doc);
2822 return(ret);
2823}
2824/**
2825 * rngTest:
2826 * @filename: the schemas file
2827 * @result: the file with expected result
2828 * @err: the file with error messages
2829 *
2830 * Parse an RNG schemas and then apply it to the related .xml
2831 *
2832 * Returns 0 in case of success, an error code otherwise
2833 */
2834static int
2835rngTest(const char *filename,
2836 const char *resul ATTRIBUTE_UNUSED,
2837 const char *errr ATTRIBUTE_UNUSED,
2838 int options) {
2839 const char *base = baseFilename(filename);
2840 const char *base2;
2841 const char *instance;
2842 xmlRelaxNGParserCtxtPtr ctxt;
2843 xmlRelaxNGPtr schemas;
2844 int res = 0, len, ret;
2845 char pattern[500];
2846 char prefix[500];
2847 char result[500];
2848 char err[500];
2849 glob_t globbuf;
2850 size_t i;
2851 char count = 0;
2852
2853 /* first compile the schemas if possible */
2854 ctxt = xmlRelaxNGNewParserCtxt(filename);
2855 xmlRelaxNGSetParserErrors(ctxt,
2856 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
2857 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
2858 ctxt);
2859 schemas = xmlRelaxNGParse(ctxt);
2860 xmlRelaxNGFreeParserCtxt(ctxt);
2861
2862 /*
2863 * most of the mess is about the output filenames generated by the Makefile
2864 */
2865 len = strlen(base);
2866 if ((len > 499) || (len < 5)) {
2867 xmlRelaxNGFree(schemas);
2868 return(-1);
2869 }
2870 len -= 4; /* remove trailing .rng */
2871 memcpy(prefix, base, len);
2872 prefix[len] = 0;
2873
2874 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
2875 pattern[499] = 0;
2876
2877 globbuf.gl_offs = 0;
2878 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2879 for (i = 0;i < globbuf.gl_pathc;i++) {
2880 testErrorsSize = 0;
2881 testErrors[0] = 0;
2882 instance = globbuf.gl_pathv[i];
2883 base2 = baseFilename(instance);
2884 len = strlen(base2);
2885 if ((len > 6) && (base2[len - 6] == '_')) {
2886 count = base2[len - 5];
2887 snprintf(result, 499, "result/relaxng/%s_%c",
2888 prefix, count);
2889 result[499] = 0;
2890 snprintf(err, 499, "result/relaxng/%s_%c.err",
2891 prefix, count);
2892 err[499] = 0;
2893 } else {
2894 fprintf(stderr, "don't know how to process %s\n", instance);
2895 continue;
2896 }
2897 if (schemas == NULL) {
2898 } else {
2899 nb_tests++;
2900 ret = rngOneTest(filename, instance, result, err,
2901 options, schemas);
2902 if (res != 0)
2903 ret = res;
2904 }
2905 }
2906 globfree(&globbuf);
2907 xmlRelaxNGFree(schemas);
2908
2909 return(res);
2910}
2911
Daniel Veillard39e5c892005-07-03 22:48:50 +00002912#ifdef LIBXML_READER_ENABLED
Daniel Veillardf2e066a2005-06-30 13:04:44 +00002913/**
2914 * rngStreamTest:
2915 * @filename: the schemas file
2916 * @result: the file with expected result
2917 * @err: the file with error messages
2918 *
2919 * Parse a set of files with streaming, applying an RNG schemas
2920 *
2921 * Returns 0 in case of success, an error code otherwise
2922 */
2923static int
2924rngStreamTest(const char *filename,
2925 const char *resul ATTRIBUTE_UNUSED,
2926 const char *errr ATTRIBUTE_UNUSED,
2927 int options) {
2928 const char *base = baseFilename(filename);
2929 const char *base2;
2930 const char *instance;
2931 int res = 0, len, ret;
2932 char pattern[500];
2933 char prefix[500];
2934 char result[500];
2935 char err[500];
2936 glob_t globbuf;
2937 size_t i;
2938 char count = 0;
2939 xmlTextReaderPtr reader;
2940 int disable_err = 0;
2941
2942 /*
2943 * most of the mess is about the output filenames generated by the Makefile
2944 */
2945 len = strlen(base);
2946 if ((len > 499) || (len < 5)) {
2947 fprintf(stderr, "len(base) == %d !\n", len);
2948 return(-1);
2949 }
2950 len -= 4; /* remove trailing .rng */
2951 memcpy(prefix, base, len);
2952 prefix[len] = 0;
2953
2954 /*
2955 * strictly unifying the error messages is nearly impossible this
2956 * hack is also done in the Makefile
2957 */
2958 if ((!strcmp(prefix, "tutor10_1")) || (!strcmp(prefix, "tutor10_2")) ||
2959 (!strcmp(prefix, "tutor3_2")))
2960 disable_err = 1;
2961
2962 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
2963 pattern[499] = 0;
2964
2965 globbuf.gl_offs = 0;
2966 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2967 for (i = 0;i < globbuf.gl_pathc;i++) {
2968 testErrorsSize = 0;
2969 testErrors[0] = 0;
2970 instance = globbuf.gl_pathv[i];
2971 base2 = baseFilename(instance);
2972 len = strlen(base2);
2973 if ((len > 6) && (base2[len - 6] == '_')) {
2974 count = base2[len - 5];
2975 snprintf(result, 499, "result/relaxng/%s_%c",
2976 prefix, count);
2977 result[499] = 0;
2978 snprintf(err, 499, "result/relaxng/%s_%c.err",
2979 prefix, count);
2980 err[499] = 0;
2981 } else {
2982 fprintf(stderr, "don't know how to process %s\n", instance);
2983 continue;
2984 }
2985 reader = xmlReaderForFile(instance, NULL, options);
2986 if (reader == NULL) {
2987 fprintf(stderr, "Failed to build reder for %s\n", instance);
2988 }
2989 if (disable_err == 1)
2990 ret = streamProcessTest(instance, result, NULL, reader, filename);
2991 else
2992 ret = streamProcessTest(instance, result, err, reader, filename);
2993 xmlFreeTextReader(reader);
2994 if (ret != 0) {
2995 fprintf(stderr, "instance %s failed\n", instance);
2996 res = ret;
2997 }
2998 }
2999 globfree(&globbuf);
3000
3001 return(res);
3002}
Daniel Veillard39e5c892005-07-03 22:48:50 +00003003#endif /* READER */
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003004
3005#endif
3006
3007#ifdef LIBXML_PATTERN_ENABLED
Daniel Veillard39e5c892005-07-03 22:48:50 +00003008#ifdef LIBXML_READER_ENABLED
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003009/************************************************************************
3010 * *
3011 * Patterns tests *
3012 * *
3013 ************************************************************************/
3014static void patternNode(FILE *out, xmlTextReaderPtr reader,
3015 const char *pattern, xmlPatternPtr patternc,
3016 xmlStreamCtxtPtr patstream) {
3017 xmlChar *path = NULL;
3018 int match = -1;
3019 int type, empty;
3020
3021 type = xmlTextReaderNodeType(reader);
3022 empty = xmlTextReaderIsEmptyElement(reader);
3023
3024 if (type == XML_READER_TYPE_ELEMENT) {
3025 /* do the check only on element start */
3026 match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader));
3027
3028 if (match) {
3029 path = xmlGetNodePath(xmlTextReaderCurrentNode(reader));
3030 fprintf(out, "Node %s matches pattern %s\n", path, pattern);
3031 }
3032 }
3033 if (patstream != NULL) {
3034 int ret;
3035
3036 if (type == XML_READER_TYPE_ELEMENT) {
3037 ret = xmlStreamPush(patstream,
3038 xmlTextReaderConstLocalName(reader),
3039 xmlTextReaderConstNamespaceUri(reader));
3040 if (ret < 0) {
3041 fprintf(out, "xmlStreamPush() failure\n");
3042 xmlFreeStreamCtxt(patstream);
3043 patstream = NULL;
3044 } else if (ret != match) {
3045 if (path == NULL) {
3046 path = xmlGetNodePath(
3047 xmlTextReaderCurrentNode(reader));
3048 }
3049 fprintf(out,
3050 "xmlPatternMatch and xmlStreamPush disagree\n");
3051 fprintf(out,
3052 " pattern %s node %s\n",
3053 pattern, path);
3054 }
3055
3056
3057 }
3058 if ((type == XML_READER_TYPE_END_ELEMENT) ||
3059 ((type == XML_READER_TYPE_ELEMENT) && (empty))) {
3060 ret = xmlStreamPop(patstream);
3061 if (ret < 0) {
3062 fprintf(out, "xmlStreamPop() failure\n");
3063 xmlFreeStreamCtxt(patstream);
3064 patstream = NULL;
3065 }
3066 }
3067 }
3068 if (path != NULL)
3069 xmlFree(path);
3070}
3071
3072/**
3073 * patternTest:
3074 * @filename: the schemas file
3075 * @result: the file with expected result
3076 * @err: the file with error messages
3077 *
3078 * Parse a set of files with streaming, applying an RNG schemas
3079 *
3080 * Returns 0 in case of success, an error code otherwise
3081 */
3082static int
3083patternTest(const char *filename,
3084 const char *resul ATTRIBUTE_UNUSED,
3085 const char *err ATTRIBUTE_UNUSED,
3086 int options) {
3087 xmlPatternPtr patternc = NULL;
3088 xmlStreamCtxtPtr patstream = NULL;
3089 FILE *o, *f;
3090 char str[1024];
3091 char xml[500];
3092 char result[500];
3093 int len, i;
3094 int ret = 0, res;
3095 char *temp;
3096 xmlTextReaderPtr reader;
3097 xmlDocPtr doc;
3098
3099 len = strlen(filename);
3100 len -= 4;
3101 memcpy(xml, filename, len);
3102 xml[len] = 0;
3103 snprintf(result, 499, "result/pattern/%s", baseFilename(xml));
3104 result[499] = 0;
3105 memcpy(xml + len, ".xml", 5);
3106
3107 if (!checkTestFile(xml)) {
3108 fprintf(stderr, "Missing xml file %s\n", xml);
3109 return(-1);
3110 }
3111 if (!checkTestFile(result)) {
3112 fprintf(stderr, "Missing result file %s\n", result);
3113 return(-1);
3114 }
3115 f = fopen(filename, "r");
3116 if (f == NULL) {
3117 fprintf(stderr, "Failed to open %s\n", filename);
3118 return(-1);
3119 }
3120 temp = resultFilename(filename, "", ".res");
3121 if (temp == NULL) {
3122 fprintf(stderr, "Out of memory\n");
3123 fatalError();
3124 }
3125 o = fopen(temp, "w");
3126 if (o == NULL) {
3127 fprintf(stderr, "failed to open output file %s\n", temp);
3128 fclose(f);
3129 free(temp);
3130 return(-1);
3131 }
3132 while (1) {
3133 /*
3134 * read one line in string buffer.
3135 */
3136 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
3137 break;
3138
3139 /*
3140 * remove the ending spaces
3141 */
3142 i = strlen(str);
3143 while ((i > 0) &&
3144 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
3145 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
3146 i--;
3147 str[i] = 0;
3148 }
3149 doc = xmlReadFile(xml, NULL, options);
3150 if (doc == NULL) {
3151 fprintf(stderr, "Failed to parse %s\n", xml);
3152 ret = 1;
3153 } else {
3154 xmlNodePtr root;
3155 const xmlChar *namespaces[22];
3156 int j;
3157 xmlNsPtr ns;
3158
3159 root = xmlDocGetRootElement(doc);
3160 for (ns = root->nsDef, j = 0;ns != NULL && j < 20;ns=ns->next) {
3161 namespaces[j++] = ns->href;
3162 namespaces[j++] = ns->prefix;
3163 }
3164 namespaces[j++] = NULL;
3165 namespaces[j++] = NULL;
3166
3167 patternc = xmlPatterncompile((const xmlChar *) str, doc->dict,
3168 0, &namespaces[0]);
3169 if (patternc == NULL) {
3170 testErrorHandler(NULL,
3171 "Pattern %s failed to compile\n", str);
3172 xmlFreeDoc(doc);
3173 ret = 1;
3174 continue;
3175 }
3176 patstream = xmlPatternGetStreamCtxt(patternc);
3177 if (patstream != NULL) {
3178 ret = xmlStreamPush(patstream, NULL, NULL);
3179 if (ret < 0) {
3180 fprintf(stderr, "xmlStreamPush() failure\n");
3181 xmlFreeStreamCtxt(patstream);
3182 patstream = NULL;
3183 }
3184 }
3185 nb_tests++;
3186
3187 reader = xmlReaderWalker(doc);
3188 res = xmlTextReaderRead(reader);
3189 while (res == 1) {
3190 patternNode(o, reader, str, patternc, patstream);
3191 res = xmlTextReaderRead(reader);
3192 }
3193 if (res != 0) {
3194 fprintf(o, "%s : failed to parse\n", filename);
3195 }
3196 xmlFreeTextReader(reader);
3197 xmlFreeDoc(doc);
3198 xmlFreeStreamCtxt(patstream);
3199 patstream = NULL;
3200 xmlFreePattern(patternc);
3201
3202 }
3203 }
3204
3205 fclose(f);
3206 fclose(o);
3207
3208 ret = compareFiles(temp, result);
3209 if (ret) {
3210 fprintf(stderr, "Result for %s failed\n", filename);
3211 ret = 1;
3212 }
3213 unlink(temp);
3214 free(temp);
3215 return(ret);
3216}
Daniel Veillard39e5c892005-07-03 22:48:50 +00003217#endif /* READER */
3218#endif /* PATTERN */
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003219#ifdef LIBXML_C14N_ENABLED
3220/************************************************************************
3221 * *
3222 * Canonicalization tests *
3223 * *
3224 ************************************************************************/
3225static xmlXPathObjectPtr
3226load_xpath_expr (xmlDocPtr parent_doc, const char* filename) {
3227 xmlXPathObjectPtr xpath;
3228 xmlDocPtr doc;
3229 xmlChar *expr;
3230 xmlXPathContextPtr ctx;
3231 xmlNodePtr node;
3232 xmlNsPtr ns;
3233
3234 /*
3235 * load XPath expr as a file
3236 */
3237 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3238 xmlSubstituteEntitiesDefault(1);
3239
3240 doc = xmlParseFile(filename);
3241 if (doc == NULL) {
3242 fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
3243 return(NULL);
3244 }
3245
3246 /*
3247 * Check the document is of the right kind
3248 */
3249 if(xmlDocGetRootElement(doc) == NULL) {
3250 fprintf(stderr,"Error: empty document for file \"%s\"\n", filename);
3251 xmlFreeDoc(doc);
3252 return(NULL);
3253 }
3254
3255 node = doc->children;
3256 while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) {
3257 node = node->next;
3258 }
3259
3260 if(node == NULL) {
3261 fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename);
3262 xmlFreeDoc(doc);
3263 return(NULL);
3264 }
3265
3266 expr = xmlNodeGetContent(node);
3267 if(expr == NULL) {
3268 fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename);
3269 xmlFreeDoc(doc);
3270 return(NULL);
3271 }
3272
3273 ctx = xmlXPathNewContext(parent_doc);
3274 if(ctx == NULL) {
3275 fprintf(stderr,"Error: unable to create new context\n");
3276 xmlFree(expr);
3277 xmlFreeDoc(doc);
3278 return(NULL);
3279 }
3280
3281 /*
3282 * Register namespaces
3283 */
3284 ns = node->nsDef;
3285 while(ns != NULL) {
3286 if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) {
3287 fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", ns->prefix, ns->href);
3288 xmlFree(expr);
3289 xmlXPathFreeContext(ctx);
3290 xmlFreeDoc(doc);
3291 return(NULL);
3292 }
3293 ns = ns->next;
3294 }
3295
3296 /*
3297 * Evaluate xpath
3298 */
3299 xpath = xmlXPathEvalExpression(expr, ctx);
3300 if(xpath == NULL) {
3301 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3302 xmlFree(expr);
3303 xmlXPathFreeContext(ctx);
3304 xmlFreeDoc(doc);
3305 return(NULL);
3306 }
3307
3308 /* print_xpath_nodes(xpath->nodesetval); */
3309
3310 xmlFree(expr);
3311 xmlXPathFreeContext(ctx);
3312 xmlFreeDoc(doc);
3313 return(xpath);
3314}
3315
3316/*
3317 * Macro used to grow the current buffer.
3318 */
3319#define xxx_growBufferReentrant() { \
3320 buffer_size *= 2; \
3321 buffer = (xmlChar **) \
3322 xmlRealloc(buffer, buffer_size * sizeof(xmlChar*)); \
3323 if (buffer == NULL) { \
3324 perror("realloc failed"); \
3325 return(NULL); \
3326 } \
3327}
3328
3329static xmlChar **
3330parse_list(xmlChar *str) {
3331 xmlChar **buffer;
3332 xmlChar **out = NULL;
3333 int buffer_size = 0;
3334 int len;
3335
3336 if(str == NULL) {
3337 return(NULL);
3338 }
3339
3340 len = xmlStrlen(str);
3341 if((str[0] == '\'') && (str[len - 1] == '\'')) {
3342 str[len - 1] = '\0';
3343 str++;
3344 len -= 2;
3345 }
3346 /*
3347 * allocate an translation buffer.
3348 */
3349 buffer_size = 1000;
3350 buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*));
3351 if (buffer == NULL) {
3352 perror("malloc failed");
3353 return(NULL);
3354 }
3355 out = buffer;
3356
3357 while(*str != '\0') {
3358 if (out - buffer > buffer_size - 10) {
3359 int indx = out - buffer;
3360
3361 xxx_growBufferReentrant();
3362 out = &buffer[indx];
3363 }
3364 (*out++) = str;
3365 while(*str != ',' && *str != '\0') ++str;
3366 if(*str == ',') *(str++) = '\0';
3367 }
3368 (*out) = NULL;
3369 return buffer;
3370}
3371
3372static int
3373c14nRunTest(const char* xml_filename, int with_comments, int exclusive,
3374 const char* xpath_filename, const char *ns_filename,
3375 const char* result_file) {
3376 xmlDocPtr doc;
3377 xmlXPathObjectPtr xpath = NULL;
3378 xmlChar *result = NULL;
3379 int ret;
3380 xmlChar **inclusive_namespaces = NULL;
3381 const char *nslist = NULL;
3382 int nssize;
3383
3384
3385 /*
3386 * build an XML tree from a the file; we need to add default
3387 * attributes and resolve all character and entities references
3388 */
3389 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3390 xmlSubstituteEntitiesDefault(1);
3391
3392 doc = xmlParseFile(xml_filename);
3393 if (doc == NULL) {
3394 fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename);
3395 return(-1);
3396 }
3397
3398 /*
3399 * Check the document is of the right kind
3400 */
3401 if(xmlDocGetRootElement(doc) == NULL) {
3402 fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename);
3403 xmlFreeDoc(doc);
3404 return(-1);
3405 }
3406
3407 /*
3408 * load xpath file if specified
3409 */
3410 if(xpath_filename) {
3411 xpath = load_xpath_expr(doc, xpath_filename);
3412 if(xpath == NULL) {
3413 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3414 xmlFreeDoc(doc);
3415 return(-1);
3416 }
3417 }
3418
3419 if (ns_filename != NULL) {
3420 if (loadMem(ns_filename, &nslist, &nssize)) {
3421 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3422 if(xpath != NULL) xmlXPathFreeObject(xpath);
3423 xmlFreeDoc(doc);
3424 return(-1);
3425 }
3426 inclusive_namespaces = parse_list((xmlChar *) nslist);
3427 }
3428
3429 /*
3430 * Canonical form
3431 */
3432 /* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */
3433 ret = xmlC14NDocDumpMemory(doc,
3434 (xpath) ? xpath->nodesetval : NULL,
3435 exclusive, inclusive_namespaces,
3436 with_comments, &result);
3437 if (ret >= 0) {
3438 if(result != NULL) {
3439 if (compareFileMem(result_file, (const char *) result, ret)) {
3440 fprintf(stderr, "Result mismatch for %s\n", xml_filename);
3441 ret = -1;
3442 }
3443 }
3444 } else {
3445 fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret);
3446 ret = -1;
3447 }
3448
3449 /*
3450 * Cleanup
3451 */
3452 if (result != NULL) xmlFree(result);
3453 if(xpath != NULL) xmlXPathFreeObject(xpath);
3454 if (inclusive_namespaces != NULL) xmlFree(inclusive_namespaces);
3455 if (nslist != NULL) free((char *) nslist);
3456 xmlFreeDoc(doc);
3457
3458 return(ret);
3459}
3460
3461static int
3462c14nCommonTest(const char *filename, int with_comments, int exclusive,
3463 const char *subdir) {
3464 char buf[500];
3465 char prefix[500];
3466 const char *base;
3467 int len;
3468 char *result = NULL;
3469 char *xpath = NULL;
3470 char *ns = NULL;
3471 int ret = 0;
3472
3473 base = baseFilename(filename);
3474 len = strlen(base);
3475 len -= 4;
3476 memcpy(prefix, base, len);
3477 prefix[len] = 0;
3478
3479 snprintf(buf, 499, "result/c14n/%s/%s", subdir,prefix);
3480 if (!checkTestFile(buf)) {
3481 fprintf(stderr, "Missing result file %s", buf);
3482 return(-1);
3483 }
3484 result = strdup(buf);
3485 snprintf(buf, 499, "test/c14n/%s/%s.xpath", subdir,prefix);
3486 if (checkTestFile(buf)) {
3487 xpath = strdup(buf);
3488 }
3489 snprintf(buf, 499, "test/c14n/%s/%s.ns", subdir,prefix);
3490 if (checkTestFile(buf)) {
3491 ns = strdup(buf);
3492 }
3493
3494 nb_tests++;
3495 if (c14nRunTest(filename, with_comments, exclusive,
3496 xpath, ns, result) < 0)
3497 ret = 1;
3498
3499 if (result != NULL) free(result);
3500 if (xpath != NULL) free(xpath);
3501 if (ns != NULL) free(ns);
3502 return(ret);
3503}
3504
3505static int
3506c14nWithCommentTest(const char *filename,
3507 const char *resul ATTRIBUTE_UNUSED,
3508 const char *err ATTRIBUTE_UNUSED,
3509 int options ATTRIBUTE_UNUSED) {
3510 return(c14nCommonTest(filename, 1, 0, "with-comments"));
3511}
3512static int
3513c14nWithoutCommentTest(const char *filename,
3514 const char *resul ATTRIBUTE_UNUSED,
3515 const char *err ATTRIBUTE_UNUSED,
3516 int options ATTRIBUTE_UNUSED) {
3517 return(c14nCommonTest(filename, 0, 0, "without-comments"));
3518}
3519static int
3520c14nExcWithoutCommentTest(const char *filename,
3521 const char *resul ATTRIBUTE_UNUSED,
3522 const char *err ATTRIBUTE_UNUSED,
3523 int options ATTRIBUTE_UNUSED) {
3524 return(c14nCommonTest(filename, 0, 1, "exc-without-comments"));
3525}
3526#endif
3527#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
3528/************************************************************************
3529 * *
3530 * Catalog and threads test *
3531 * *
3532 ************************************************************************/
3533
3534/*
3535 * mostly a cut and paste from testThreads.c
3536 */
3537#define MAX_ARGC 20
3538
3539static const char *catalog = "test/threads/complex.xml";
3540static const char *testfiles[] = {
3541 "test/threads/abc.xml",
3542 "test/threads/acb.xml",
3543 "test/threads/bac.xml",
3544 "test/threads/bca.xml",
3545 "test/threads/cab.xml",
3546 "test/threads/cba.xml",
3547 "test/threads/invalid.xml",
3548};
3549
3550const char *Okay = "OK";
3551const char *Failed = "Failed";
3552
3553#ifndef xmlDoValidityCheckingDefaultValue
3554#error xmlDoValidityCheckingDefaultValue is not a macro
3555#endif
3556#ifndef xmlGenericErrorContext
3557#error xmlGenericErrorContext is not a macro
3558#endif
3559
3560static void *
3561thread_specific_data(void *private_data)
3562{
3563 xmlDocPtr myDoc;
3564 const char *filename = (const char *) private_data;
3565 int okay = 1;
3566
3567 if (!strcmp(filename, "test/threads/invalid.xml")) {
3568 xmlDoValidityCheckingDefaultValue = 0;
3569 xmlGenericErrorContext = stdout;
3570 } else {
3571 xmlDoValidityCheckingDefaultValue = 1;
3572 xmlGenericErrorContext = stderr;
3573 }
3574 myDoc = xmlParseFile(filename);
3575 if (myDoc) {
3576 xmlFreeDoc(myDoc);
3577 } else {
3578 printf("parse failed\n");
3579 okay = 0;
3580 }
3581 if (!strcmp(filename, "test/threads/invalid.xml")) {
3582 if (xmlDoValidityCheckingDefaultValue != 0) {
3583 printf("ValidityCheckingDefaultValue override failed\n");
3584 okay = 0;
3585 }
3586 if (xmlGenericErrorContext != stdout) {
3587 printf("xmlGenericErrorContext override failed\n");
3588 okay = 0;
3589 }
3590 } else {
3591 if (xmlDoValidityCheckingDefaultValue != 1) {
3592 printf("ValidityCheckingDefaultValue override failed\n");
3593 okay = 0;
3594 }
3595 if (xmlGenericErrorContext != stderr) {
3596 printf("xmlGenericErrorContext override failed\n");
3597 okay = 0;
3598 }
3599 }
3600 if (okay == 0)
3601 return ((void *) Failed);
3602 return ((void *) Okay);
3603}
3604
3605#if defined(linux) || defined(solaris)
3606
3607#include <pthread.h>
3608
3609static pthread_t tid[MAX_ARGC];
3610
3611static int
3612testThread(void)
3613{
3614 unsigned int i, repeat;
3615 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
3616 void *results[MAX_ARGC];
3617 int ret;
3618 int res = 0;
3619
3620 xmlInitParser();
3621
3622 for (repeat = 0; repeat < 500; repeat++) {
3623 xmlLoadCatalog(catalog);
3624 nb_tests++;
3625
3626 nb_tests++;
3627 for (i = 0; i < num_threads; i++) {
3628 results[i] = NULL;
3629 tid[i] = (pthread_t) - 1;
3630 }
3631
3632 for (i = 0; i < num_threads; i++) {
3633 ret = pthread_create(&tid[i], 0, thread_specific_data,
3634 (void *) testfiles[i]);
3635 if (ret != 0) {
3636 fprintf(stderr, "pthread_create failed\n");
3637 return (1);
3638 }
3639 }
3640 for (i = 0; i < num_threads; i++) {
3641 ret = pthread_join(tid[i], &results[i]);
3642 if (ret != 0) {
3643 fprintf(stderr, "pthread_join failed\n");
3644 return (1);
3645 }
3646 }
3647
3648 xmlCatalogCleanup();
3649 for (i = 0; i < num_threads; i++)
3650 if (results[i] != (void *) Okay) {
3651 fprintf(stderr, "Thread %d handling %s failed\n",
3652 i, testfiles[i]);
3653 res = 1;
3654 }
3655 }
3656 return (res);
3657}
3658
3659#elif defined WIN32
3660#include <windows.h>
3661#include <string.h>
3662
3663static HANDLE tid[MAX_ARGC];
3664
3665static DWORD WINAPI
3666win32_thread_specific_data(void *private_data)
3667{
3668 return((DWORD) thread_specific_data());
3669}
3670
3671static int
3672testThread(void)
3673{
3674 unsigned int i, repeat;
3675 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
3676 DWORD results[MAX_ARGC];
3677 BOOL ret;
3678 int res = 0;
3679
3680 xmlInitParser();
3681 for (repeat = 0; repeat < TEST_REPEAT_COUNT; repeat++) {
3682 xmlLoadCatalog(catalog);
3683
3684 for (i = 0; i < num_threads; i++) {
3685 results[i] = 0;
3686 tid[i] = (HANDLE) - 1;
3687 }
3688
3689 for (i = 0; i < num_threads; i++) {
3690 DWORD useless;
3691
3692 tid[i] = CreateThread(NULL, 0,
3693 win32_thread_specific_data, testfiles[i], 0,
3694 &useless);
3695 if (tid[i] == NULL) {
3696 fprintf(stderr, "CreateThread failed\n");
3697 return(1);
3698 }
3699 }
3700
3701 if (WaitForMultipleObjects(num_threads, tid, TRUE, INFINITE) ==
3702 WAIT_FAILED) {
3703 fprintf(stderr, "WaitForMultipleObjects failed\n");
3704 return(1);
3705 }
3706
3707 for (i = 0; i < num_threads; i++) {
3708 ret = GetExitCodeThread(tid[i], &results[i]);
3709 if (ret == 0) {
3710 fprintf(stderr, "GetExitCodeThread failed\n");
3711 return(1);
3712 }
3713 CloseHandle(tid[i]);
3714 }
3715
3716 xmlCatalogCleanup();
3717 for (i = 0; i < num_threads; i++) {
3718 if (results[i] != (DWORD) Okay) {
3719 fprintf(stderr, "Thread %d handling %s failed\n",
3720 i, testfiles[i]);
3721 res = 1;
3722 }
3723 }
3724 }
3725
3726 return (res);
3727}
3728
3729#elif defined __BEOS__
3730#include <OS.h>
3731
3732static thread_id tid[MAX_ARGC];
3733
3734static int
3735testThread(void)
3736{
3737 unsigned int i, repeat;
3738 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
3739 void *results[MAX_ARGC];
3740 status_t ret;
3741 int res = 0;
3742
3743 xmlInitParser();
3744 for (repeat = 0; repeat < 500; repeat++) {
3745 xmlLoadCatalog(catalog);
3746 for (i = 0; i < num_threads; i++) {
3747 results[i] = NULL;
3748 tid[i] = (thread_id) - 1;
3749 }
3750 for (i = 0; i < num_threads; i++) {
3751 tid[i] =
3752 spawn_thread(thread_specific_data, "xmlTestThread",
3753 B_NORMAL_PRIORITY, (void *) testfiles[i]);
3754 if (tid[i] < B_OK) {
3755 fprintf(stderr, "beos_thread_create failed\n");
3756 return (1);
3757 }
3758 printf("beos_thread_create %d -> %d\n", i, tid[i]);
3759 }
3760 for (i = 0; i < num_threads; i++) {
3761 ret = wait_for_thread(tid[i], &results[i]);
3762 printf("beos_thread_wait %d -> %d\n", i, ret);
3763 if (ret != B_OK) {
3764 fprintf(stderr, "beos_thread_wait failed\n");
3765 return (1);
3766 }
3767 }
3768
3769 xmlCatalogCleanup();
3770 ret = B_OK;
3771 for (i = 0; i < num_threads; i++)
3772 if (results[i] != (void *) Okay) {
3773 printf("Thread %d handling %s failed\n", i, testfiles[i]);
3774 ret = B_ERROR;
3775 }
3776 }
3777 if (ret != B_OK)
3778 return(1);
3779 return (0);
3780}
3781#else
3782static int
3783testThread(void)
3784{
3785 fprintf(stderr,
3786 "Specific platform thread support not detected\n");
3787 return (-1);
3788}
3789#endif
3790static int
3791threadsTest(const char *filename ATTRIBUTE_UNUSED,
3792 const char *resul ATTRIBUTE_UNUSED,
3793 const char *err ATTRIBUTE_UNUSED,
3794 int options ATTRIBUTE_UNUSED) {
3795 return(testThread());
3796}
3797#endif
Daniel Veillard30564042005-06-28 07:30:41 +00003798/************************************************************************
3799 * *
3800 * Tests Descriptions *
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00003801 * *
3802 ************************************************************************/
3803
3804static
3805testDesc testDescriptions[] = {
Daniel Veillardfd110d22005-06-27 00:02:02 +00003806 { "XML regression tests" ,
Daniel Veillardc111c152005-06-27 08:22:10 +00003807 oldParseTest, "./test/*", "result/", "", NULL,
3808 0 },
Daniel Veillardfd110d22005-06-27 00:02:02 +00003809 { "XML regression tests on memory" ,
Daniel Veillardc111c152005-06-27 08:22:10 +00003810 memParseTest, "./test/*", "result/", "", NULL,
3811 0 },
Daniel Veillardfd110d22005-06-27 00:02:02 +00003812 { "XML entity subst regression tests" ,
Daniel Veillardc111c152005-06-27 08:22:10 +00003813 noentParseTest, "./test/*", "result/noent/", "", NULL,
Daniel Veillard4a5a9642005-06-27 10:40:55 +00003814 XML_PARSE_NOENT },
Daniel Veillardfd110d22005-06-27 00:02:02 +00003815 { "XML Namespaces regression tests",
Daniel Veillardc111c152005-06-27 08:22:10 +00003816 errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err",
3817 0 },
Daniel Veillardfd110d22005-06-27 00:02:02 +00003818 { "Error cases regression tests",
Daniel Veillardc111c152005-06-27 08:22:10 +00003819 errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err",
3820 0 },
3821#ifdef LIBXML_READER_ENABLED
3822 { "Error cases stream regression tests",
3823 streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str",
3824 0 },
3825 { "Reader regression tests",
3826 streamParseTest, "./test/*", "result/", ".rdr", NULL,
3827 0 },
3828 { "Reader entities substitution regression tests",
3829 streamParseTest, "./test/*", "result/", ".rde", NULL,
3830 XML_PARSE_NOENT },
Daniel Veillardc950d702005-06-27 09:15:06 +00003831 { "Reader on memory regression tests",
3832 streamMemParseTest, "./test/*", "result/", ".rdr", NULL,
3833 0 },
3834 { "Walker regression tests",
3835 walkerParseTest, "./test/*", "result/", ".rdr", NULL,
3836 0 },
Daniel Veillardc111c152005-06-27 08:22:10 +00003837#endif
Daniel Veillard6b6d6802005-07-03 21:00:34 +00003838#ifdef LIBXML_SAX1_ENABLED
Daniel Veillard4a5a9642005-06-27 10:40:55 +00003839 { "SAX1 callbacks regression tests" ,
3840 saxParseTest, "./test/*", "result/", ".sax", NULL,
3841 XML_PARSE_SAX1 },
3842 { "SAX2 callbacks regression tests" ,
3843 saxParseTest, "./test/*", "result/", ".sax2", NULL,
3844 0 },
Daniel Veillard6b6d6802005-07-03 21:00:34 +00003845#endif
Daniel Veillardfc319af2005-06-27 12:44:55 +00003846#ifdef LIBXML_PUSH_ENABLED
3847 { "XML push regression tests" ,
3848 pushParseTest, "./test/*", "result/", "", NULL,
3849 0 },
3850#endif
3851#ifdef LIBXML_HTML_ENABLED
3852 { "HTML regression tests" ,
3853 errParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
3854 XML_PARSE_HTML },
3855#ifdef LIBXML_PUSH_ENABLED
3856 { "Push HTML regression tests" ,
3857 pushParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
3858 XML_PARSE_HTML },
3859#endif
Daniel Veillard6b6d6802005-07-03 21:00:34 +00003860#ifdef LIBXML_SAX1_ENABLED
Daniel Veillardfc319af2005-06-27 12:44:55 +00003861 { "HTML SAX regression tests" ,
3862 saxParseTest, "./test/HTML/*", "result/HTML/", ".sax", NULL,
3863 XML_PARSE_HTML },
3864#endif
Daniel Veillard6b6d6802005-07-03 21:00:34 +00003865#endif
Daniel Veillarddbee0f12005-06-27 13:42:57 +00003866#ifdef LIBXML_VALID_ENABLED
3867 { "Valid documents regression tests" ,
3868 errParseTest, "./test/VCM/*", NULL, NULL, NULL,
3869 XML_PARSE_DTDVALID },
3870 { "Validity checking regression tests" ,
3871 errParseTest, "./test/VC/*", "result/VC/", NULL, "",
3872 XML_PARSE_DTDVALID },
3873 { "General documents valid regression tests" ,
3874 errParseTest, "./test/valid/*", "result/valid/", "", ".err",
3875 XML_PARSE_DTDVALID },
3876#endif
Daniel Veillard970adf52005-06-27 16:40:10 +00003877#ifdef LIBXML_XINCLUDE_ENABLED
3878 { "XInclude regression tests" ,
3879 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
3880 /* Ignore errors at this point ".err", */
3881 XML_PARSE_XINCLUDE },
3882 { "XInclude xmlReader regression tests",
3883 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
3884 /* Ignore errors at this point ".err", */
3885 NULL, XML_PARSE_XINCLUDE },
3886 { "XInclude regression tests stripping include nodes" ,
3887 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
3888 /* Ignore errors at this point ".err", */
3889 XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
3890 { "XInclude xmlReader regression tests stripping include nodes",
3891 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
3892 /* Ignore errors at this point ".err", */
3893 NULL, XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
3894#endif
3895#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard39e5c892005-07-03 22:48:50 +00003896#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard970adf52005-06-27 16:40:10 +00003897 { "XPath expressions regression tests" ,
3898 xpathExprTest, "./test/XPath/expr/*", "result/XPath/expr/", "", NULL,
3899 0 },
Daniel Veillard54a203c2005-06-27 22:29:56 +00003900 { "XPath document queries regression tests" ,
3901 xpathDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
3902 0 },
3903#ifdef LIBXML_XPTR_ENABLED
3904 { "XPointer document queries regression tests" ,
3905 xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
3906 0 },
3907#endif
Daniel Veillard48dec9d2005-06-27 22:56:11 +00003908 { "xml:id regression tests" ,
3909 xmlidDocTest, "./test/xmlid/*", "result/xmlid/", "", ".err",
3910 0 },
Daniel Veillard970adf52005-06-27 16:40:10 +00003911#endif
Daniel Veillard39e5c892005-07-03 22:48:50 +00003912#endif
Daniel Veillard30564042005-06-28 07:30:41 +00003913 { "URI parsing tests" ,
3914 uriParseTest, "./test/URI/*.uri", "result/URI/", "", NULL,
3915 0 },
3916 { "URI base composition tests" ,
3917 uriBaseTest, "./test/URI/*.data", "result/URI/", "", NULL,
3918 0 },
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003919#ifdef LIBXML_SCHEMAS_ENABLED
3920 { "Schemas regression tests" ,
3921 schemasTest, "./test/schemas/*_*.xsd", NULL, NULL, NULL,
3922 0 },
3923 { "Relax-NG regression tests" ,
3924 rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
3925 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
Daniel Veillard39e5c892005-07-03 22:48:50 +00003926#ifdef LIBXML_READER_ENABLED
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003927 { "Relax-NG streaming regression tests" ,
3928 rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
3929 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
3930#endif
Daniel Veillard39e5c892005-07-03 22:48:50 +00003931#endif
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003932#ifdef LIBXML_PATTERN_ENABLED
Daniel Veillard39e5c892005-07-03 22:48:50 +00003933#ifdef LIBXML_READER_ENABLED
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003934 { "Pattern regression tests" ,
3935 patternTest, "./test/pattern/*.pat", "result/pattern/", NULL, NULL,
3936 0 },
3937#endif
Daniel Veillard39e5c892005-07-03 22:48:50 +00003938#endif
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003939#ifdef LIBXML_C14N_ENABLED
3940 { "C14N with comments regression tests" ,
3941 c14nWithCommentTest, "./test/c14n/with-comments/*.xml", NULL, NULL, NULL,
3942 0 },
3943 { "C14N without comments regression tests" ,
3944 c14nWithoutCommentTest, "./test/c14n/without-comments/*.xml", NULL, NULL, NULL,
3945 0 },
3946 { "C14N exclusive without comments regression tests" ,
3947 c14nExcWithoutCommentTest, "./test/c14n/exc-without-comments/*.xml", NULL, NULL, NULL,
3948 0 },
3949#endif
3950#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
3951 { "Catalog and Threads regression tests" ,
3952 threadsTest, NULL, NULL, NULL, NULL,
3953 0 },
3954#endif
Daniel Veillardc111c152005-06-27 08:22:10 +00003955 {NULL, NULL, NULL, NULL, NULL, NULL, 0}
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00003956};
3957
3958/************************************************************************
3959 * *
Daniel Veillard4a5a9642005-06-27 10:40:55 +00003960 * The main code driving the tests *
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00003961 * *
3962 ************************************************************************/
3963
3964static int
3965launchTests(testDescPtr tst) {
3966 int res = 0, err = 0;
3967 size_t i;
3968 char *result;
Daniel Veillardfd110d22005-06-27 00:02:02 +00003969 char *error;
Daniel Veillardf2e066a2005-06-30 13:04:44 +00003970 int mem;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00003971
3972 if (tst == NULL) return(-1);
3973 if (tst->in != NULL) {
3974 glob_t globbuf;
3975
3976 globbuf.gl_offs = 0;
3977 glob(tst->in, GLOB_DOOFFS, NULL, &globbuf);
3978 for (i = 0;i < globbuf.gl_pathc;i++) {
3979 if (!checkTestFile(globbuf.gl_pathv[i]))
3980 continue;
Daniel Veillardfd110d22005-06-27 00:02:02 +00003981 if (tst->suffix != NULL) {
3982 result = resultFilename(globbuf.gl_pathv[i], tst->out,
3983 tst->suffix);
3984 if (result == NULL) {
3985 fprintf(stderr, "Out of memory !\n");
3986 fatalError();
3987 }
3988 } else {
3989 result = NULL;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00003990 }
Daniel Veillardfd110d22005-06-27 00:02:02 +00003991 if (tst->err != NULL) {
3992 error = resultFilename(globbuf.gl_pathv[i], tst->out,
3993 tst->err);
3994 if (error == NULL) {
3995 fprintf(stderr, "Out of memory !\n");
3996 fatalError();
3997 }
3998 } else {
3999 error = NULL;
4000 }
4001 if ((result) &&(!checkTestFile(result))) {
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004002 fprintf(stderr, "Missing result file %s\n", result);
Daniel Veillardfd110d22005-06-27 00:02:02 +00004003 } else if ((error) &&(!checkTestFile(error))) {
4004 fprintf(stderr, "Missing error file %s\n", error);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004005 } else {
4006 mem = xmlMemUsed();
4007 extraMemoryFromResolver = 0;
Daniel Veillardfd110d22005-06-27 00:02:02 +00004008 testErrorsSize = 0;
4009 testErrors[0] = 0;
Daniel Veillardc111c152005-06-27 08:22:10 +00004010 res = tst->func(globbuf.gl_pathv[i], result, error,
4011 tst->options);
Daniel Veillardfc319af2005-06-27 12:44:55 +00004012 xmlResetLastError();
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004013 if (res != 0) {
4014 fprintf(stderr, "File %s generated an error\n",
4015 globbuf.gl_pathv[i]);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004016 nb_errors++;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004017 err++;
4018 }
4019 else if (xmlMemUsed() != mem) {
Daniel Veillardfd110d22005-06-27 00:02:02 +00004020 if ((xmlMemUsed() != mem) &&
4021 (extraMemoryFromResolver == 0)) {
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004022 fprintf(stderr, "File %s leaked %d bytes\n",
4023 globbuf.gl_pathv[i], xmlMemUsed() - mem);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004024 nb_leaks++;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004025 err++;
4026 }
4027 }
Daniel Veillardfd110d22005-06-27 00:02:02 +00004028 testErrorsSize = 0;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004029 }
Daniel Veillardfd110d22005-06-27 00:02:02 +00004030 if (result)
4031 free(result);
4032 if (error)
4033 free(error);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004034 }
Daniel Veillard54a203c2005-06-27 22:29:56 +00004035 globfree(&globbuf);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004036 } else {
Daniel Veillardfd110d22005-06-27 00:02:02 +00004037 testErrorsSize = 0;
4038 testErrors[0] = 0;
4039 extraMemoryFromResolver = 0;
Daniel Veillardc111c152005-06-27 08:22:10 +00004040 res = tst->func(NULL, NULL, NULL, tst->options);
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004041 if (res != 0) {
4042 nb_errors++;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004043 err++;
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004044 }
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004045 }
4046 return(err);
4047}
4048
4049int
Daniel Veillardc111c152005-06-27 08:22:10 +00004050main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004051 int i = 0, res, ret = 0;
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004052 int verbose = 0;
4053 int old_errors, old_tests, old_leaks;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004054
4055 initializeLibxml2();
4056
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004057 if ((argc >= 2) && (!strcmp(argv[1], "-v")))
4058 verbose = 1;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004059 for (i = 0; testDescriptions[i].func != NULL; i++) {
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004060 old_errors = nb_errors;
4061 old_tests = nb_tests;
4062 old_leaks = nb_leaks;
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004063 if (testDescriptions[i].desc != NULL)
4064 printf("## %s\n", testDescriptions[i].desc);
4065 res = launchTests(&testDescriptions[i]);
4066 if (res != 0)
4067 ret++;
Daniel Veillardf2e066a2005-06-30 13:04:44 +00004068 if (verbose) {
4069 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
4070 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
4071 else
4072 printf("Ran %d tests, %d errors, %d leaks\n",
4073 nb_tests - old_tests,
4074 nb_errors - old_errors,
4075 nb_leaks - old_leaks);
4076 }
4077 }
4078 if ((nb_errors == 0) && (nb_leaks == 0)) {
4079 ret = 0;
4080 printf("Total %d tests, no errors\n",
4081 nb_tests);
4082 } else {
4083 ret = 1;
4084 printf("Total %d tests, %d errors, %d leaks\n",
4085 nb_tests, nb_errors, nb_leaks);
Daniel Veillard1b75c3b2005-06-26 21:49:08 +00004086 }
4087 xmlCleanupParser();
4088 xmlMemoryDump();
4089
4090 return(ret);
4091}
Daniel Veillard6b6d6802005-07-03 21:00:34 +00004092
4093#else /* ! LIBXML_OUTPUT_ENABLED */
4094int
4095main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
4096 fprintf(stderr, "runtest requires output to be enabled in libxml2\n");
4097 return(1);
4098}
4099#endif