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