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