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