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