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