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