blob: 497a892e6ef7339446e7533809802fe0f6fec615 [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;
Daniel Veillard93e577f2005-11-15 08:50:04 +00002938 } else {
2939 ret = 0;
William M. Brackca15a542005-07-06 20:41:33 +00002940 }
2941 }
2942
William M. Brackca15a542005-07-06 20:41:33 +00002943 xmlSchemaFreeValidCtxt(ctxt);
2944 xmlFreeDoc(doc);
2945 return(ret);
2946}
2947/**
2948 * schemasTest:
2949 * @filename: the schemas file
2950 * @result: the file with expected result
2951 * @err: the file with error messages
2952 *
2953 * Parse a file containing URI, compose them against a fixed base and
2954 * check for errors
2955 *
2956 * Returns 0 in case of success, an error code otherwise
2957 */
2958static int
2959schemasTest(const char *filename,
2960 const char *resul ATTRIBUTE_UNUSED,
2961 const char *errr ATTRIBUTE_UNUSED,
2962 int options) {
2963 const char *base = baseFilename(filename);
2964 const char *base2;
2965 const char *instance;
2966 xmlSchemaParserCtxtPtr ctxt;
2967 xmlSchemaPtr schemas;
2968 int res = 0, len, ret;
2969 char pattern[500];
2970 char prefix[500];
2971 char result[500];
2972 char err[500];
2973 glob_t globbuf;
2974 size_t i;
2975 char count = 0;
2976
2977 /* first compile the schemas if possible */
2978 ctxt = xmlSchemaNewParserCtxt(filename);
2979 xmlSchemaSetParserErrors(ctxt,
2980 (xmlSchemaValidityErrorFunc) testErrorHandler,
2981 (xmlSchemaValidityWarningFunc) testErrorHandler,
2982 ctxt);
2983 schemas = xmlSchemaParse(ctxt);
2984 xmlSchemaFreeParserCtxt(ctxt);
2985
2986 /*
2987 * most of the mess is about the output filenames generated by the Makefile
2988 */
2989 len = strlen(base);
2990 if ((len > 499) || (len < 5)) {
2991 xmlSchemaFree(schemas);
2992 return(-1);
2993 }
2994 len -= 4; /* remove trailing .xsd */
2995 if (base[len - 2] == '_') {
2996 len -= 2; /* remove subtest number */
2997 }
2998 if (base[len - 2] == '_') {
2999 len -= 2; /* remove subtest number */
3000 }
3001 memcpy(prefix, base, len);
3002 prefix[len] = 0;
3003
3004 snprintf(pattern, 499, "./test/schemas/%s_?.xml", prefix);
3005 pattern[499] = 0;
3006
3007 if (base[len] == '_') {
3008 len += 2;
3009 memcpy(prefix, base, len);
3010 prefix[len] = 0;
3011 }
3012
3013 globbuf.gl_offs = 0;
3014 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3015 for (i = 0;i < globbuf.gl_pathc;i++) {
3016 testErrorsSize = 0;
3017 testErrors[0] = 0;
3018 instance = globbuf.gl_pathv[i];
3019 base2 = baseFilename(instance);
3020 len = strlen(base2);
3021 if ((len > 6) && (base2[len - 6] == '_')) {
3022 count = base2[len - 5];
3023 snprintf(result, 499, "result/schemas/%s_%c",
3024 prefix, count);
3025 result[499] = 0;
3026 snprintf(err, 499, "result/schemas/%s_%c.err",
3027 prefix, count);
3028 err[499] = 0;
3029 } else {
3030 fprintf(stderr, "don't know how to process %s\n", instance);
3031 continue;
3032 }
3033 if (schemas == NULL) {
3034 } else {
3035 nb_tests++;
3036 ret = schemasOneTest(filename, instance, result, err,
3037 options, schemas);
Daniel Veillard93e577f2005-11-15 08:50:04 +00003038 if (ret != 0)
3039 res = ret;
William M. Brackca15a542005-07-06 20:41:33 +00003040 }
3041 }
3042 globfree(&globbuf);
3043 xmlSchemaFree(schemas);
3044
3045 return(res);
3046}
3047
3048/************************************************************************
3049 * *
3050 * Schemas tests *
3051 * *
3052 ************************************************************************/
3053static int
3054rngOneTest(const char *sch,
3055 const char *filename,
3056 const char *result,
3057 const char *err,
3058 int options,
3059 xmlRelaxNGPtr schemas) {
3060 xmlDocPtr doc;
3061 xmlRelaxNGValidCtxtPtr ctxt;
3062 int ret = 0;
3063 char *temp;
3064 FILE *schemasOutput;
3065
3066 doc = xmlReadFile(filename, NULL, options);
3067 if (doc == NULL) {
3068 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
3069 return(-1);
3070 }
3071
3072 temp = resultFilename(result, "", ".res");
3073 if (temp == NULL) {
3074 fprintf(stderr, "Out of memory\n");
3075 fatalError();
3076 }
3077 schemasOutput = fopen(temp, "wb");
3078 if (schemasOutput == NULL) {
3079 fprintf(stderr, "failed to open output file %s\n", temp);
3080 xmlFreeDoc(doc);
3081 free(temp);
3082 return(-1);
3083 }
3084
3085 ctxt = xmlRelaxNGNewValidCtxt(schemas);
3086 xmlRelaxNGSetValidErrors(ctxt,
3087 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
3088 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
3089 ctxt);
3090 ret = xmlRelaxNGValidateDoc(ctxt, doc);
3091 if (ret == 0) {
3092 testErrorHandler(NULL, "%s validates\n", filename);
3093 } else if (ret > 0) {
3094 testErrorHandler(NULL, "%s fails to validate\n", filename);
3095 } else {
3096 testErrorHandler(NULL, "%s validation generated an internal error\n",
3097 filename);
3098 }
3099 fclose(schemasOutput);
3100 if (result) {
3101 if (compareFiles(temp, result)) {
3102 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
3103 ret = 1;
3104 }
3105 }
3106 unlink(temp);
3107 free(temp);
3108
3109 if (err != NULL) {
3110 if (compareFileMem(err, testErrors, testErrorsSize)) {
3111 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
3112 ret = 1;
3113 printf("%s", testErrors);
3114 }
3115 }
3116
3117
3118 xmlRelaxNGFreeValidCtxt(ctxt);
3119 xmlFreeDoc(doc);
3120 return(ret);
3121}
3122/**
3123 * rngTest:
3124 * @filename: the schemas file
3125 * @result: the file with expected result
3126 * @err: the file with error messages
3127 *
3128 * Parse an RNG schemas and then apply it to the related .xml
3129 *
3130 * Returns 0 in case of success, an error code otherwise
3131 */
3132static int
3133rngTest(const char *filename,
3134 const char *resul ATTRIBUTE_UNUSED,
3135 const char *errr ATTRIBUTE_UNUSED,
3136 int options) {
3137 const char *base = baseFilename(filename);
3138 const char *base2;
3139 const char *instance;
3140 xmlRelaxNGParserCtxtPtr ctxt;
3141 xmlRelaxNGPtr schemas;
3142 int res = 0, len, ret;
3143 char pattern[500];
3144 char prefix[500];
3145 char result[500];
3146 char err[500];
3147 glob_t globbuf;
3148 size_t i;
3149 char count = 0;
3150
3151 /* first compile the schemas if possible */
3152 ctxt = xmlRelaxNGNewParserCtxt(filename);
3153 xmlRelaxNGSetParserErrors(ctxt,
3154 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
3155 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
3156 ctxt);
3157 schemas = xmlRelaxNGParse(ctxt);
3158 xmlRelaxNGFreeParserCtxt(ctxt);
3159
3160 /*
3161 * most of the mess is about the output filenames generated by the Makefile
3162 */
3163 len = strlen(base);
3164 if ((len > 499) || (len < 5)) {
3165 xmlRelaxNGFree(schemas);
3166 return(-1);
3167 }
3168 len -= 4; /* remove trailing .rng */
3169 memcpy(prefix, base, len);
3170 prefix[len] = 0;
3171
3172 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
3173 pattern[499] = 0;
3174
3175 globbuf.gl_offs = 0;
3176 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3177 for (i = 0;i < globbuf.gl_pathc;i++) {
3178 testErrorsSize = 0;
3179 testErrors[0] = 0;
3180 instance = globbuf.gl_pathv[i];
3181 base2 = baseFilename(instance);
3182 len = strlen(base2);
3183 if ((len > 6) && (base2[len - 6] == '_')) {
3184 count = base2[len - 5];
3185 snprintf(result, 499, "result/relaxng/%s_%c",
3186 prefix, count);
3187 result[499] = 0;
3188 snprintf(err, 499, "result/relaxng/%s_%c.err",
3189 prefix, count);
3190 err[499] = 0;
3191 } else {
3192 fprintf(stderr, "don't know how to process %s\n", instance);
3193 continue;
3194 }
3195 if (schemas == NULL) {
3196 } else {
3197 nb_tests++;
3198 ret = rngOneTest(filename, instance, result, err,
3199 options, schemas);
3200 if (res != 0)
3201 ret = res;
3202 }
3203 }
3204 globfree(&globbuf);
3205 xmlRelaxNGFree(schemas);
3206
3207 return(res);
3208}
3209
3210#ifdef LIBXML_READER_ENABLED
3211/**
3212 * rngStreamTest:
3213 * @filename: the schemas file
3214 * @result: the file with expected result
3215 * @err: the file with error messages
3216 *
3217 * Parse a set of files with streaming, applying an RNG schemas
3218 *
3219 * Returns 0 in case of success, an error code otherwise
3220 */
3221static int
3222rngStreamTest(const char *filename,
3223 const char *resul ATTRIBUTE_UNUSED,
3224 const char *errr ATTRIBUTE_UNUSED,
3225 int options) {
3226 const char *base = baseFilename(filename);
3227 const char *base2;
3228 const char *instance;
3229 int res = 0, len, ret;
3230 char pattern[500];
3231 char prefix[500];
3232 char result[500];
3233 char err[500];
3234 glob_t globbuf;
3235 size_t i;
3236 char count = 0;
3237 xmlTextReaderPtr reader;
3238 int disable_err = 0;
3239
3240 /*
3241 * most of the mess is about the output filenames generated by the Makefile
3242 */
3243 len = strlen(base);
3244 if ((len > 499) || (len < 5)) {
3245 fprintf(stderr, "len(base) == %d !\n", len);
3246 return(-1);
3247 }
3248 len -= 4; /* remove trailing .rng */
3249 memcpy(prefix, base, len);
3250 prefix[len] = 0;
3251
3252 /*
3253 * strictly unifying the error messages is nearly impossible this
3254 * hack is also done in the Makefile
3255 */
3256 if ((!strcmp(prefix, "tutor10_1")) || (!strcmp(prefix, "tutor10_2")) ||
Daniel Veillard60faf522005-08-10 16:23:57 +00003257 (!strcmp(prefix, "tutor3_2")) || (!strcmp(prefix, "307377")))
William M. Brackca15a542005-07-06 20:41:33 +00003258 disable_err = 1;
3259
3260 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
3261 pattern[499] = 0;
3262
3263 globbuf.gl_offs = 0;
3264 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3265 for (i = 0;i < globbuf.gl_pathc;i++) {
3266 testErrorsSize = 0;
3267 testErrors[0] = 0;
3268 instance = globbuf.gl_pathv[i];
3269 base2 = baseFilename(instance);
3270 len = strlen(base2);
3271 if ((len > 6) && (base2[len - 6] == '_')) {
3272 count = base2[len - 5];
3273 snprintf(result, 499, "result/relaxng/%s_%c",
3274 prefix, count);
3275 result[499] = 0;
3276 snprintf(err, 499, "result/relaxng/%s_%c.err",
3277 prefix, count);
3278 err[499] = 0;
3279 } else {
3280 fprintf(stderr, "don't know how to process %s\n", instance);
3281 continue;
3282 }
3283 reader = xmlReaderForFile(instance, NULL, options);
3284 if (reader == NULL) {
3285 fprintf(stderr, "Failed to build reder for %s\n", instance);
3286 }
3287 if (disable_err == 1)
3288 ret = streamProcessTest(instance, result, NULL, reader, filename);
3289 else
3290 ret = streamProcessTest(instance, result, err, reader, filename);
3291 xmlFreeTextReader(reader);
3292 if (ret != 0) {
3293 fprintf(stderr, "instance %s failed\n", instance);
3294 res = ret;
3295 }
3296 }
3297 globfree(&globbuf);
3298
3299 return(res);
3300}
3301#endif /* READER */
3302
3303#endif
3304
3305#ifdef LIBXML_PATTERN_ENABLED
3306#ifdef LIBXML_READER_ENABLED
3307/************************************************************************
3308 * *
3309 * Patterns tests *
3310 * *
3311 ************************************************************************/
3312static void patternNode(FILE *out, xmlTextReaderPtr reader,
3313 const char *pattern, xmlPatternPtr patternc,
3314 xmlStreamCtxtPtr patstream) {
3315 xmlChar *path = NULL;
3316 int match = -1;
3317 int type, empty;
3318
3319 type = xmlTextReaderNodeType(reader);
3320 empty = xmlTextReaderIsEmptyElement(reader);
3321
3322 if (type == XML_READER_TYPE_ELEMENT) {
3323 /* do the check only on element start */
3324 match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader));
3325
3326 if (match) {
3327 path = xmlGetNodePath(xmlTextReaderCurrentNode(reader));
3328 fprintf(out, "Node %s matches pattern %s\n", path, pattern);
3329 }
3330 }
3331 if (patstream != NULL) {
3332 int ret;
3333
3334 if (type == XML_READER_TYPE_ELEMENT) {
3335 ret = xmlStreamPush(patstream,
3336 xmlTextReaderConstLocalName(reader),
3337 xmlTextReaderConstNamespaceUri(reader));
3338 if (ret < 0) {
3339 fprintf(out, "xmlStreamPush() failure\n");
3340 xmlFreeStreamCtxt(patstream);
3341 patstream = NULL;
3342 } else if (ret != match) {
3343 if (path == NULL) {
3344 path = xmlGetNodePath(
3345 xmlTextReaderCurrentNode(reader));
3346 }
3347 fprintf(out,
3348 "xmlPatternMatch and xmlStreamPush disagree\n");
3349 fprintf(out,
3350 " pattern %s node %s\n",
3351 pattern, path);
3352 }
3353
3354
3355 }
3356 if ((type == XML_READER_TYPE_END_ELEMENT) ||
3357 ((type == XML_READER_TYPE_ELEMENT) && (empty))) {
3358 ret = xmlStreamPop(patstream);
3359 if (ret < 0) {
3360 fprintf(out, "xmlStreamPop() failure\n");
3361 xmlFreeStreamCtxt(patstream);
3362 patstream = NULL;
3363 }
3364 }
3365 }
3366 if (path != NULL)
3367 xmlFree(path);
3368}
3369
3370/**
3371 * patternTest:
3372 * @filename: the schemas file
3373 * @result: the file with expected result
3374 * @err: the file with error messages
3375 *
3376 * Parse a set of files with streaming, applying an RNG schemas
3377 *
3378 * Returns 0 in case of success, an error code otherwise
3379 */
3380static int
3381patternTest(const char *filename,
3382 const char *resul ATTRIBUTE_UNUSED,
3383 const char *err ATTRIBUTE_UNUSED,
3384 int options) {
3385 xmlPatternPtr patternc = NULL;
3386 xmlStreamCtxtPtr patstream = NULL;
3387 FILE *o, *f;
3388 char str[1024];
3389 char xml[500];
3390 char result[500];
3391 int len, i;
3392 int ret = 0, res;
3393 char *temp;
3394 xmlTextReaderPtr reader;
3395 xmlDocPtr doc;
3396
3397 len = strlen(filename);
3398 len -= 4;
3399 memcpy(xml, filename, len);
3400 xml[len] = 0;
3401 snprintf(result, 499, "result/pattern/%s", baseFilename(xml));
3402 result[499] = 0;
3403 memcpy(xml + len, ".xml", 5);
3404
3405 if (!checkTestFile(xml)) {
3406 fprintf(stderr, "Missing xml file %s\n", xml);
3407 return(-1);
3408 }
3409 if (!checkTestFile(result)) {
3410 fprintf(stderr, "Missing result file %s\n", result);
3411 return(-1);
3412 }
3413 f = fopen(filename, "rb");
3414 if (f == NULL) {
3415 fprintf(stderr, "Failed to open %s\n", filename);
3416 return(-1);
3417 }
3418 temp = resultFilename(filename, "", ".res");
3419 if (temp == NULL) {
3420 fprintf(stderr, "Out of memory\n");
3421 fatalError();
3422 }
3423 o = fopen(temp, "wb");
3424 if (o == NULL) {
3425 fprintf(stderr, "failed to open output file %s\n", temp);
3426 fclose(f);
3427 free(temp);
3428 return(-1);
3429 }
3430 while (1) {
3431 /*
3432 * read one line in string buffer.
3433 */
3434 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
3435 break;
3436
3437 /*
3438 * remove the ending spaces
3439 */
3440 i = strlen(str);
3441 while ((i > 0) &&
3442 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
3443 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
3444 i--;
3445 str[i] = 0;
3446 }
3447 doc = xmlReadFile(xml, NULL, options);
3448 if (doc == NULL) {
3449 fprintf(stderr, "Failed to parse %s\n", xml);
3450 ret = 1;
3451 } else {
3452 xmlNodePtr root;
3453 const xmlChar *namespaces[22];
3454 int j;
3455 xmlNsPtr ns;
3456
3457 root = xmlDocGetRootElement(doc);
3458 for (ns = root->nsDef, j = 0;ns != NULL && j < 20;ns=ns->next) {
3459 namespaces[j++] = ns->href;
3460 namespaces[j++] = ns->prefix;
3461 }
3462 namespaces[j++] = NULL;
3463 namespaces[j++] = NULL;
3464
3465 patternc = xmlPatterncompile((const xmlChar *) str, doc->dict,
3466 0, &namespaces[0]);
3467 if (patternc == NULL) {
3468 testErrorHandler(NULL,
3469 "Pattern %s failed to compile\n", str);
3470 xmlFreeDoc(doc);
3471 ret = 1;
3472 continue;
3473 }
3474 patstream = xmlPatternGetStreamCtxt(patternc);
3475 if (patstream != NULL) {
3476 ret = xmlStreamPush(patstream, NULL, NULL);
3477 if (ret < 0) {
3478 fprintf(stderr, "xmlStreamPush() failure\n");
3479 xmlFreeStreamCtxt(patstream);
3480 patstream = NULL;
3481 }
3482 }
3483 nb_tests++;
3484
3485 reader = xmlReaderWalker(doc);
3486 res = xmlTextReaderRead(reader);
3487 while (res == 1) {
3488 patternNode(o, reader, str, patternc, patstream);
3489 res = xmlTextReaderRead(reader);
3490 }
3491 if (res != 0) {
3492 fprintf(o, "%s : failed to parse\n", filename);
3493 }
3494 xmlFreeTextReader(reader);
3495 xmlFreeDoc(doc);
3496 xmlFreeStreamCtxt(patstream);
3497 patstream = NULL;
3498 xmlFreePattern(patternc);
3499
3500 }
3501 }
3502
3503 fclose(f);
3504 fclose(o);
3505
3506 ret = compareFiles(temp, result);
3507 if (ret) {
3508 fprintf(stderr, "Result for %s failed\n", filename);
3509 ret = 1;
3510 }
3511 unlink(temp);
3512 free(temp);
3513 return(ret);
3514}
3515#endif /* READER */
3516#endif /* PATTERN */
3517#ifdef LIBXML_C14N_ENABLED
3518/************************************************************************
3519 * *
3520 * Canonicalization tests *
3521 * *
3522 ************************************************************************/
3523static xmlXPathObjectPtr
3524load_xpath_expr (xmlDocPtr parent_doc, const char* filename) {
3525 xmlXPathObjectPtr xpath;
3526 xmlDocPtr doc;
3527 xmlChar *expr;
3528 xmlXPathContextPtr ctx;
3529 xmlNodePtr node;
3530 xmlNsPtr ns;
3531
3532 /*
3533 * load XPath expr as a file
3534 */
3535 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3536 xmlSubstituteEntitiesDefault(1);
3537
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003538 doc = xmlReadFile(filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
William M. Brackca15a542005-07-06 20:41:33 +00003539 if (doc == NULL) {
3540 fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
3541 return(NULL);
3542 }
3543
3544 /*
3545 * Check the document is of the right kind
3546 */
3547 if(xmlDocGetRootElement(doc) == NULL) {
3548 fprintf(stderr,"Error: empty document for file \"%s\"\n", filename);
3549 xmlFreeDoc(doc);
3550 return(NULL);
3551 }
3552
3553 node = doc->children;
3554 while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) {
3555 node = node->next;
3556 }
3557
3558 if(node == NULL) {
3559 fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename);
3560 xmlFreeDoc(doc);
3561 return(NULL);
3562 }
3563
3564 expr = xmlNodeGetContent(node);
3565 if(expr == NULL) {
3566 fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename);
3567 xmlFreeDoc(doc);
3568 return(NULL);
3569 }
3570
3571 ctx = xmlXPathNewContext(parent_doc);
3572 if(ctx == NULL) {
3573 fprintf(stderr,"Error: unable to create new context\n");
3574 xmlFree(expr);
3575 xmlFreeDoc(doc);
3576 return(NULL);
3577 }
3578
3579 /*
3580 * Register namespaces
3581 */
3582 ns = node->nsDef;
3583 while(ns != NULL) {
3584 if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) {
3585 fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", ns->prefix, ns->href);
3586 xmlFree(expr);
3587 xmlXPathFreeContext(ctx);
3588 xmlFreeDoc(doc);
3589 return(NULL);
3590 }
3591 ns = ns->next;
3592 }
3593
3594 /*
3595 * Evaluate xpath
3596 */
3597 xpath = xmlXPathEvalExpression(expr, ctx);
3598 if(xpath == NULL) {
3599 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3600 xmlFree(expr);
3601 xmlXPathFreeContext(ctx);
3602 xmlFreeDoc(doc);
3603 return(NULL);
3604 }
3605
3606 /* print_xpath_nodes(xpath->nodesetval); */
3607
3608 xmlFree(expr);
3609 xmlXPathFreeContext(ctx);
3610 xmlFreeDoc(doc);
3611 return(xpath);
3612}
3613
3614/*
3615 * Macro used to grow the current buffer.
3616 */
3617#define xxx_growBufferReentrant() { \
3618 buffer_size *= 2; \
3619 buffer = (xmlChar **) \
3620 xmlRealloc(buffer, buffer_size * sizeof(xmlChar*)); \
3621 if (buffer == NULL) { \
3622 perror("realloc failed"); \
3623 return(NULL); \
3624 } \
3625}
3626
3627static xmlChar **
3628parse_list(xmlChar *str) {
3629 xmlChar **buffer;
3630 xmlChar **out = NULL;
3631 int buffer_size = 0;
3632 int len;
3633
3634 if(str == NULL) {
3635 return(NULL);
3636 }
3637
3638 len = xmlStrlen(str);
3639 if((str[0] == '\'') && (str[len - 1] == '\'')) {
3640 str[len - 1] = '\0';
3641 str++;
3642 len -= 2;
3643 }
3644 /*
3645 * allocate an translation buffer.
3646 */
3647 buffer_size = 1000;
3648 buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*));
3649 if (buffer == NULL) {
3650 perror("malloc failed");
3651 return(NULL);
3652 }
3653 out = buffer;
3654
3655 while(*str != '\0') {
3656 if (out - buffer > buffer_size - 10) {
3657 int indx = out - buffer;
3658
3659 xxx_growBufferReentrant();
3660 out = &buffer[indx];
3661 }
3662 (*out++) = str;
3663 while(*str != ',' && *str != '\0') ++str;
3664 if(*str == ',') *(str++) = '\0';
3665 }
3666 (*out) = NULL;
3667 return buffer;
3668}
3669
3670static int
3671c14nRunTest(const char* xml_filename, int with_comments, int exclusive,
3672 const char* xpath_filename, const char *ns_filename,
3673 const char* result_file) {
3674 xmlDocPtr doc;
3675 xmlXPathObjectPtr xpath = NULL;
3676 xmlChar *result = NULL;
3677 int ret;
3678 xmlChar **inclusive_namespaces = NULL;
3679 const char *nslist = NULL;
3680 int nssize;
3681
3682
3683 /*
3684 * build an XML tree from a the file; we need to add default
3685 * attributes and resolve all character and entities references
3686 */
3687 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3688 xmlSubstituteEntitiesDefault(1);
3689
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003690 doc = xmlReadFile(xml_filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
William M. Brackca15a542005-07-06 20:41:33 +00003691 if (doc == NULL) {
3692 fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename);
3693 return(-1);
3694 }
3695
3696 /*
3697 * Check the document is of the right kind
3698 */
3699 if(xmlDocGetRootElement(doc) == NULL) {
3700 fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename);
3701 xmlFreeDoc(doc);
3702 return(-1);
3703 }
3704
3705 /*
3706 * load xpath file if specified
3707 */
3708 if(xpath_filename) {
3709 xpath = load_xpath_expr(doc, xpath_filename);
3710 if(xpath == NULL) {
3711 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3712 xmlFreeDoc(doc);
3713 return(-1);
3714 }
3715 }
3716
3717 if (ns_filename != NULL) {
3718 if (loadMem(ns_filename, &nslist, &nssize)) {
3719 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3720 if(xpath != NULL) xmlXPathFreeObject(xpath);
3721 xmlFreeDoc(doc);
3722 return(-1);
3723 }
3724 inclusive_namespaces = parse_list((xmlChar *) nslist);
3725 }
3726
3727 /*
3728 * Canonical form
3729 */
3730 /* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */
3731 ret = xmlC14NDocDumpMemory(doc,
3732 (xpath) ? xpath->nodesetval : NULL,
3733 exclusive, inclusive_namespaces,
3734 with_comments, &result);
3735 if (ret >= 0) {
3736 if(result != NULL) {
3737 if (compareFileMem(result_file, (const char *) result, ret)) {
3738 fprintf(stderr, "Result mismatch for %s\n", xml_filename);
3739 ret = -1;
3740 }
3741 }
3742 } else {
3743 fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret);
3744 ret = -1;
3745 }
3746
3747 /*
3748 * Cleanup
3749 */
3750 if (result != NULL) xmlFree(result);
3751 if(xpath != NULL) xmlXPathFreeObject(xpath);
3752 if (inclusive_namespaces != NULL) xmlFree(inclusive_namespaces);
3753 if (nslist != NULL) free((char *) nslist);
3754 xmlFreeDoc(doc);
3755
3756 return(ret);
3757}
3758
3759static int
3760c14nCommonTest(const char *filename, int with_comments, int exclusive,
3761 const char *subdir) {
3762 char buf[500];
3763 char prefix[500];
3764 const char *base;
3765 int len;
3766 char *result = NULL;
3767 char *xpath = NULL;
3768 char *ns = NULL;
3769 int ret = 0;
3770
3771 base = baseFilename(filename);
3772 len = strlen(base);
3773 len -= 4;
3774 memcpy(prefix, base, len);
3775 prefix[len] = 0;
3776
3777 snprintf(buf, 499, "result/c14n/%s/%s", subdir,prefix);
3778 if (!checkTestFile(buf)) {
3779 fprintf(stderr, "Missing result file %s", buf);
3780 return(-1);
3781 }
3782 result = strdup(buf);
3783 snprintf(buf, 499, "test/c14n/%s/%s.xpath", subdir,prefix);
3784 if (checkTestFile(buf)) {
3785 xpath = strdup(buf);
3786 }
3787 snprintf(buf, 499, "test/c14n/%s/%s.ns", subdir,prefix);
3788 if (checkTestFile(buf)) {
3789 ns = strdup(buf);
3790 }
3791
3792 nb_tests++;
3793 if (c14nRunTest(filename, with_comments, exclusive,
3794 xpath, ns, result) < 0)
3795 ret = 1;
3796
3797 if (result != NULL) free(result);
3798 if (xpath != NULL) free(xpath);
3799 if (ns != NULL) free(ns);
3800 return(ret);
3801}
3802
3803static int
3804c14nWithCommentTest(const char *filename,
3805 const char *resul ATTRIBUTE_UNUSED,
3806 const char *err ATTRIBUTE_UNUSED,
3807 int options ATTRIBUTE_UNUSED) {
3808 return(c14nCommonTest(filename, 1, 0, "with-comments"));
3809}
3810static int
3811c14nWithoutCommentTest(const char *filename,
3812 const char *resul ATTRIBUTE_UNUSED,
3813 const char *err ATTRIBUTE_UNUSED,
3814 int options ATTRIBUTE_UNUSED) {
3815 return(c14nCommonTest(filename, 0, 0, "without-comments"));
3816}
3817static int
3818c14nExcWithoutCommentTest(const char *filename,
3819 const char *resul ATTRIBUTE_UNUSED,
3820 const char *err ATTRIBUTE_UNUSED,
3821 int options ATTRIBUTE_UNUSED) {
3822 return(c14nCommonTest(filename, 0, 1, "exc-without-comments"));
3823}
3824#endif
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003825#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) && defined (LIBXML_SAX1_ENABLED)
William M. Brackca15a542005-07-06 20:41:33 +00003826/************************************************************************
3827 * *
3828 * Catalog and threads test *
3829 * *
3830 ************************************************************************/
3831
3832/*
3833 * mostly a cut and paste from testThreads.c
3834 */
3835#define MAX_ARGC 20
3836
3837static const char *catalog = "test/threads/complex.xml";
3838static const char *testfiles[] = {
3839 "test/threads/abc.xml",
3840 "test/threads/acb.xml",
3841 "test/threads/bac.xml",
3842 "test/threads/bca.xml",
3843 "test/threads/cab.xml",
3844 "test/threads/cba.xml",
3845 "test/threads/invalid.xml",
3846};
3847
Daniel Veillard24505b02005-07-28 23:49:35 +00003848static const char *Okay = "OK";
3849static const char *Failed = "Failed";
William M. Brackca15a542005-07-06 20:41:33 +00003850
3851#ifndef xmlDoValidityCheckingDefaultValue
3852#error xmlDoValidityCheckingDefaultValue is not a macro
3853#endif
3854#ifndef xmlGenericErrorContext
3855#error xmlGenericErrorContext is not a macro
3856#endif
3857
3858static void *
3859thread_specific_data(void *private_data)
3860{
3861 xmlDocPtr myDoc;
3862 const char *filename = (const char *) private_data;
3863 int okay = 1;
3864
3865 if (!strcmp(filename, "test/threads/invalid.xml")) {
3866 xmlDoValidityCheckingDefaultValue = 0;
3867 xmlGenericErrorContext = stdout;
3868 } else {
3869 xmlDoValidityCheckingDefaultValue = 1;
3870 xmlGenericErrorContext = stderr;
3871 }
3872 myDoc = xmlParseFile(filename);
3873 if (myDoc) {
3874 xmlFreeDoc(myDoc);
3875 } else {
3876 printf("parse failed\n");
3877 okay = 0;
3878 }
3879 if (!strcmp(filename, "test/threads/invalid.xml")) {
3880 if (xmlDoValidityCheckingDefaultValue != 0) {
3881 printf("ValidityCheckingDefaultValue override failed\n");
3882 okay = 0;
3883 }
3884 if (xmlGenericErrorContext != stdout) {
3885 printf("xmlGenericErrorContext override failed\n");
3886 okay = 0;
3887 }
3888 } else {
3889 if (xmlDoValidityCheckingDefaultValue != 1) {
3890 printf("ValidityCheckingDefaultValue override failed\n");
3891 okay = 0;
3892 }
3893 if (xmlGenericErrorContext != stderr) {
3894 printf("xmlGenericErrorContext override failed\n");
3895 okay = 0;
3896 }
3897 }
3898 if (okay == 0)
3899 return ((void *) Failed);
3900 return ((void *) Okay);
3901}
3902
3903#if defined(linux) || defined(solaris)
3904
3905#include <pthread.h>
3906
3907static pthread_t tid[MAX_ARGC];
3908
3909static int
3910testThread(void)
3911{
3912 unsigned int i, repeat;
3913 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
3914 void *results[MAX_ARGC];
3915 int ret;
3916 int res = 0;
3917
3918 xmlInitParser();
3919
3920 for (repeat = 0; repeat < 500; repeat++) {
3921 xmlLoadCatalog(catalog);
3922 nb_tests++;
3923
3924 for (i = 0; i < num_threads; i++) {
3925 results[i] = NULL;
3926 tid[i] = (pthread_t) - 1;
3927 }
3928
3929 for (i = 0; i < num_threads; i++) {
3930 ret = pthread_create(&tid[i], 0, thread_specific_data,
3931 (void *) testfiles[i]);
3932 if (ret != 0) {
3933 fprintf(stderr, "pthread_create failed\n");
3934 return (1);
3935 }
3936 }
3937 for (i = 0; i < num_threads; i++) {
3938 ret = pthread_join(tid[i], &results[i]);
3939 if (ret != 0) {
3940 fprintf(stderr, "pthread_join failed\n");
3941 return (1);
3942 }
3943 }
3944
3945 xmlCatalogCleanup();
3946 for (i = 0; i < num_threads; i++)
3947 if (results[i] != (void *) Okay) {
3948 fprintf(stderr, "Thread %d handling %s failed\n",
3949 i, testfiles[i]);
3950 res = 1;
3951 }
3952 }
3953 return (res);
3954}
3955
3956#elif defined WIN32
3957#include <windows.h>
3958#include <string.h>
3959
3960#define TEST_REPEAT_COUNT 500
3961
3962static HANDLE tid[MAX_ARGC];
3963
3964static DWORD WINAPI
3965win32_thread_specific_data(void *private_data)
3966{
3967 return((DWORD) thread_specific_data(private_data));
3968}
3969
3970static int
3971testThread(void)
3972{
3973 unsigned int i, repeat;
3974 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
3975 DWORD results[MAX_ARGC];
3976 BOOL ret;
3977 int res = 0;
3978
3979 xmlInitParser();
3980 for (repeat = 0; repeat < TEST_REPEAT_COUNT; repeat++) {
3981 xmlLoadCatalog(catalog);
3982 nb_tests++;
3983
3984 for (i = 0; i < num_threads; i++) {
3985 results[i] = 0;
3986 tid[i] = (HANDLE) - 1;
3987 }
3988
3989 for (i = 0; i < num_threads; i++) {
3990 DWORD useless;
3991
3992 tid[i] = CreateThread(NULL, 0,
3993 win32_thread_specific_data,
3994 (void *) testfiles[i], 0,
3995 &useless);
3996 if (tid[i] == NULL) {
3997 fprintf(stderr, "CreateThread failed\n");
3998 return(1);
3999 }
4000 }
4001
4002 if (WaitForMultipleObjects(num_threads, tid, TRUE, INFINITE) ==
4003 WAIT_FAILED) {
4004 fprintf(stderr, "WaitForMultipleObjects failed\n");
4005 return(1);
4006 }
4007
4008 for (i = 0; i < num_threads; i++) {
4009 ret = GetExitCodeThread(tid[i], &results[i]);
4010 if (ret == 0) {
4011 fprintf(stderr, "GetExitCodeThread failed\n");
4012 return(1);
4013 }
4014 CloseHandle(tid[i]);
4015 }
4016
4017 xmlCatalogCleanup();
4018 for (i = 0; i < num_threads; i++) {
4019 if (results[i] != (DWORD) Okay) {
4020 fprintf(stderr, "Thread %d handling %s failed\n",
4021 i, testfiles[i]);
4022 res = 1;
4023 }
4024 }
4025 }
4026
4027 return (res);
4028}
4029
4030#elif defined __BEOS__
4031#include <OS.h>
4032
4033static thread_id tid[MAX_ARGC];
4034
4035static int
4036testThread(void)
4037{
4038 unsigned int i, repeat;
4039 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
4040 void *results[MAX_ARGC];
4041 status_t ret;
4042 int res = 0;
4043
4044 xmlInitParser();
4045 for (repeat = 0; repeat < 500; repeat++) {
4046 xmlLoadCatalog(catalog);
4047 for (i = 0; i < num_threads; i++) {
4048 results[i] = NULL;
4049 tid[i] = (thread_id) - 1;
4050 }
4051 for (i = 0; i < num_threads; i++) {
4052 tid[i] =
4053 spawn_thread(thread_specific_data, "xmlTestThread",
4054 B_NORMAL_PRIORITY, (void *) testfiles[i]);
4055 if (tid[i] < B_OK) {
4056 fprintf(stderr, "beos_thread_create failed\n");
4057 return (1);
4058 }
4059 printf("beos_thread_create %d -> %d\n", i, tid[i]);
4060 }
4061 for (i = 0; i < num_threads; i++) {
4062 ret = wait_for_thread(tid[i], &results[i]);
4063 printf("beos_thread_wait %d -> %d\n", i, ret);
4064 if (ret != B_OK) {
4065 fprintf(stderr, "beos_thread_wait failed\n");
4066 return (1);
4067 }
4068 }
4069
4070 xmlCatalogCleanup();
4071 ret = B_OK;
4072 for (i = 0; i < num_threads; i++)
4073 if (results[i] != (void *) Okay) {
4074 printf("Thread %d handling %s failed\n", i, testfiles[i]);
4075 ret = B_ERROR;
4076 }
4077 }
4078 if (ret != B_OK)
4079 return(1);
4080 return (0);
4081}
4082#else
4083static int
4084testThread(void)
4085{
4086 fprintf(stderr,
4087 "Specific platform thread support not detected\n");
4088 return (-1);
4089}
4090#endif
4091static int
4092threadsTest(const char *filename ATTRIBUTE_UNUSED,
4093 const char *resul ATTRIBUTE_UNUSED,
4094 const char *err ATTRIBUTE_UNUSED,
4095 int options ATTRIBUTE_UNUSED) {
4096 return(testThread());
4097}
4098#endif
4099/************************************************************************
4100 * *
4101 * Tests Descriptions *
4102 * *
4103 ************************************************************************/
4104
4105static
4106testDesc testDescriptions[] = {
4107 { "XML regression tests" ,
4108 oldParseTest, "./test/*", "result/", "", NULL,
4109 0 },
4110 { "XML regression tests on memory" ,
4111 memParseTest, "./test/*", "result/", "", NULL,
4112 0 },
4113 { "XML entity subst regression tests" ,
4114 noentParseTest, "./test/*", "result/noent/", "", NULL,
4115 XML_PARSE_NOENT },
4116 { "XML Namespaces regression tests",
4117 errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err",
4118 0 },
4119 { "Error cases regression tests",
4120 errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err",
4121 0 },
4122#ifdef LIBXML_READER_ENABLED
4123 { "Error cases stream regression tests",
4124 streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str",
4125 0 },
4126 { "Reader regression tests",
4127 streamParseTest, "./test/*", "result/", ".rdr", NULL,
4128 0 },
4129 { "Reader entities substitution regression tests",
4130 streamParseTest, "./test/*", "result/", ".rde", NULL,
4131 XML_PARSE_NOENT },
4132 { "Reader on memory regression tests",
4133 streamMemParseTest, "./test/*", "result/", ".rdr", NULL,
4134 0 },
4135 { "Walker regression tests",
4136 walkerParseTest, "./test/*", "result/", ".rdr", NULL,
4137 0 },
4138#endif
4139#ifdef LIBXML_SAX1_ENABLED
4140 { "SAX1 callbacks regression tests" ,
4141 saxParseTest, "./test/*", "result/", ".sax", NULL,
4142 XML_PARSE_SAX1 },
4143 { "SAX2 callbacks regression tests" ,
4144 saxParseTest, "./test/*", "result/", ".sax2", NULL,
4145 0 },
4146#endif
4147#ifdef LIBXML_PUSH_ENABLED
4148 { "XML push regression tests" ,
4149 pushParseTest, "./test/*", "result/", "", NULL,
4150 0 },
4151#endif
4152#ifdef LIBXML_HTML_ENABLED
4153 { "HTML regression tests" ,
4154 errParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4155 XML_PARSE_HTML },
4156#ifdef LIBXML_PUSH_ENABLED
4157 { "Push HTML regression tests" ,
4158 pushParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4159 XML_PARSE_HTML },
4160#endif
4161#ifdef LIBXML_SAX1_ENABLED
4162 { "HTML SAX regression tests" ,
4163 saxParseTest, "./test/HTML/*", "result/HTML/", ".sax", NULL,
4164 XML_PARSE_HTML },
4165#endif
4166#endif
4167#ifdef LIBXML_VALID_ENABLED
4168 { "Valid documents regression tests" ,
4169 errParseTest, "./test/VCM/*", NULL, NULL, NULL,
4170 XML_PARSE_DTDVALID },
4171 { "Validity checking regression tests" ,
4172 errParseTest, "./test/VC/*", "result/VC/", NULL, "",
4173 XML_PARSE_DTDVALID },
4174 { "General documents valid regression tests" ,
4175 errParseTest, "./test/valid/*", "result/valid/", "", ".err",
4176 XML_PARSE_DTDVALID },
4177#endif
4178#ifdef LIBXML_XINCLUDE_ENABLED
4179 { "XInclude regression tests" ,
4180 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4181 /* Ignore errors at this point ".err", */
4182 XML_PARSE_XINCLUDE },
4183 { "XInclude xmlReader regression tests",
4184 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4185 /* Ignore errors at this point ".err", */
4186 NULL, XML_PARSE_XINCLUDE },
4187 { "XInclude regression tests stripping include nodes" ,
4188 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4189 /* Ignore errors at this point ".err", */
4190 XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
4191 { "XInclude xmlReader regression tests stripping include nodes",
4192 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4193 /* Ignore errors at this point ".err", */
4194 NULL, XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
4195#endif
4196#ifdef LIBXML_XPATH_ENABLED
4197#ifdef LIBXML_DEBUG_ENABLED
4198 { "XPath expressions regression tests" ,
4199 xpathExprTest, "./test/XPath/expr/*", "result/XPath/expr/", "", NULL,
4200 0 },
4201 { "XPath document queries regression tests" ,
4202 xpathDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4203 0 },
4204#ifdef LIBXML_XPTR_ENABLED
4205 { "XPointer document queries regression tests" ,
4206 xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4207 0 },
4208#endif
4209 { "xml:id regression tests" ,
4210 xmlidDocTest, "./test/xmlid/*", "result/xmlid/", "", ".err",
4211 0 },
4212#endif
4213#endif
4214 { "URI parsing tests" ,
4215 uriParseTest, "./test/URI/*.uri", "result/URI/", "", NULL,
4216 0 },
4217 { "URI base composition tests" ,
4218 uriBaseTest, "./test/URI/*.data", "result/URI/", "", NULL,
4219 0 },
Daniel Veillard336a8e12005-08-07 10:46:19 +00004220 { "Path URI conversion tests" ,
4221 uriPathTest, NULL, NULL, NULL, NULL,
4222 0 },
William M. Brackca15a542005-07-06 20:41:33 +00004223#ifdef LIBXML_SCHEMAS_ENABLED
4224 { "Schemas regression tests" ,
4225 schemasTest, "./test/schemas/*_*.xsd", NULL, NULL, NULL,
4226 0 },
4227 { "Relax-NG regression tests" ,
4228 rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4229 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4230#ifdef LIBXML_READER_ENABLED
4231 { "Relax-NG streaming regression tests" ,
4232 rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4233 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4234#endif
4235#endif
4236#ifdef LIBXML_PATTERN_ENABLED
4237#ifdef LIBXML_READER_ENABLED
4238 { "Pattern regression tests" ,
4239 patternTest, "./test/pattern/*.pat", "result/pattern/", NULL, NULL,
4240 0 },
4241#endif
4242#endif
4243#ifdef LIBXML_C14N_ENABLED
4244 { "C14N with comments regression tests" ,
4245 c14nWithCommentTest, "./test/c14n/with-comments/*.xml", NULL, NULL, NULL,
4246 0 },
4247 { "C14N without comments regression tests" ,
4248 c14nWithoutCommentTest, "./test/c14n/without-comments/*.xml", NULL, NULL, NULL,
4249 0 },
4250 { "C14N exclusive without comments regression tests" ,
4251 c14nExcWithoutCommentTest, "./test/c14n/exc-without-comments/*.xml", NULL, NULL, NULL,
4252 0 },
4253#endif
Daniel Veillardbca3ad22005-08-23 22:14:02 +00004254#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) && defined(LIBXML_SAX1_ENABLED)
William M. Brackca15a542005-07-06 20:41:33 +00004255 { "Catalog and Threads regression tests" ,
4256 threadsTest, NULL, NULL, NULL, NULL,
4257 0 },
4258#endif
4259 {NULL, NULL, NULL, NULL, NULL, NULL, 0}
4260};
4261
4262/************************************************************************
4263 * *
4264 * The main code driving the tests *
4265 * *
4266 ************************************************************************/
4267
4268static int
4269launchTests(testDescPtr tst) {
4270 int res = 0, err = 0;
4271 size_t i;
4272 char *result;
4273 char *error;
4274 int mem;
4275
4276 if (tst == NULL) return(-1);
4277 if (tst->in != NULL) {
4278 glob_t globbuf;
4279
4280 globbuf.gl_offs = 0;
4281 glob(tst->in, GLOB_DOOFFS, NULL, &globbuf);
4282 for (i = 0;i < globbuf.gl_pathc;i++) {
4283 if (!checkTestFile(globbuf.gl_pathv[i]))
4284 continue;
4285 if (tst->suffix != NULL) {
4286 result = resultFilename(globbuf.gl_pathv[i], tst->out,
4287 tst->suffix);
4288 if (result == NULL) {
4289 fprintf(stderr, "Out of memory !\n");
4290 fatalError();
4291 }
4292 } else {
4293 result = NULL;
4294 }
4295 if (tst->err != NULL) {
4296 error = resultFilename(globbuf.gl_pathv[i], tst->out,
4297 tst->err);
4298 if (error == NULL) {
4299 fprintf(stderr, "Out of memory !\n");
4300 fatalError();
4301 }
4302 } else {
4303 error = NULL;
4304 }
4305 if ((result) &&(!checkTestFile(result))) {
4306 fprintf(stderr, "Missing result file %s\n", result);
4307 } else if ((error) &&(!checkTestFile(error))) {
4308 fprintf(stderr, "Missing error file %s\n", error);
4309 } else {
4310 mem = xmlMemUsed();
4311 extraMemoryFromResolver = 0;
4312 testErrorsSize = 0;
4313 testErrors[0] = 0;
4314 res = tst->func(globbuf.gl_pathv[i], result, error,
Daniel Veillard8874b942005-08-25 13:19:21 +00004315 tst->options | XML_PARSE_COMPACT);
William M. Brackca15a542005-07-06 20:41:33 +00004316 xmlResetLastError();
4317 if (res != 0) {
4318 fprintf(stderr, "File %s generated an error\n",
4319 globbuf.gl_pathv[i]);
4320 nb_errors++;
4321 err++;
4322 }
4323 else if (xmlMemUsed() != mem) {
4324 if ((xmlMemUsed() != mem) &&
4325 (extraMemoryFromResolver == 0)) {
4326 fprintf(stderr, "File %s leaked %d bytes\n",
4327 globbuf.gl_pathv[i], xmlMemUsed() - mem);
4328 nb_leaks++;
4329 err++;
4330 }
4331 }
4332 testErrorsSize = 0;
4333 }
4334 if (result)
4335 free(result);
4336 if (error)
4337 free(error);
4338 }
4339 globfree(&globbuf);
4340 } else {
4341 testErrorsSize = 0;
4342 testErrors[0] = 0;
4343 extraMemoryFromResolver = 0;
4344 res = tst->func(NULL, NULL, NULL, tst->options);
4345 if (res != 0) {
4346 nb_errors++;
4347 err++;
4348 }
4349 }
4350 return(err);
4351}
4352
Daniel Veillarddb68b742005-07-30 13:18:24 +00004353static int verbose = 0;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004354static int tests_quiet = 0;
Daniel Veillarddb68b742005-07-30 13:18:24 +00004355
4356static int
4357runtest(int i) {
4358 int ret = 0, res;
4359 int old_errors, old_tests, old_leaks;
4360
4361 old_errors = nb_errors;
4362 old_tests = nb_tests;
4363 old_leaks = nb_leaks;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004364 if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
Daniel Veillarddb68b742005-07-30 13:18:24 +00004365 printf("## %s\n", testDescriptions[i].desc);
4366 res = launchTests(&testDescriptions[i]);
4367 if (res != 0)
4368 ret++;
4369 if (verbose) {
4370 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
4371 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
4372 else
4373 printf("Ran %d tests, %d errors, %d leaks\n",
4374 nb_tests - old_tests,
4375 nb_errors - old_errors,
4376 nb_leaks - old_leaks);
4377 }
4378 return(ret);
4379}
4380
William M. Brackca15a542005-07-06 20:41:33 +00004381int
4382main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
Daniel Veillarddb68b742005-07-30 13:18:24 +00004383 int i, a, ret = 0;
4384 int subset = 0;
William M. Brackca15a542005-07-06 20:41:33 +00004385
4386 initializeLibxml2();
4387
Daniel Veillarddb68b742005-07-30 13:18:24 +00004388
4389 for (a = 1; a < argc;a++) {
4390 if (!strcmp(argv[a], "-v"))
4391 verbose = 1;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004392 else if (!strcmp(argv[a], "-quiet"))
4393 tests_quiet = 1;
Daniel Veillarddb68b742005-07-30 13:18:24 +00004394 else {
4395 for (i = 0; testDescriptions[i].func != NULL; i++) {
4396 if (strstr(testDescriptions[i].desc, argv[a])) {
4397 ret += runtest(i);
4398 subset++;
4399 }
4400 }
4401 }
4402 }
4403 if (subset == 0) {
4404 for (i = 0; testDescriptions[i].func != NULL; i++) {
4405 ret += runtest(i);
William M. Brackca15a542005-07-06 20:41:33 +00004406 }
4407 }
4408 if ((nb_errors == 0) && (nb_leaks == 0)) {
4409 ret = 0;
4410 printf("Total %d tests, no errors\n",
4411 nb_tests);
4412 } else {
4413 ret = 1;
4414 printf("Total %d tests, %d errors, %d leaks\n",
4415 nb_tests, nb_errors, nb_leaks);
4416 }
4417 xmlCleanupParser();
4418 xmlMemoryDump();
4419
4420 return(ret);
4421}
4422
4423#else /* ! LIBXML_OUTPUT_ENABLED */
4424int
4425main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
4426 fprintf(stderr, "runtest requires output to be enabled in libxml2\n");
4427 return(1);
4428}
4429#endif