blob: cf0fb63a3829ee1a600f2420926071ae535607b8 [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);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000620 if ((res1 != res2) || (res1 < 0)) {
William M. Brackca15a542005-07-06 20:41:33 +0000621 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;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002548 xmlChar *res = NULL;
William M. Brackca15a542005-07-06 20:41:33 +00002549
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);
William M. Brackca15a542005-07-06 20:41:33 +00002571 xmlFreeURI(uri);
2572}
2573
2574/**
2575 * uriCommonTest:
2576 * @filename: the file to parse
2577 * @result: the file with expected result
2578 * @err: the file with error messages
2579 *
2580 * Parse a file containing URI and check for errors
2581 *
2582 * Returns 0 in case of success, an error code otherwise
2583 */
2584static int
2585uriCommonTest(const char *filename,
2586 const char *result,
2587 const char *err,
2588 const char *base) {
2589 char *temp;
2590 FILE *o, *f;
2591 char str[1024];
2592 int res = 0, i, ret;
2593
2594 temp = resultFilename(filename, "", ".res");
2595 if (temp == NULL) {
2596 fprintf(stderr, "Out of memory\n");
2597 fatalError();
2598 }
2599 o = fopen(temp, "wb");
2600 if (o == NULL) {
2601 fprintf(stderr, "failed to open output file %s\n", temp);
2602 free(temp);
2603 return(-1);
2604 }
2605 f = fopen(filename, "rb");
2606 if (f == NULL) {
2607 fprintf(stderr, "failed to open input file %s\n", filename);
2608 fclose(o);
2609 unlink(temp);
2610 free(temp);
2611 return(-1);
2612 }
2613
2614 while (1) {
2615 /*
2616 * read one line in string buffer.
2617 */
2618 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
2619 break;
2620
2621 /*
2622 * remove the ending spaces
2623 */
2624 i = strlen(str);
2625 while ((i > 0) &&
2626 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
2627 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
2628 i--;
2629 str[i] = 0;
2630 }
2631 nb_tests++;
2632 handleURI(str, base, o);
2633 }
2634
2635 fclose(f);
2636 fclose(o);
2637
2638 if (result != NULL) {
2639 ret = compareFiles(temp, result);
2640 if (ret) {
2641 fprintf(stderr, "Result for %s failed\n", filename);
2642 res = 1;
2643 }
2644 }
2645 if (err != NULL) {
2646 ret = compareFileMem(err, testErrors, testErrorsSize);
2647 if (ret != 0) {
2648 fprintf(stderr, "Error for %s failed\n", filename);
2649 res = 1;
2650 }
2651 }
2652
2653 unlink(temp);
2654 free(temp);
2655 return(res);
2656}
2657
2658/**
2659 * uriParseTest:
2660 * @filename: the file to parse
2661 * @result: the file with expected result
2662 * @err: the file with error messages
2663 *
2664 * Parse a file containing URI and check for errors
2665 *
2666 * Returns 0 in case of success, an error code otherwise
2667 */
2668static int
2669uriParseTest(const char *filename,
2670 const char *result,
2671 const char *err,
2672 int options ATTRIBUTE_UNUSED) {
2673 return(uriCommonTest(filename, result, err, NULL));
2674}
2675
2676/**
2677 * uriBaseTest:
2678 * @filename: the file to parse
2679 * @result: the file with expected result
2680 * @err: the file with error messages
2681 *
2682 * Parse a file containing URI, compose them against a fixed base and
2683 * check for errors
2684 *
2685 * Returns 0 in case of success, an error code otherwise
2686 */
2687static int
2688uriBaseTest(const char *filename,
2689 const char *result,
2690 const char *err,
2691 int options ATTRIBUTE_UNUSED) {
2692 return(uriCommonTest(filename, result, err,
2693 "http://foo.com/path/to/index.html?orig#help"));
2694}
2695
Daniel Veillard336a8e12005-08-07 10:46:19 +00002696static int urip_success = 1;
2697static int urip_current = 0;
2698static const char *urip_testURLs[] = {
2699 "urip://example.com/a b.html",
2700 "urip://example.com/a%20b.html",
2701 "file:///path/to/a b.html",
2702 "file:///path/to/a%20b.html",
2703 "/path/to/a b.html",
2704 "/path/to/a%20b.html",
2705 "urip://example.com/résumé.html",
2706 "urip://example.com/test?a=1&b=2%263&c=4#foo",
2707 NULL
2708};
2709static const char *urip_rcvsURLs[] = {
2710 /* it is an URI the strings must be escaped */
2711 "urip://example.com/a%20b.html",
2712 /* check that % escaping is not broken */
2713 "urip://example.com/a%20b.html",
2714 /* it's an URI path the strings must be escaped */
2715 "file:///path/to/a%20b.html",
2716 /* check that % escaping is not broken */
2717 "file:///path/to/a%20b.html",
2718 /* this is not an URI, this is a path, so this should not be escaped */
2719 "/path/to/a b.html",
2720 /* check that paths with % are not broken */
2721 "/path/to/a%20b.html",
2722 /* out of context the encoding can't be guessed byte by byte conversion */
2723 "urip://example.com/r%E9sum%E9.html",
2724 /* verify we don't destroy URIs especially the query part */
2725 "urip://example.com/test?a=1&b=2%263&c=4#foo",
2726 NULL
2727};
2728static const char *urip_res = "<list/>";
2729static const char *urip_cur = NULL;
2730static int urip_rlen;
2731
2732/**
2733 * uripMatch:
2734 * @URI: an URI to test
2735 *
2736 * Check for an urip: query
2737 *
2738 * Returns 1 if yes and 0 if another Input module should be used
2739 */
2740static int
2741uripMatch(const char * URI) {
2742 if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog")))
2743 return(0);
2744 /* Verify we received the escaped URL */
2745 if (strcmp(urip_rcvsURLs[urip_current], URI))
2746 urip_success = 0;
2747 return(1);
2748}
2749
2750/**
2751 * uripOpen:
2752 * @URI: an URI to test
2753 *
2754 * Return a pointer to the urip: query handler, in this example simply
2755 * the urip_current pointer...
2756 *
2757 * Returns an Input context or NULL in case or error
2758 */
2759static void *
2760uripOpen(const char * URI) {
2761 if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog")))
2762 return(NULL);
2763 /* Verify we received the escaped URL */
2764 if (strcmp(urip_rcvsURLs[urip_current], URI))
2765 urip_success = 0;
2766 urip_cur = urip_res;
2767 urip_rlen = strlen(urip_res);
2768 return((void *) urip_cur);
2769}
2770
2771/**
2772 * uripClose:
2773 * @context: the read context
2774 *
2775 * Close the urip: query handler
2776 *
2777 * Returns 0 or -1 in case of error
2778 */
2779static int
2780uripClose(void * context) {
2781 if (context == NULL) return(-1);
2782 urip_cur = NULL;
2783 urip_rlen = 0;
2784 return(0);
2785}
2786
2787/**
2788 * uripRead:
2789 * @context: the read context
2790 * @buffer: where to store data
2791 * @len: number of bytes to read
2792 *
2793 * Implement an urip: query read.
2794 *
2795 * Returns the number of bytes read or -1 in case of error
2796 */
2797static int
2798uripRead(void * context, char * buffer, int len) {
2799 const char *ptr = (const char *) context;
2800
2801 if ((context == NULL) || (buffer == NULL) || (len < 0))
2802 return(-1);
2803
2804 if (len > urip_rlen) len = urip_rlen;
2805 memcpy(buffer, ptr, len);
2806 urip_rlen -= len;
2807 return(len);
2808}
2809
2810static int
2811urip_checkURL(const char *URL) {
2812 xmlDocPtr doc;
2813
2814 doc = xmlReadFile(URL, NULL, 0);
2815 if (doc == NULL)
2816 return(-1);
2817 xmlFreeDoc(doc);
2818 return(1);
2819}
2820
2821/**
2822 * uriPathTest:
2823 * @filename: ignored
2824 * @result: ignored
2825 * @err: ignored
2826 *
2827 * Run a set of tests to check how Path and URI are handled before
2828 * being passed to the I/O layer
2829 *
2830 * Returns 0 in case of success, an error code otherwise
2831 */
2832static int
2833uriPathTest(const char *filename ATTRIBUTE_UNUSED,
2834 const char *result ATTRIBUTE_UNUSED,
2835 const char *err ATTRIBUTE_UNUSED,
2836 int options ATTRIBUTE_UNUSED) {
2837 int parsed;
2838 int failures = 0;
2839
2840 /*
2841 * register the new I/O handlers
2842 */
2843 if (xmlRegisterInputCallbacks(uripMatch, uripOpen, uripRead, uripClose) < 0)
2844 {
2845 fprintf(stderr, "failed to register HTTP handler\n");
2846 return(-1);
2847 }
2848
2849 for (urip_current = 0;urip_testURLs[urip_current] != NULL;urip_current++) {
2850 urip_success = 1;
2851 parsed = urip_checkURL(urip_testURLs[urip_current]);
2852 if (urip_success != 1) {
2853 fprintf(stderr, "failed the URL passing test for %s",
2854 urip_testURLs[urip_current]);
2855 failures++;
2856 } else if (parsed != 1) {
2857 fprintf(stderr, "failed the parsing test for %s",
2858 urip_testURLs[urip_current]);
2859 failures++;
2860 }
2861 nb_tests++;
2862 }
2863
2864 xmlPopInputCallbacks();
2865 return(failures);
2866}
2867
William M. Brackca15a542005-07-06 20:41:33 +00002868#ifdef LIBXML_SCHEMAS_ENABLED
2869/************************************************************************
2870 * *
2871 * Schemas tests *
2872 * *
2873 ************************************************************************/
2874static int
2875schemasOneTest(const char *sch,
2876 const char *filename,
2877 const char *result,
2878 const char *err,
2879 int options,
2880 xmlSchemaPtr schemas) {
2881 xmlDocPtr doc;
2882 xmlSchemaValidCtxtPtr ctxt;
2883 int ret = 0;
2884 char *temp;
2885 FILE *schemasOutput;
2886
2887 doc = xmlReadFile(filename, NULL, options);
2888 if (doc == NULL) {
2889 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
2890 return(-1);
2891 }
2892
2893 temp = resultFilename(result, "", ".res");
2894 if (temp == NULL) {
2895 fprintf(stderr, "Out of memory\n");
2896 fatalError();
2897 }
2898 schemasOutput = fopen(temp, "wb");
2899 if (schemasOutput == NULL) {
2900 fprintf(stderr, "failed to open output file %s\n", temp);
2901 xmlFreeDoc(doc);
2902 free(temp);
2903 return(-1);
2904 }
2905
2906 ctxt = xmlSchemaNewValidCtxt(schemas);
2907 xmlSchemaSetValidErrors(ctxt,
2908 (xmlSchemaValidityErrorFunc) testErrorHandler,
2909 (xmlSchemaValidityWarningFunc) testErrorHandler,
2910 ctxt);
2911 ret = xmlSchemaValidateDoc(ctxt, doc);
2912 if (ret == 0) {
2913 fprintf(schemasOutput, "%s validates\n", filename);
2914 } else if (ret > 0) {
2915 fprintf(schemasOutput, "%s fails to validate\n", filename);
2916 } else {
2917 fprintf(schemasOutput, "%s validation generated an internal error\n",
2918 filename);
2919 }
2920 fclose(schemasOutput);
2921 if (result) {
2922 if (compareFiles(temp, result)) {
2923 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
2924 ret = 1;
2925 }
2926 }
2927 unlink(temp);
2928 free(temp);
2929
Daniel Veillard567a45b2005-10-18 19:11:55 +00002930 if ((ret != 0) && (err != NULL)) {
William M. Brackca15a542005-07-06 20:41:33 +00002931 if (compareFileMem(err, testErrors, testErrorsSize)) {
2932 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
2933 ret = 1;
Daniel Veillard93e577f2005-11-15 08:50:04 +00002934 } else {
2935 ret = 0;
William M. Brackca15a542005-07-06 20:41:33 +00002936 }
2937 }
2938
William M. Brackca15a542005-07-06 20:41:33 +00002939 xmlSchemaFreeValidCtxt(ctxt);
2940 xmlFreeDoc(doc);
2941 return(ret);
2942}
2943/**
2944 * schemasTest:
2945 * @filename: the schemas file
2946 * @result: the file with expected result
2947 * @err: the file with error messages
2948 *
2949 * Parse a file containing URI, compose them against a fixed base and
2950 * check for errors
2951 *
2952 * Returns 0 in case of success, an error code otherwise
2953 */
2954static int
2955schemasTest(const char *filename,
2956 const char *resul ATTRIBUTE_UNUSED,
2957 const char *errr ATTRIBUTE_UNUSED,
2958 int options) {
2959 const char *base = baseFilename(filename);
2960 const char *base2;
2961 const char *instance;
2962 xmlSchemaParserCtxtPtr ctxt;
2963 xmlSchemaPtr schemas;
2964 int res = 0, len, ret;
2965 char pattern[500];
2966 char prefix[500];
2967 char result[500];
2968 char err[500];
2969 glob_t globbuf;
2970 size_t i;
2971 char count = 0;
2972
2973 /* first compile the schemas if possible */
2974 ctxt = xmlSchemaNewParserCtxt(filename);
2975 xmlSchemaSetParserErrors(ctxt,
2976 (xmlSchemaValidityErrorFunc) testErrorHandler,
2977 (xmlSchemaValidityWarningFunc) testErrorHandler,
2978 ctxt);
2979 schemas = xmlSchemaParse(ctxt);
2980 xmlSchemaFreeParserCtxt(ctxt);
2981
2982 /*
2983 * most of the mess is about the output filenames generated by the Makefile
2984 */
2985 len = strlen(base);
2986 if ((len > 499) || (len < 5)) {
2987 xmlSchemaFree(schemas);
2988 return(-1);
2989 }
2990 len -= 4; /* remove trailing .xsd */
2991 if (base[len - 2] == '_') {
2992 len -= 2; /* remove subtest number */
2993 }
2994 if (base[len - 2] == '_') {
2995 len -= 2; /* remove subtest number */
2996 }
2997 memcpy(prefix, base, len);
2998 prefix[len] = 0;
2999
3000 snprintf(pattern, 499, "./test/schemas/%s_?.xml", prefix);
3001 pattern[499] = 0;
3002
3003 if (base[len] == '_') {
3004 len += 2;
3005 memcpy(prefix, base, len);
3006 prefix[len] = 0;
3007 }
3008
3009 globbuf.gl_offs = 0;
3010 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3011 for (i = 0;i < globbuf.gl_pathc;i++) {
3012 testErrorsSize = 0;
3013 testErrors[0] = 0;
3014 instance = globbuf.gl_pathv[i];
3015 base2 = baseFilename(instance);
3016 len = strlen(base2);
3017 if ((len > 6) && (base2[len - 6] == '_')) {
3018 count = base2[len - 5];
3019 snprintf(result, 499, "result/schemas/%s_%c",
3020 prefix, count);
3021 result[499] = 0;
3022 snprintf(err, 499, "result/schemas/%s_%c.err",
3023 prefix, count);
3024 err[499] = 0;
3025 } else {
3026 fprintf(stderr, "don't know how to process %s\n", instance);
3027 continue;
3028 }
3029 if (schemas == NULL) {
3030 } else {
3031 nb_tests++;
3032 ret = schemasOneTest(filename, instance, result, err,
3033 options, schemas);
Daniel Veillard93e577f2005-11-15 08:50:04 +00003034 if (ret != 0)
3035 res = ret;
William M. Brackca15a542005-07-06 20:41:33 +00003036 }
3037 }
3038 globfree(&globbuf);
3039 xmlSchemaFree(schemas);
3040
3041 return(res);
3042}
3043
3044/************************************************************************
3045 * *
3046 * Schemas tests *
3047 * *
3048 ************************************************************************/
3049static int
3050rngOneTest(const char *sch,
3051 const char *filename,
3052 const char *result,
3053 const char *err,
3054 int options,
3055 xmlRelaxNGPtr schemas) {
3056 xmlDocPtr doc;
3057 xmlRelaxNGValidCtxtPtr ctxt;
3058 int ret = 0;
3059 char *temp;
3060 FILE *schemasOutput;
3061
3062 doc = xmlReadFile(filename, NULL, options);
3063 if (doc == NULL) {
3064 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
3065 return(-1);
3066 }
3067
3068 temp = resultFilename(result, "", ".res");
3069 if (temp == NULL) {
3070 fprintf(stderr, "Out of memory\n");
3071 fatalError();
3072 }
3073 schemasOutput = fopen(temp, "wb");
3074 if (schemasOutput == NULL) {
3075 fprintf(stderr, "failed to open output file %s\n", temp);
3076 xmlFreeDoc(doc);
3077 free(temp);
3078 return(-1);
3079 }
3080
3081 ctxt = xmlRelaxNGNewValidCtxt(schemas);
3082 xmlRelaxNGSetValidErrors(ctxt,
3083 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
3084 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
3085 ctxt);
3086 ret = xmlRelaxNGValidateDoc(ctxt, doc);
3087 if (ret == 0) {
3088 testErrorHandler(NULL, "%s validates\n", filename);
3089 } else if (ret > 0) {
3090 testErrorHandler(NULL, "%s fails to validate\n", filename);
3091 } else {
3092 testErrorHandler(NULL, "%s validation generated an internal error\n",
3093 filename);
3094 }
3095 fclose(schemasOutput);
3096 if (result) {
3097 if (compareFiles(temp, result)) {
3098 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
3099 ret = 1;
3100 }
3101 }
3102 unlink(temp);
3103 free(temp);
3104
3105 if (err != NULL) {
3106 if (compareFileMem(err, testErrors, testErrorsSize)) {
3107 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
3108 ret = 1;
3109 printf("%s", testErrors);
3110 }
3111 }
3112
3113
3114 xmlRelaxNGFreeValidCtxt(ctxt);
3115 xmlFreeDoc(doc);
3116 return(ret);
3117}
3118/**
3119 * rngTest:
3120 * @filename: the schemas file
3121 * @result: the file with expected result
3122 * @err: the file with error messages
3123 *
3124 * Parse an RNG schemas and then apply it to the related .xml
3125 *
3126 * Returns 0 in case of success, an error code otherwise
3127 */
3128static int
3129rngTest(const char *filename,
3130 const char *resul ATTRIBUTE_UNUSED,
3131 const char *errr ATTRIBUTE_UNUSED,
3132 int options) {
3133 const char *base = baseFilename(filename);
3134 const char *base2;
3135 const char *instance;
3136 xmlRelaxNGParserCtxtPtr ctxt;
3137 xmlRelaxNGPtr schemas;
3138 int res = 0, len, ret;
3139 char pattern[500];
3140 char prefix[500];
3141 char result[500];
3142 char err[500];
3143 glob_t globbuf;
3144 size_t i;
3145 char count = 0;
3146
3147 /* first compile the schemas if possible */
3148 ctxt = xmlRelaxNGNewParserCtxt(filename);
3149 xmlRelaxNGSetParserErrors(ctxt,
3150 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
3151 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
3152 ctxt);
3153 schemas = xmlRelaxNGParse(ctxt);
3154 xmlRelaxNGFreeParserCtxt(ctxt);
3155
3156 /*
3157 * most of the mess is about the output filenames generated by the Makefile
3158 */
3159 len = strlen(base);
3160 if ((len > 499) || (len < 5)) {
3161 xmlRelaxNGFree(schemas);
3162 return(-1);
3163 }
3164 len -= 4; /* remove trailing .rng */
3165 memcpy(prefix, base, len);
3166 prefix[len] = 0;
3167
3168 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
3169 pattern[499] = 0;
3170
3171 globbuf.gl_offs = 0;
3172 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3173 for (i = 0;i < globbuf.gl_pathc;i++) {
3174 testErrorsSize = 0;
3175 testErrors[0] = 0;
3176 instance = globbuf.gl_pathv[i];
3177 base2 = baseFilename(instance);
3178 len = strlen(base2);
3179 if ((len > 6) && (base2[len - 6] == '_')) {
3180 count = base2[len - 5];
3181 snprintf(result, 499, "result/relaxng/%s_%c",
3182 prefix, count);
3183 result[499] = 0;
3184 snprintf(err, 499, "result/relaxng/%s_%c.err",
3185 prefix, count);
3186 err[499] = 0;
3187 } else {
3188 fprintf(stderr, "don't know how to process %s\n", instance);
3189 continue;
3190 }
3191 if (schemas == NULL) {
3192 } else {
3193 nb_tests++;
3194 ret = rngOneTest(filename, instance, result, err,
3195 options, schemas);
3196 if (res != 0)
3197 ret = res;
3198 }
3199 }
3200 globfree(&globbuf);
3201 xmlRelaxNGFree(schemas);
3202
3203 return(res);
3204}
3205
3206#ifdef LIBXML_READER_ENABLED
3207/**
3208 * rngStreamTest:
3209 * @filename: the schemas file
3210 * @result: the file with expected result
3211 * @err: the file with error messages
3212 *
3213 * Parse a set of files with streaming, applying an RNG schemas
3214 *
3215 * Returns 0 in case of success, an error code otherwise
3216 */
3217static int
3218rngStreamTest(const char *filename,
3219 const char *resul ATTRIBUTE_UNUSED,
3220 const char *errr ATTRIBUTE_UNUSED,
3221 int options) {
3222 const char *base = baseFilename(filename);
3223 const char *base2;
3224 const char *instance;
3225 int res = 0, len, ret;
3226 char pattern[500];
3227 char prefix[500];
3228 char result[500];
3229 char err[500];
3230 glob_t globbuf;
3231 size_t i;
3232 char count = 0;
3233 xmlTextReaderPtr reader;
3234 int disable_err = 0;
3235
3236 /*
3237 * most of the mess is about the output filenames generated by the Makefile
3238 */
3239 len = strlen(base);
3240 if ((len > 499) || (len < 5)) {
3241 fprintf(stderr, "len(base) == %d !\n", len);
3242 return(-1);
3243 }
3244 len -= 4; /* remove trailing .rng */
3245 memcpy(prefix, base, len);
3246 prefix[len] = 0;
3247
3248 /*
3249 * strictly unifying the error messages is nearly impossible this
3250 * hack is also done in the Makefile
3251 */
3252 if ((!strcmp(prefix, "tutor10_1")) || (!strcmp(prefix, "tutor10_2")) ||
Daniel Veillard60faf522005-08-10 16:23:57 +00003253 (!strcmp(prefix, "tutor3_2")) || (!strcmp(prefix, "307377")))
William M. Brackca15a542005-07-06 20:41:33 +00003254 disable_err = 1;
3255
3256 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
3257 pattern[499] = 0;
3258
3259 globbuf.gl_offs = 0;
3260 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3261 for (i = 0;i < globbuf.gl_pathc;i++) {
3262 testErrorsSize = 0;
3263 testErrors[0] = 0;
3264 instance = globbuf.gl_pathv[i];
3265 base2 = baseFilename(instance);
3266 len = strlen(base2);
3267 if ((len > 6) && (base2[len - 6] == '_')) {
3268 count = base2[len - 5];
3269 snprintf(result, 499, "result/relaxng/%s_%c",
3270 prefix, count);
3271 result[499] = 0;
3272 snprintf(err, 499, "result/relaxng/%s_%c.err",
3273 prefix, count);
3274 err[499] = 0;
3275 } else {
3276 fprintf(stderr, "don't know how to process %s\n", instance);
3277 continue;
3278 }
3279 reader = xmlReaderForFile(instance, NULL, options);
3280 if (reader == NULL) {
3281 fprintf(stderr, "Failed to build reder for %s\n", instance);
3282 }
3283 if (disable_err == 1)
3284 ret = streamProcessTest(instance, result, NULL, reader, filename);
3285 else
3286 ret = streamProcessTest(instance, result, err, reader, filename);
3287 xmlFreeTextReader(reader);
3288 if (ret != 0) {
3289 fprintf(stderr, "instance %s failed\n", instance);
3290 res = ret;
3291 }
3292 }
3293 globfree(&globbuf);
3294
3295 return(res);
3296}
3297#endif /* READER */
3298
3299#endif
3300
3301#ifdef LIBXML_PATTERN_ENABLED
3302#ifdef LIBXML_READER_ENABLED
3303/************************************************************************
3304 * *
3305 * Patterns tests *
3306 * *
3307 ************************************************************************/
3308static void patternNode(FILE *out, xmlTextReaderPtr reader,
3309 const char *pattern, xmlPatternPtr patternc,
3310 xmlStreamCtxtPtr patstream) {
3311 xmlChar *path = NULL;
3312 int match = -1;
3313 int type, empty;
3314
3315 type = xmlTextReaderNodeType(reader);
3316 empty = xmlTextReaderIsEmptyElement(reader);
3317
3318 if (type == XML_READER_TYPE_ELEMENT) {
3319 /* do the check only on element start */
3320 match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader));
3321
3322 if (match) {
3323 path = xmlGetNodePath(xmlTextReaderCurrentNode(reader));
3324 fprintf(out, "Node %s matches pattern %s\n", path, pattern);
3325 }
3326 }
3327 if (patstream != NULL) {
3328 int ret;
3329
3330 if (type == XML_READER_TYPE_ELEMENT) {
3331 ret = xmlStreamPush(patstream,
3332 xmlTextReaderConstLocalName(reader),
3333 xmlTextReaderConstNamespaceUri(reader));
3334 if (ret < 0) {
3335 fprintf(out, "xmlStreamPush() failure\n");
3336 xmlFreeStreamCtxt(patstream);
3337 patstream = NULL;
3338 } else if (ret != match) {
3339 if (path == NULL) {
3340 path = xmlGetNodePath(
3341 xmlTextReaderCurrentNode(reader));
3342 }
3343 fprintf(out,
3344 "xmlPatternMatch and xmlStreamPush disagree\n");
3345 fprintf(out,
3346 " pattern %s node %s\n",
3347 pattern, path);
3348 }
3349
3350
3351 }
3352 if ((type == XML_READER_TYPE_END_ELEMENT) ||
3353 ((type == XML_READER_TYPE_ELEMENT) && (empty))) {
3354 ret = xmlStreamPop(patstream);
3355 if (ret < 0) {
3356 fprintf(out, "xmlStreamPop() failure\n");
3357 xmlFreeStreamCtxt(patstream);
3358 patstream = NULL;
3359 }
3360 }
3361 }
3362 if (path != NULL)
3363 xmlFree(path);
3364}
3365
3366/**
3367 * patternTest:
3368 * @filename: the schemas file
3369 * @result: the file with expected result
3370 * @err: the file with error messages
3371 *
3372 * Parse a set of files with streaming, applying an RNG schemas
3373 *
3374 * Returns 0 in case of success, an error code otherwise
3375 */
3376static int
3377patternTest(const char *filename,
3378 const char *resul ATTRIBUTE_UNUSED,
3379 const char *err ATTRIBUTE_UNUSED,
3380 int options) {
3381 xmlPatternPtr patternc = NULL;
3382 xmlStreamCtxtPtr patstream = NULL;
3383 FILE *o, *f;
3384 char str[1024];
3385 char xml[500];
3386 char result[500];
3387 int len, i;
3388 int ret = 0, res;
3389 char *temp;
3390 xmlTextReaderPtr reader;
3391 xmlDocPtr doc;
3392
3393 len = strlen(filename);
3394 len -= 4;
3395 memcpy(xml, filename, len);
3396 xml[len] = 0;
3397 snprintf(result, 499, "result/pattern/%s", baseFilename(xml));
3398 result[499] = 0;
3399 memcpy(xml + len, ".xml", 5);
3400
3401 if (!checkTestFile(xml)) {
3402 fprintf(stderr, "Missing xml file %s\n", xml);
3403 return(-1);
3404 }
3405 if (!checkTestFile(result)) {
3406 fprintf(stderr, "Missing result file %s\n", result);
3407 return(-1);
3408 }
3409 f = fopen(filename, "rb");
3410 if (f == NULL) {
3411 fprintf(stderr, "Failed to open %s\n", filename);
3412 return(-1);
3413 }
3414 temp = resultFilename(filename, "", ".res");
3415 if (temp == NULL) {
3416 fprintf(stderr, "Out of memory\n");
3417 fatalError();
3418 }
3419 o = fopen(temp, "wb");
3420 if (o == NULL) {
3421 fprintf(stderr, "failed to open output file %s\n", temp);
3422 fclose(f);
3423 free(temp);
3424 return(-1);
3425 }
3426 while (1) {
3427 /*
3428 * read one line in string buffer.
3429 */
3430 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
3431 break;
3432
3433 /*
3434 * remove the ending spaces
3435 */
3436 i = strlen(str);
3437 while ((i > 0) &&
3438 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
3439 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
3440 i--;
3441 str[i] = 0;
3442 }
3443 doc = xmlReadFile(xml, NULL, options);
3444 if (doc == NULL) {
3445 fprintf(stderr, "Failed to parse %s\n", xml);
3446 ret = 1;
3447 } else {
3448 xmlNodePtr root;
3449 const xmlChar *namespaces[22];
3450 int j;
3451 xmlNsPtr ns;
3452
3453 root = xmlDocGetRootElement(doc);
3454 for (ns = root->nsDef, j = 0;ns != NULL && j < 20;ns=ns->next) {
3455 namespaces[j++] = ns->href;
3456 namespaces[j++] = ns->prefix;
3457 }
3458 namespaces[j++] = NULL;
3459 namespaces[j++] = NULL;
3460
3461 patternc = xmlPatterncompile((const xmlChar *) str, doc->dict,
3462 0, &namespaces[0]);
3463 if (patternc == NULL) {
3464 testErrorHandler(NULL,
3465 "Pattern %s failed to compile\n", str);
3466 xmlFreeDoc(doc);
3467 ret = 1;
3468 continue;
3469 }
3470 patstream = xmlPatternGetStreamCtxt(patternc);
3471 if (patstream != NULL) {
3472 ret = xmlStreamPush(patstream, NULL, NULL);
3473 if (ret < 0) {
3474 fprintf(stderr, "xmlStreamPush() failure\n");
3475 xmlFreeStreamCtxt(patstream);
3476 patstream = NULL;
3477 }
3478 }
3479 nb_tests++;
3480
3481 reader = xmlReaderWalker(doc);
3482 res = xmlTextReaderRead(reader);
3483 while (res == 1) {
3484 patternNode(o, reader, str, patternc, patstream);
3485 res = xmlTextReaderRead(reader);
3486 }
3487 if (res != 0) {
3488 fprintf(o, "%s : failed to parse\n", filename);
3489 }
3490 xmlFreeTextReader(reader);
3491 xmlFreeDoc(doc);
3492 xmlFreeStreamCtxt(patstream);
3493 patstream = NULL;
3494 xmlFreePattern(patternc);
3495
3496 }
3497 }
3498
3499 fclose(f);
3500 fclose(o);
3501
3502 ret = compareFiles(temp, result);
3503 if (ret) {
3504 fprintf(stderr, "Result for %s failed\n", filename);
3505 ret = 1;
3506 }
3507 unlink(temp);
3508 free(temp);
3509 return(ret);
3510}
3511#endif /* READER */
3512#endif /* PATTERN */
3513#ifdef LIBXML_C14N_ENABLED
3514/************************************************************************
3515 * *
3516 * Canonicalization tests *
3517 * *
3518 ************************************************************************/
3519static xmlXPathObjectPtr
3520load_xpath_expr (xmlDocPtr parent_doc, const char* filename) {
3521 xmlXPathObjectPtr xpath;
3522 xmlDocPtr doc;
3523 xmlChar *expr;
3524 xmlXPathContextPtr ctx;
3525 xmlNodePtr node;
3526 xmlNsPtr ns;
3527
3528 /*
3529 * load XPath expr as a file
3530 */
3531 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3532 xmlSubstituteEntitiesDefault(1);
3533
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003534 doc = xmlReadFile(filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
William M. Brackca15a542005-07-06 20:41:33 +00003535 if (doc == NULL) {
3536 fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
3537 return(NULL);
3538 }
3539
3540 /*
3541 * Check the document is of the right kind
3542 */
3543 if(xmlDocGetRootElement(doc) == NULL) {
3544 fprintf(stderr,"Error: empty document for file \"%s\"\n", filename);
3545 xmlFreeDoc(doc);
3546 return(NULL);
3547 }
3548
3549 node = doc->children;
3550 while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) {
3551 node = node->next;
3552 }
3553
3554 if(node == NULL) {
3555 fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename);
3556 xmlFreeDoc(doc);
3557 return(NULL);
3558 }
3559
3560 expr = xmlNodeGetContent(node);
3561 if(expr == NULL) {
3562 fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename);
3563 xmlFreeDoc(doc);
3564 return(NULL);
3565 }
3566
3567 ctx = xmlXPathNewContext(parent_doc);
3568 if(ctx == NULL) {
3569 fprintf(stderr,"Error: unable to create new context\n");
3570 xmlFree(expr);
3571 xmlFreeDoc(doc);
3572 return(NULL);
3573 }
3574
3575 /*
3576 * Register namespaces
3577 */
3578 ns = node->nsDef;
3579 while(ns != NULL) {
3580 if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) {
3581 fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", ns->prefix, ns->href);
3582 xmlFree(expr);
3583 xmlXPathFreeContext(ctx);
3584 xmlFreeDoc(doc);
3585 return(NULL);
3586 }
3587 ns = ns->next;
3588 }
3589
3590 /*
3591 * Evaluate xpath
3592 */
3593 xpath = xmlXPathEvalExpression(expr, ctx);
3594 if(xpath == NULL) {
3595 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3596 xmlFree(expr);
3597 xmlXPathFreeContext(ctx);
3598 xmlFreeDoc(doc);
3599 return(NULL);
3600 }
3601
3602 /* print_xpath_nodes(xpath->nodesetval); */
3603
3604 xmlFree(expr);
3605 xmlXPathFreeContext(ctx);
3606 xmlFreeDoc(doc);
3607 return(xpath);
3608}
3609
3610/*
3611 * Macro used to grow the current buffer.
3612 */
3613#define xxx_growBufferReentrant() { \
3614 buffer_size *= 2; \
3615 buffer = (xmlChar **) \
3616 xmlRealloc(buffer, buffer_size * sizeof(xmlChar*)); \
3617 if (buffer == NULL) { \
3618 perror("realloc failed"); \
3619 return(NULL); \
3620 } \
3621}
3622
3623static xmlChar **
3624parse_list(xmlChar *str) {
3625 xmlChar **buffer;
3626 xmlChar **out = NULL;
3627 int buffer_size = 0;
3628 int len;
3629
3630 if(str == NULL) {
3631 return(NULL);
3632 }
3633
3634 len = xmlStrlen(str);
3635 if((str[0] == '\'') && (str[len - 1] == '\'')) {
3636 str[len - 1] = '\0';
3637 str++;
3638 len -= 2;
3639 }
3640 /*
3641 * allocate an translation buffer.
3642 */
3643 buffer_size = 1000;
3644 buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*));
3645 if (buffer == NULL) {
3646 perror("malloc failed");
3647 return(NULL);
3648 }
3649 out = buffer;
3650
3651 while(*str != '\0') {
3652 if (out - buffer > buffer_size - 10) {
3653 int indx = out - buffer;
3654
3655 xxx_growBufferReentrant();
3656 out = &buffer[indx];
3657 }
3658 (*out++) = str;
3659 while(*str != ',' && *str != '\0') ++str;
3660 if(*str == ',') *(str++) = '\0';
3661 }
3662 (*out) = NULL;
3663 return buffer;
3664}
3665
3666static int
3667c14nRunTest(const char* xml_filename, int with_comments, int exclusive,
3668 const char* xpath_filename, const char *ns_filename,
3669 const char* result_file) {
3670 xmlDocPtr doc;
3671 xmlXPathObjectPtr xpath = NULL;
3672 xmlChar *result = NULL;
3673 int ret;
3674 xmlChar **inclusive_namespaces = NULL;
3675 const char *nslist = NULL;
3676 int nssize;
3677
3678
3679 /*
3680 * build an XML tree from a the file; we need to add default
3681 * attributes and resolve all character and entities references
3682 */
3683 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3684 xmlSubstituteEntitiesDefault(1);
3685
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003686 doc = xmlReadFile(xml_filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
William M. Brackca15a542005-07-06 20:41:33 +00003687 if (doc == NULL) {
3688 fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename);
3689 return(-1);
3690 }
3691
3692 /*
3693 * Check the document is of the right kind
3694 */
3695 if(xmlDocGetRootElement(doc) == NULL) {
3696 fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename);
3697 xmlFreeDoc(doc);
3698 return(-1);
3699 }
3700
3701 /*
3702 * load xpath file if specified
3703 */
3704 if(xpath_filename) {
3705 xpath = load_xpath_expr(doc, xpath_filename);
3706 if(xpath == NULL) {
3707 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3708 xmlFreeDoc(doc);
3709 return(-1);
3710 }
3711 }
3712
3713 if (ns_filename != NULL) {
3714 if (loadMem(ns_filename, &nslist, &nssize)) {
3715 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3716 if(xpath != NULL) xmlXPathFreeObject(xpath);
3717 xmlFreeDoc(doc);
3718 return(-1);
3719 }
3720 inclusive_namespaces = parse_list((xmlChar *) nslist);
3721 }
3722
3723 /*
3724 * Canonical form
3725 */
3726 /* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */
3727 ret = xmlC14NDocDumpMemory(doc,
3728 (xpath) ? xpath->nodesetval : NULL,
3729 exclusive, inclusive_namespaces,
3730 with_comments, &result);
3731 if (ret >= 0) {
3732 if(result != NULL) {
3733 if (compareFileMem(result_file, (const char *) result, ret)) {
3734 fprintf(stderr, "Result mismatch for %s\n", xml_filename);
3735 ret = -1;
3736 }
3737 }
3738 } else {
3739 fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret);
3740 ret = -1;
3741 }
3742
3743 /*
3744 * Cleanup
3745 */
3746 if (result != NULL) xmlFree(result);
3747 if(xpath != NULL) xmlXPathFreeObject(xpath);
3748 if (inclusive_namespaces != NULL) xmlFree(inclusive_namespaces);
3749 if (nslist != NULL) free((char *) nslist);
3750 xmlFreeDoc(doc);
3751
3752 return(ret);
3753}
3754
3755static int
3756c14nCommonTest(const char *filename, int with_comments, int exclusive,
3757 const char *subdir) {
3758 char buf[500];
3759 char prefix[500];
3760 const char *base;
3761 int len;
3762 char *result = NULL;
3763 char *xpath = NULL;
3764 char *ns = NULL;
3765 int ret = 0;
3766
3767 base = baseFilename(filename);
3768 len = strlen(base);
3769 len -= 4;
3770 memcpy(prefix, base, len);
3771 prefix[len] = 0;
3772
3773 snprintf(buf, 499, "result/c14n/%s/%s", subdir,prefix);
3774 if (!checkTestFile(buf)) {
3775 fprintf(stderr, "Missing result file %s", buf);
3776 return(-1);
3777 }
3778 result = strdup(buf);
3779 snprintf(buf, 499, "test/c14n/%s/%s.xpath", subdir,prefix);
3780 if (checkTestFile(buf)) {
3781 xpath = strdup(buf);
3782 }
3783 snprintf(buf, 499, "test/c14n/%s/%s.ns", subdir,prefix);
3784 if (checkTestFile(buf)) {
3785 ns = strdup(buf);
3786 }
3787
3788 nb_tests++;
3789 if (c14nRunTest(filename, with_comments, exclusive,
3790 xpath, ns, result) < 0)
3791 ret = 1;
3792
3793 if (result != NULL) free(result);
3794 if (xpath != NULL) free(xpath);
3795 if (ns != NULL) free(ns);
3796 return(ret);
3797}
3798
3799static int
3800c14nWithCommentTest(const char *filename,
3801 const char *resul ATTRIBUTE_UNUSED,
3802 const char *err ATTRIBUTE_UNUSED,
3803 int options ATTRIBUTE_UNUSED) {
3804 return(c14nCommonTest(filename, 1, 0, "with-comments"));
3805}
3806static int
3807c14nWithoutCommentTest(const char *filename,
3808 const char *resul ATTRIBUTE_UNUSED,
3809 const char *err ATTRIBUTE_UNUSED,
3810 int options ATTRIBUTE_UNUSED) {
3811 return(c14nCommonTest(filename, 0, 0, "without-comments"));
3812}
3813static int
3814c14nExcWithoutCommentTest(const char *filename,
3815 const char *resul ATTRIBUTE_UNUSED,
3816 const char *err ATTRIBUTE_UNUSED,
3817 int options ATTRIBUTE_UNUSED) {
3818 return(c14nCommonTest(filename, 0, 1, "exc-without-comments"));
3819}
3820#endif
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003821#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) && defined (LIBXML_SAX1_ENABLED)
William M. Brackca15a542005-07-06 20:41:33 +00003822/************************************************************************
3823 * *
3824 * Catalog and threads test *
3825 * *
3826 ************************************************************************/
3827
3828/*
3829 * mostly a cut and paste from testThreads.c
3830 */
3831#define MAX_ARGC 20
3832
3833static const char *catalog = "test/threads/complex.xml";
3834static const char *testfiles[] = {
3835 "test/threads/abc.xml",
3836 "test/threads/acb.xml",
3837 "test/threads/bac.xml",
3838 "test/threads/bca.xml",
3839 "test/threads/cab.xml",
3840 "test/threads/cba.xml",
3841 "test/threads/invalid.xml",
3842};
3843
Daniel Veillard24505b02005-07-28 23:49:35 +00003844static const char *Okay = "OK";
3845static const char *Failed = "Failed";
William M. Brackca15a542005-07-06 20:41:33 +00003846
3847#ifndef xmlDoValidityCheckingDefaultValue
3848#error xmlDoValidityCheckingDefaultValue is not a macro
3849#endif
3850#ifndef xmlGenericErrorContext
3851#error xmlGenericErrorContext is not a macro
3852#endif
3853
3854static void *
3855thread_specific_data(void *private_data)
3856{
3857 xmlDocPtr myDoc;
3858 const char *filename = (const char *) private_data;
3859 int okay = 1;
3860
3861 if (!strcmp(filename, "test/threads/invalid.xml")) {
3862 xmlDoValidityCheckingDefaultValue = 0;
3863 xmlGenericErrorContext = stdout;
3864 } else {
3865 xmlDoValidityCheckingDefaultValue = 1;
3866 xmlGenericErrorContext = stderr;
3867 }
3868 myDoc = xmlParseFile(filename);
3869 if (myDoc) {
3870 xmlFreeDoc(myDoc);
3871 } else {
3872 printf("parse failed\n");
3873 okay = 0;
3874 }
3875 if (!strcmp(filename, "test/threads/invalid.xml")) {
3876 if (xmlDoValidityCheckingDefaultValue != 0) {
3877 printf("ValidityCheckingDefaultValue override failed\n");
3878 okay = 0;
3879 }
3880 if (xmlGenericErrorContext != stdout) {
3881 printf("xmlGenericErrorContext override failed\n");
3882 okay = 0;
3883 }
3884 } else {
3885 if (xmlDoValidityCheckingDefaultValue != 1) {
3886 printf("ValidityCheckingDefaultValue override failed\n");
3887 okay = 0;
3888 }
3889 if (xmlGenericErrorContext != stderr) {
3890 printf("xmlGenericErrorContext override failed\n");
3891 okay = 0;
3892 }
3893 }
3894 if (okay == 0)
3895 return ((void *) Failed);
3896 return ((void *) Okay);
3897}
3898
3899#if defined(linux) || defined(solaris)
3900
3901#include <pthread.h>
3902
3903static pthread_t tid[MAX_ARGC];
3904
3905static int
3906testThread(void)
3907{
3908 unsigned int i, repeat;
3909 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
3910 void *results[MAX_ARGC];
3911 int ret;
3912 int res = 0;
3913
3914 xmlInitParser();
3915
3916 for (repeat = 0; repeat < 500; repeat++) {
3917 xmlLoadCatalog(catalog);
3918 nb_tests++;
3919
3920 for (i = 0; i < num_threads; i++) {
3921 results[i] = NULL;
3922 tid[i] = (pthread_t) - 1;
3923 }
3924
3925 for (i = 0; i < num_threads; i++) {
3926 ret = pthread_create(&tid[i], 0, thread_specific_data,
3927 (void *) testfiles[i]);
3928 if (ret != 0) {
3929 fprintf(stderr, "pthread_create failed\n");
3930 return (1);
3931 }
3932 }
3933 for (i = 0; i < num_threads; i++) {
3934 ret = pthread_join(tid[i], &results[i]);
3935 if (ret != 0) {
3936 fprintf(stderr, "pthread_join failed\n");
3937 return (1);
3938 }
3939 }
3940
3941 xmlCatalogCleanup();
3942 for (i = 0; i < num_threads; i++)
3943 if (results[i] != (void *) Okay) {
3944 fprintf(stderr, "Thread %d handling %s failed\n",
3945 i, testfiles[i]);
3946 res = 1;
3947 }
3948 }
3949 return (res);
3950}
3951
3952#elif defined WIN32
3953#include <windows.h>
3954#include <string.h>
3955
3956#define TEST_REPEAT_COUNT 500
3957
3958static HANDLE tid[MAX_ARGC];
3959
3960static DWORD WINAPI
3961win32_thread_specific_data(void *private_data)
3962{
3963 return((DWORD) thread_specific_data(private_data));
3964}
3965
3966static int
3967testThread(void)
3968{
3969 unsigned int i, repeat;
3970 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
3971 DWORD results[MAX_ARGC];
3972 BOOL ret;
3973 int res = 0;
3974
3975 xmlInitParser();
3976 for (repeat = 0; repeat < TEST_REPEAT_COUNT; repeat++) {
3977 xmlLoadCatalog(catalog);
3978 nb_tests++;
3979
3980 for (i = 0; i < num_threads; i++) {
3981 results[i] = 0;
3982 tid[i] = (HANDLE) - 1;
3983 }
3984
3985 for (i = 0; i < num_threads; i++) {
3986 DWORD useless;
3987
3988 tid[i] = CreateThread(NULL, 0,
3989 win32_thread_specific_data,
3990 (void *) testfiles[i], 0,
3991 &useless);
3992 if (tid[i] == NULL) {
3993 fprintf(stderr, "CreateThread failed\n");
3994 return(1);
3995 }
3996 }
3997
3998 if (WaitForMultipleObjects(num_threads, tid, TRUE, INFINITE) ==
3999 WAIT_FAILED) {
4000 fprintf(stderr, "WaitForMultipleObjects failed\n");
4001 return(1);
4002 }
4003
4004 for (i = 0; i < num_threads; i++) {
4005 ret = GetExitCodeThread(tid[i], &results[i]);
4006 if (ret == 0) {
4007 fprintf(stderr, "GetExitCodeThread failed\n");
4008 return(1);
4009 }
4010 CloseHandle(tid[i]);
4011 }
4012
4013 xmlCatalogCleanup();
4014 for (i = 0; i < num_threads; i++) {
4015 if (results[i] != (DWORD) Okay) {
4016 fprintf(stderr, "Thread %d handling %s failed\n",
4017 i, testfiles[i]);
4018 res = 1;
4019 }
4020 }
4021 }
4022
4023 return (res);
4024}
4025
4026#elif defined __BEOS__
4027#include <OS.h>
4028
4029static thread_id tid[MAX_ARGC];
4030
4031static int
4032testThread(void)
4033{
4034 unsigned int i, repeat;
4035 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
4036 void *results[MAX_ARGC];
4037 status_t ret;
4038 int res = 0;
4039
4040 xmlInitParser();
4041 for (repeat = 0; repeat < 500; repeat++) {
4042 xmlLoadCatalog(catalog);
4043 for (i = 0; i < num_threads; i++) {
4044 results[i] = NULL;
4045 tid[i] = (thread_id) - 1;
4046 }
4047 for (i = 0; i < num_threads; i++) {
4048 tid[i] =
4049 spawn_thread(thread_specific_data, "xmlTestThread",
4050 B_NORMAL_PRIORITY, (void *) testfiles[i]);
4051 if (tid[i] < B_OK) {
4052 fprintf(stderr, "beos_thread_create failed\n");
4053 return (1);
4054 }
4055 printf("beos_thread_create %d -> %d\n", i, tid[i]);
4056 }
4057 for (i = 0; i < num_threads; i++) {
4058 ret = wait_for_thread(tid[i], &results[i]);
4059 printf("beos_thread_wait %d -> %d\n", i, ret);
4060 if (ret != B_OK) {
4061 fprintf(stderr, "beos_thread_wait failed\n");
4062 return (1);
4063 }
4064 }
4065
4066 xmlCatalogCleanup();
4067 ret = B_OK;
4068 for (i = 0; i < num_threads; i++)
4069 if (results[i] != (void *) Okay) {
4070 printf("Thread %d handling %s failed\n", i, testfiles[i]);
4071 ret = B_ERROR;
4072 }
4073 }
4074 if (ret != B_OK)
4075 return(1);
4076 return (0);
4077}
4078#else
4079static int
4080testThread(void)
4081{
4082 fprintf(stderr,
4083 "Specific platform thread support not detected\n");
4084 return (-1);
4085}
4086#endif
4087static int
4088threadsTest(const char *filename ATTRIBUTE_UNUSED,
4089 const char *resul ATTRIBUTE_UNUSED,
4090 const char *err ATTRIBUTE_UNUSED,
4091 int options ATTRIBUTE_UNUSED) {
4092 return(testThread());
4093}
4094#endif
4095/************************************************************************
4096 * *
4097 * Tests Descriptions *
4098 * *
4099 ************************************************************************/
4100
4101static
4102testDesc testDescriptions[] = {
4103 { "XML regression tests" ,
4104 oldParseTest, "./test/*", "result/", "", NULL,
4105 0 },
4106 { "XML regression tests on memory" ,
4107 memParseTest, "./test/*", "result/", "", NULL,
4108 0 },
4109 { "XML entity subst regression tests" ,
4110 noentParseTest, "./test/*", "result/noent/", "", NULL,
4111 XML_PARSE_NOENT },
4112 { "XML Namespaces regression tests",
4113 errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err",
4114 0 },
4115 { "Error cases regression tests",
4116 errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err",
4117 0 },
4118#ifdef LIBXML_READER_ENABLED
4119 { "Error cases stream regression tests",
4120 streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str",
4121 0 },
4122 { "Reader regression tests",
4123 streamParseTest, "./test/*", "result/", ".rdr", NULL,
4124 0 },
4125 { "Reader entities substitution regression tests",
4126 streamParseTest, "./test/*", "result/", ".rde", NULL,
4127 XML_PARSE_NOENT },
4128 { "Reader on memory regression tests",
4129 streamMemParseTest, "./test/*", "result/", ".rdr", NULL,
4130 0 },
4131 { "Walker regression tests",
4132 walkerParseTest, "./test/*", "result/", ".rdr", NULL,
4133 0 },
4134#endif
4135#ifdef LIBXML_SAX1_ENABLED
4136 { "SAX1 callbacks regression tests" ,
4137 saxParseTest, "./test/*", "result/", ".sax", NULL,
4138 XML_PARSE_SAX1 },
4139 { "SAX2 callbacks regression tests" ,
4140 saxParseTest, "./test/*", "result/", ".sax2", NULL,
4141 0 },
4142#endif
4143#ifdef LIBXML_PUSH_ENABLED
4144 { "XML push regression tests" ,
4145 pushParseTest, "./test/*", "result/", "", NULL,
4146 0 },
4147#endif
4148#ifdef LIBXML_HTML_ENABLED
4149 { "HTML regression tests" ,
4150 errParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4151 XML_PARSE_HTML },
4152#ifdef LIBXML_PUSH_ENABLED
4153 { "Push HTML regression tests" ,
4154 pushParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4155 XML_PARSE_HTML },
4156#endif
4157#ifdef LIBXML_SAX1_ENABLED
4158 { "HTML SAX regression tests" ,
4159 saxParseTest, "./test/HTML/*", "result/HTML/", ".sax", NULL,
4160 XML_PARSE_HTML },
4161#endif
4162#endif
4163#ifdef LIBXML_VALID_ENABLED
4164 { "Valid documents regression tests" ,
4165 errParseTest, "./test/VCM/*", NULL, NULL, NULL,
4166 XML_PARSE_DTDVALID },
4167 { "Validity checking regression tests" ,
4168 errParseTest, "./test/VC/*", "result/VC/", NULL, "",
4169 XML_PARSE_DTDVALID },
4170 { "General documents valid regression tests" ,
4171 errParseTest, "./test/valid/*", "result/valid/", "", ".err",
4172 XML_PARSE_DTDVALID },
4173#endif
4174#ifdef LIBXML_XINCLUDE_ENABLED
4175 { "XInclude regression tests" ,
4176 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4177 /* Ignore errors at this point ".err", */
4178 XML_PARSE_XINCLUDE },
4179 { "XInclude xmlReader regression tests",
4180 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4181 /* Ignore errors at this point ".err", */
4182 NULL, XML_PARSE_XINCLUDE },
4183 { "XInclude regression tests stripping include nodes" ,
4184 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4185 /* Ignore errors at this point ".err", */
4186 XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
4187 { "XInclude xmlReader regression tests stripping include nodes",
4188 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4189 /* Ignore errors at this point ".err", */
4190 NULL, XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
4191#endif
4192#ifdef LIBXML_XPATH_ENABLED
4193#ifdef LIBXML_DEBUG_ENABLED
4194 { "XPath expressions regression tests" ,
4195 xpathExprTest, "./test/XPath/expr/*", "result/XPath/expr/", "", NULL,
4196 0 },
4197 { "XPath document queries regression tests" ,
4198 xpathDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4199 0 },
4200#ifdef LIBXML_XPTR_ENABLED
4201 { "XPointer document queries regression tests" ,
4202 xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4203 0 },
4204#endif
4205 { "xml:id regression tests" ,
4206 xmlidDocTest, "./test/xmlid/*", "result/xmlid/", "", ".err",
4207 0 },
4208#endif
4209#endif
4210 { "URI parsing tests" ,
4211 uriParseTest, "./test/URI/*.uri", "result/URI/", "", NULL,
4212 0 },
4213 { "URI base composition tests" ,
4214 uriBaseTest, "./test/URI/*.data", "result/URI/", "", NULL,
4215 0 },
Daniel Veillard336a8e12005-08-07 10:46:19 +00004216 { "Path URI conversion tests" ,
4217 uriPathTest, NULL, NULL, NULL, NULL,
4218 0 },
William M. Brackca15a542005-07-06 20:41:33 +00004219#ifdef LIBXML_SCHEMAS_ENABLED
4220 { "Schemas regression tests" ,
4221 schemasTest, "./test/schemas/*_*.xsd", NULL, NULL, NULL,
4222 0 },
4223 { "Relax-NG regression tests" ,
4224 rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4225 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4226#ifdef LIBXML_READER_ENABLED
4227 { "Relax-NG streaming regression tests" ,
4228 rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4229 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4230#endif
4231#endif
4232#ifdef LIBXML_PATTERN_ENABLED
4233#ifdef LIBXML_READER_ENABLED
4234 { "Pattern regression tests" ,
4235 patternTest, "./test/pattern/*.pat", "result/pattern/", NULL, NULL,
4236 0 },
4237#endif
4238#endif
4239#ifdef LIBXML_C14N_ENABLED
4240 { "C14N with comments regression tests" ,
4241 c14nWithCommentTest, "./test/c14n/with-comments/*.xml", NULL, NULL, NULL,
4242 0 },
4243 { "C14N without comments regression tests" ,
4244 c14nWithoutCommentTest, "./test/c14n/without-comments/*.xml", NULL, NULL, NULL,
4245 0 },
4246 { "C14N exclusive without comments regression tests" ,
4247 c14nExcWithoutCommentTest, "./test/c14n/exc-without-comments/*.xml", NULL, NULL, NULL,
4248 0 },
4249#endif
Daniel Veillardbca3ad22005-08-23 22:14:02 +00004250#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) && defined(LIBXML_SAX1_ENABLED)
William M. Brackca15a542005-07-06 20:41:33 +00004251 { "Catalog and Threads regression tests" ,
4252 threadsTest, NULL, NULL, NULL, NULL,
4253 0 },
4254#endif
4255 {NULL, NULL, NULL, NULL, NULL, NULL, 0}
4256};
4257
4258/************************************************************************
4259 * *
4260 * The main code driving the tests *
4261 * *
4262 ************************************************************************/
4263
4264static int
4265launchTests(testDescPtr tst) {
4266 int res = 0, err = 0;
4267 size_t i;
4268 char *result;
4269 char *error;
4270 int mem;
4271
4272 if (tst == NULL) return(-1);
4273 if (tst->in != NULL) {
4274 glob_t globbuf;
4275
4276 globbuf.gl_offs = 0;
4277 glob(tst->in, GLOB_DOOFFS, NULL, &globbuf);
4278 for (i = 0;i < globbuf.gl_pathc;i++) {
4279 if (!checkTestFile(globbuf.gl_pathv[i]))
4280 continue;
4281 if (tst->suffix != NULL) {
4282 result = resultFilename(globbuf.gl_pathv[i], tst->out,
4283 tst->suffix);
4284 if (result == NULL) {
4285 fprintf(stderr, "Out of memory !\n");
4286 fatalError();
4287 }
4288 } else {
4289 result = NULL;
4290 }
4291 if (tst->err != NULL) {
4292 error = resultFilename(globbuf.gl_pathv[i], tst->out,
4293 tst->err);
4294 if (error == NULL) {
4295 fprintf(stderr, "Out of memory !\n");
4296 fatalError();
4297 }
4298 } else {
4299 error = NULL;
4300 }
4301 if ((result) &&(!checkTestFile(result))) {
4302 fprintf(stderr, "Missing result file %s\n", result);
4303 } else if ((error) &&(!checkTestFile(error))) {
4304 fprintf(stderr, "Missing error file %s\n", error);
4305 } else {
4306 mem = xmlMemUsed();
4307 extraMemoryFromResolver = 0;
4308 testErrorsSize = 0;
4309 testErrors[0] = 0;
4310 res = tst->func(globbuf.gl_pathv[i], result, error,
Daniel Veillard8874b942005-08-25 13:19:21 +00004311 tst->options | XML_PARSE_COMPACT);
William M. Brackca15a542005-07-06 20:41:33 +00004312 xmlResetLastError();
4313 if (res != 0) {
4314 fprintf(stderr, "File %s generated an error\n",
4315 globbuf.gl_pathv[i]);
4316 nb_errors++;
4317 err++;
4318 }
4319 else if (xmlMemUsed() != mem) {
4320 if ((xmlMemUsed() != mem) &&
4321 (extraMemoryFromResolver == 0)) {
4322 fprintf(stderr, "File %s leaked %d bytes\n",
4323 globbuf.gl_pathv[i], xmlMemUsed() - mem);
4324 nb_leaks++;
4325 err++;
4326 }
4327 }
4328 testErrorsSize = 0;
4329 }
4330 if (result)
4331 free(result);
4332 if (error)
4333 free(error);
4334 }
4335 globfree(&globbuf);
4336 } else {
4337 testErrorsSize = 0;
4338 testErrors[0] = 0;
4339 extraMemoryFromResolver = 0;
4340 res = tst->func(NULL, NULL, NULL, tst->options);
4341 if (res != 0) {
4342 nb_errors++;
4343 err++;
4344 }
4345 }
4346 return(err);
4347}
4348
Daniel Veillarddb68b742005-07-30 13:18:24 +00004349static int verbose = 0;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004350static int tests_quiet = 0;
Daniel Veillarddb68b742005-07-30 13:18:24 +00004351
4352static int
4353runtest(int i) {
4354 int ret = 0, res;
4355 int old_errors, old_tests, old_leaks;
4356
4357 old_errors = nb_errors;
4358 old_tests = nb_tests;
4359 old_leaks = nb_leaks;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004360 if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
Daniel Veillarddb68b742005-07-30 13:18:24 +00004361 printf("## %s\n", testDescriptions[i].desc);
4362 res = launchTests(&testDescriptions[i]);
4363 if (res != 0)
4364 ret++;
4365 if (verbose) {
4366 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
4367 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
4368 else
4369 printf("Ran %d tests, %d errors, %d leaks\n",
4370 nb_tests - old_tests,
4371 nb_errors - old_errors,
4372 nb_leaks - old_leaks);
4373 }
4374 return(ret);
4375}
4376
William M. Brackca15a542005-07-06 20:41:33 +00004377int
4378main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
Daniel Veillarddb68b742005-07-30 13:18:24 +00004379 int i, a, ret = 0;
4380 int subset = 0;
William M. Brackca15a542005-07-06 20:41:33 +00004381
4382 initializeLibxml2();
4383
Daniel Veillarddb68b742005-07-30 13:18:24 +00004384
4385 for (a = 1; a < argc;a++) {
4386 if (!strcmp(argv[a], "-v"))
4387 verbose = 1;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004388 else if (!strcmp(argv[a], "-quiet"))
4389 tests_quiet = 1;
Daniel Veillarddb68b742005-07-30 13:18:24 +00004390 else {
4391 for (i = 0; testDescriptions[i].func != NULL; i++) {
4392 if (strstr(testDescriptions[i].desc, argv[a])) {
4393 ret += runtest(i);
4394 subset++;
4395 }
4396 }
4397 }
4398 }
4399 if (subset == 0) {
4400 for (i = 0; testDescriptions[i].func != NULL; i++) {
4401 ret += runtest(i);
William M. Brackca15a542005-07-06 20:41:33 +00004402 }
4403 }
4404 if ((nb_errors == 0) && (nb_leaks == 0)) {
4405 ret = 0;
4406 printf("Total %d tests, no errors\n",
4407 nb_tests);
4408 } else {
4409 ret = 1;
4410 printf("Total %d tests, %d errors, %d leaks\n",
4411 nb_tests, nb_errors, nb_leaks);
4412 }
4413 xmlCleanupParser();
4414 xmlMemoryDump();
4415
4416 return(ret);
4417}
4418
4419#else /* ! LIBXML_OUTPUT_ENABLED */
4420int
4421main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
4422 fprintf(stderr, "runtest requires output to be enabled in libxml2\n");
4423 return(1);
4424}
4425#endif