blob: c98995359d46bede2db79104c04accaf06683f7a [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 Veillardaa6de472008-08-25 14:53:31 +00003260 (!strcmp(prefix, "tutor3_2")) || (!strcmp(prefix, "307377")))
William M. Brackca15a542005-07-06 20:41:33 +00003261 disable_err = 1;
3262
3263 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
3264 pattern[499] = 0;
3265
3266 globbuf.gl_offs = 0;
3267 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3268 for (i = 0;i < globbuf.gl_pathc;i++) {
3269 testErrorsSize = 0;
3270 testErrors[0] = 0;
3271 instance = globbuf.gl_pathv[i];
3272 base2 = baseFilename(instance);
3273 len = strlen(base2);
3274 if ((len > 6) && (base2[len - 6] == '_')) {
3275 count = base2[len - 5];
3276 snprintf(result, 499, "result/relaxng/%s_%c",
3277 prefix, count);
3278 result[499] = 0;
3279 snprintf(err, 499, "result/relaxng/%s_%c.err",
3280 prefix, count);
3281 err[499] = 0;
3282 } else {
3283 fprintf(stderr, "don't know how to process %s\n", instance);
3284 continue;
3285 }
3286 reader = xmlReaderForFile(instance, NULL, options);
3287 if (reader == NULL) {
3288 fprintf(stderr, "Failed to build reder for %s\n", instance);
3289 }
3290 if (disable_err == 1)
3291 ret = streamProcessTest(instance, result, NULL, reader, filename);
3292 else
3293 ret = streamProcessTest(instance, result, err, reader, filename);
3294 xmlFreeTextReader(reader);
3295 if (ret != 0) {
3296 fprintf(stderr, "instance %s failed\n", instance);
3297 res = ret;
3298 }
3299 }
3300 globfree(&globbuf);
3301
3302 return(res);
3303}
3304#endif /* READER */
3305
3306#endif
3307
3308#ifdef LIBXML_PATTERN_ENABLED
3309#ifdef LIBXML_READER_ENABLED
3310/************************************************************************
3311 * *
3312 * Patterns tests *
3313 * *
3314 ************************************************************************/
3315static void patternNode(FILE *out, xmlTextReaderPtr reader,
3316 const char *pattern, xmlPatternPtr patternc,
3317 xmlStreamCtxtPtr patstream) {
3318 xmlChar *path = NULL;
3319 int match = -1;
3320 int type, empty;
3321
3322 type = xmlTextReaderNodeType(reader);
3323 empty = xmlTextReaderIsEmptyElement(reader);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003324
William M. Brackca15a542005-07-06 20:41:33 +00003325 if (type == XML_READER_TYPE_ELEMENT) {
3326 /* do the check only on element start */
3327 match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader));
3328
3329 if (match) {
3330 path = xmlGetNodePath(xmlTextReaderCurrentNode(reader));
3331 fprintf(out, "Node %s matches pattern %s\n", path, pattern);
3332 }
3333 }
3334 if (patstream != NULL) {
3335 int ret;
3336
3337 if (type == XML_READER_TYPE_ELEMENT) {
3338 ret = xmlStreamPush(patstream,
3339 xmlTextReaderConstLocalName(reader),
3340 xmlTextReaderConstNamespaceUri(reader));
3341 if (ret < 0) {
3342 fprintf(out, "xmlStreamPush() failure\n");
3343 xmlFreeStreamCtxt(patstream);
3344 patstream = NULL;
3345 } else if (ret != match) {
3346 if (path == NULL) {
3347 path = xmlGetNodePath(
3348 xmlTextReaderCurrentNode(reader));
3349 }
3350 fprintf(out,
3351 "xmlPatternMatch and xmlStreamPush disagree\n");
3352 fprintf(out,
3353 " pattern %s node %s\n",
3354 pattern, path);
3355 }
William M. Brackca15a542005-07-06 20:41:33 +00003356
Daniel Veillardaa6de472008-08-25 14:53:31 +00003357
3358 }
William M. Brackca15a542005-07-06 20:41:33 +00003359 if ((type == XML_READER_TYPE_END_ELEMENT) ||
3360 ((type == XML_READER_TYPE_ELEMENT) && (empty))) {
3361 ret = xmlStreamPop(patstream);
3362 if (ret < 0) {
3363 fprintf(out, "xmlStreamPop() failure\n");
3364 xmlFreeStreamCtxt(patstream);
3365 patstream = NULL;
3366 }
3367 }
3368 }
3369 if (path != NULL)
3370 xmlFree(path);
3371}
3372
3373/**
3374 * patternTest:
3375 * @filename: the schemas file
3376 * @result: the file with expected result
3377 * @err: the file with error messages
3378 *
Daniel Veillardaa6de472008-08-25 14:53:31 +00003379 * Parse a set of files with streaming, applying an RNG schemas
William M. Brackca15a542005-07-06 20:41:33 +00003380 *
3381 * Returns 0 in case of success, an error code otherwise
3382 */
3383static int
3384patternTest(const char *filename,
3385 const char *resul ATTRIBUTE_UNUSED,
3386 const char *err ATTRIBUTE_UNUSED,
3387 int options) {
3388 xmlPatternPtr patternc = NULL;
3389 xmlStreamCtxtPtr patstream = NULL;
3390 FILE *o, *f;
3391 char str[1024];
3392 char xml[500];
3393 char result[500];
3394 int len, i;
3395 int ret = 0, res;
3396 char *temp;
3397 xmlTextReaderPtr reader;
3398 xmlDocPtr doc;
3399
3400 len = strlen(filename);
3401 len -= 4;
3402 memcpy(xml, filename, len);
3403 xml[len] = 0;
3404 snprintf(result, 499, "result/pattern/%s", baseFilename(xml));
3405 result[499] = 0;
3406 memcpy(xml + len, ".xml", 5);
3407
3408 if (!checkTestFile(xml)) {
3409 fprintf(stderr, "Missing xml file %s\n", xml);
3410 return(-1);
3411 }
3412 if (!checkTestFile(result)) {
3413 fprintf(stderr, "Missing result file %s\n", result);
3414 return(-1);
3415 }
3416 f = fopen(filename, "rb");
3417 if (f == NULL) {
3418 fprintf(stderr, "Failed to open %s\n", filename);
3419 return(-1);
3420 }
3421 temp = resultFilename(filename, "", ".res");
3422 if (temp == NULL) {
3423 fprintf(stderr, "Out of memory\n");
3424 fatalError();
3425 }
3426 o = fopen(temp, "wb");
3427 if (o == NULL) {
3428 fprintf(stderr, "failed to open output file %s\n", temp);
3429 fclose(f);
3430 free(temp);
3431 return(-1);
3432 }
3433 while (1) {
3434 /*
3435 * read one line in string buffer.
3436 */
3437 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
3438 break;
3439
3440 /*
3441 * remove the ending spaces
3442 */
3443 i = strlen(str);
3444 while ((i > 0) &&
3445 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
3446 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
3447 i--;
3448 str[i] = 0;
3449 }
3450 doc = xmlReadFile(xml, NULL, options);
3451 if (doc == NULL) {
3452 fprintf(stderr, "Failed to parse %s\n", xml);
3453 ret = 1;
3454 } else {
3455 xmlNodePtr root;
3456 const xmlChar *namespaces[22];
3457 int j;
3458 xmlNsPtr ns;
3459
3460 root = xmlDocGetRootElement(doc);
3461 for (ns = root->nsDef, j = 0;ns != NULL && j < 20;ns=ns->next) {
3462 namespaces[j++] = ns->href;
3463 namespaces[j++] = ns->prefix;
3464 }
3465 namespaces[j++] = NULL;
3466 namespaces[j++] = NULL;
3467
3468 patternc = xmlPatterncompile((const xmlChar *) str, doc->dict,
3469 0, &namespaces[0]);
3470 if (patternc == NULL) {
3471 testErrorHandler(NULL,
3472 "Pattern %s failed to compile\n", str);
3473 xmlFreeDoc(doc);
3474 ret = 1;
3475 continue;
3476 }
3477 patstream = xmlPatternGetStreamCtxt(patternc);
3478 if (patstream != NULL) {
3479 ret = xmlStreamPush(patstream, NULL, NULL);
3480 if (ret < 0) {
3481 fprintf(stderr, "xmlStreamPush() failure\n");
3482 xmlFreeStreamCtxt(patstream);
3483 patstream = NULL;
3484 }
3485 }
3486 nb_tests++;
3487
3488 reader = xmlReaderWalker(doc);
3489 res = xmlTextReaderRead(reader);
3490 while (res == 1) {
3491 patternNode(o, reader, str, patternc, patstream);
3492 res = xmlTextReaderRead(reader);
3493 }
3494 if (res != 0) {
3495 fprintf(o, "%s : failed to parse\n", filename);
3496 }
3497 xmlFreeTextReader(reader);
3498 xmlFreeDoc(doc);
3499 xmlFreeStreamCtxt(patstream);
3500 patstream = NULL;
3501 xmlFreePattern(patternc);
3502
3503 }
3504 }
3505
3506 fclose(f);
3507 fclose(o);
3508
3509 ret = compareFiles(temp, result);
3510 if (ret) {
3511 fprintf(stderr, "Result for %s failed\n", filename);
3512 ret = 1;
3513 }
3514 unlink(temp);
3515 free(temp);
3516 return(ret);
3517}
3518#endif /* READER */
3519#endif /* PATTERN */
3520#ifdef LIBXML_C14N_ENABLED
3521/************************************************************************
3522 * *
3523 * Canonicalization tests *
3524 * *
3525 ************************************************************************/
3526static xmlXPathObjectPtr
3527load_xpath_expr (xmlDocPtr parent_doc, const char* filename) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00003528 xmlXPathObjectPtr xpath;
William M. Brackca15a542005-07-06 20:41:33 +00003529 xmlDocPtr doc;
3530 xmlChar *expr;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003531 xmlXPathContextPtr ctx;
William M. Brackca15a542005-07-06 20:41:33 +00003532 xmlNodePtr node;
3533 xmlNsPtr ns;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003534
William M. Brackca15a542005-07-06 20:41:33 +00003535 /*
3536 * load XPath expr as a file
3537 */
3538 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3539 xmlSubstituteEntitiesDefault(1);
3540
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003541 doc = xmlReadFile(filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
William M. Brackca15a542005-07-06 20:41:33 +00003542 if (doc == NULL) {
3543 fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
3544 return(NULL);
3545 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003546
William M. Brackca15a542005-07-06 20:41:33 +00003547 /*
3548 * Check the document is of the right kind
Daniel Veillardaa6de472008-08-25 14:53:31 +00003549 */
William M. Brackca15a542005-07-06 20:41:33 +00003550 if(xmlDocGetRootElement(doc) == NULL) {
3551 fprintf(stderr,"Error: empty document for file \"%s\"\n", filename);
3552 xmlFreeDoc(doc);
3553 return(NULL);
3554 }
3555
3556 node = doc->children;
3557 while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) {
3558 node = node->next;
3559 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003560
3561 if(node == NULL) {
William M. Brackca15a542005-07-06 20:41:33 +00003562 fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename);
3563 xmlFreeDoc(doc);
3564 return(NULL);
3565 }
3566
3567 expr = xmlNodeGetContent(node);
3568 if(expr == NULL) {
3569 fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename);
3570 xmlFreeDoc(doc);
3571 return(NULL);
3572 }
3573
3574 ctx = xmlXPathNewContext(parent_doc);
3575 if(ctx == NULL) {
3576 fprintf(stderr,"Error: unable to create new context\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003577 xmlFree(expr);
3578 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003579 return(NULL);
3580 }
3581
3582 /*
3583 * Register namespaces
3584 */
3585 ns = node->nsDef;
3586 while(ns != NULL) {
3587 if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) {
3588 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 +00003589 xmlFree(expr);
3590 xmlXPathFreeContext(ctx);
3591 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003592 return(NULL);
3593 }
3594 ns = ns->next;
3595 }
3596
Daniel Veillardaa6de472008-08-25 14:53:31 +00003597 /*
William M. Brackca15a542005-07-06 20:41:33 +00003598 * Evaluate xpath
3599 */
3600 xpath = xmlXPathEvalExpression(expr, ctx);
3601 if(xpath == NULL) {
3602 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003603xmlFree(expr);
3604 xmlXPathFreeContext(ctx);
3605 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003606 return(NULL);
3607 }
3608
3609 /* print_xpath_nodes(xpath->nodesetval); */
3610
Daniel Veillardaa6de472008-08-25 14:53:31 +00003611 xmlFree(expr);
3612 xmlXPathFreeContext(ctx);
3613 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003614 return(xpath);
3615}
3616
3617/*
3618 * Macro used to grow the current buffer.
3619 */
3620#define xxx_growBufferReentrant() { \
3621 buffer_size *= 2; \
3622 buffer = (xmlChar **) \
Daniel Veillardaa6de472008-08-25 14:53:31 +00003623 xmlRealloc(buffer, buffer_size * sizeof(xmlChar*)); \
William M. Brackca15a542005-07-06 20:41:33 +00003624 if (buffer == NULL) { \
3625 perror("realloc failed"); \
3626 return(NULL); \
3627 } \
3628}
3629
3630static xmlChar **
3631parse_list(xmlChar *str) {
3632 xmlChar **buffer;
3633 xmlChar **out = NULL;
3634 int buffer_size = 0;
3635 int len;
3636
3637 if(str == NULL) {
3638 return(NULL);
3639 }
3640
3641 len = xmlStrlen(str);
3642 if((str[0] == '\'') && (str[len - 1] == '\'')) {
3643 str[len - 1] = '\0';
3644 str++;
3645 len -= 2;
3646 }
3647 /*
3648 * allocate an translation buffer.
3649 */
3650 buffer_size = 1000;
3651 buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*));
3652 if (buffer == NULL) {
3653 perror("malloc failed");
3654 return(NULL);
3655 }
3656 out = buffer;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003657
William M. Brackca15a542005-07-06 20:41:33 +00003658 while(*str != '\0') {
3659 if (out - buffer > buffer_size - 10) {
3660 int indx = out - buffer;
3661
3662 xxx_growBufferReentrant();
3663 out = &buffer[indx];
3664 }
3665 (*out++) = str;
3666 while(*str != ',' && *str != '\0') ++str;
3667 if(*str == ',') *(str++) = '\0';
3668 }
3669 (*out) = NULL;
3670 return buffer;
3671}
3672
Daniel Veillardaa6de472008-08-25 14:53:31 +00003673static int
Aleksey Sanin83868242009-07-09 10:26:22 +02003674c14nRunTest(const char* xml_filename, int with_comments, int mode,
William M. Brackca15a542005-07-06 20:41:33 +00003675 const char* xpath_filename, const char *ns_filename,
3676 const char* result_file) {
3677 xmlDocPtr doc;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003678 xmlXPathObjectPtr xpath = NULL;
William M. Brackca15a542005-07-06 20:41:33 +00003679 xmlChar *result = NULL;
3680 int ret;
3681 xmlChar **inclusive_namespaces = NULL;
3682 const char *nslist = NULL;
3683 int nssize;
3684
3685
3686 /*
3687 * build an XML tree from a the file; we need to add default
3688 * attributes and resolve all character and entities references
3689 */
3690 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3691 xmlSubstituteEntitiesDefault(1);
3692
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003693 doc = xmlReadFile(xml_filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
William M. Brackca15a542005-07-06 20:41:33 +00003694 if (doc == NULL) {
3695 fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename);
3696 return(-1);
3697 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003698
William M. Brackca15a542005-07-06 20:41:33 +00003699 /*
3700 * Check the document is of the right kind
Daniel Veillardaa6de472008-08-25 14:53:31 +00003701 */
William M. Brackca15a542005-07-06 20:41:33 +00003702 if(xmlDocGetRootElement(doc) == NULL) {
3703 fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename);
3704 xmlFreeDoc(doc);
3705 return(-1);
3706 }
3707
Daniel Veillardaa6de472008-08-25 14:53:31 +00003708 /*
3709 * load xpath file if specified
William M. Brackca15a542005-07-06 20:41:33 +00003710 */
3711 if(xpath_filename) {
3712 xpath = load_xpath_expr(doc, xpath_filename);
3713 if(xpath == NULL) {
3714 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003715 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003716 return(-1);
3717 }
3718 }
3719
3720 if (ns_filename != NULL) {
3721 if (loadMem(ns_filename, &nslist, &nssize)) {
3722 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3723 if(xpath != NULL) xmlXPathFreeObject(xpath);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003724 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003725 return(-1);
3726 }
3727 inclusive_namespaces = parse_list((xmlChar *) nslist);
3728 }
3729
3730 /*
3731 * Canonical form
Daniel Veillardaa6de472008-08-25 14:53:31 +00003732 */
William M. Brackca15a542005-07-06 20:41:33 +00003733 /* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */
Daniel Veillardaa6de472008-08-25 14:53:31 +00003734 ret = xmlC14NDocDumpMemory(doc,
3735 (xpath) ? xpath->nodesetval : NULL,
Aleksey Sanin83868242009-07-09 10:26:22 +02003736 mode, inclusive_namespaces,
William M. Brackca15a542005-07-06 20:41:33 +00003737 with_comments, &result);
3738 if (ret >= 0) {
3739 if(result != NULL) {
3740 if (compareFileMem(result_file, (const char *) result, ret)) {
3741 fprintf(stderr, "Result mismatch for %s\n", xml_filename);
Aleksey Sanin83868242009-07-09 10:26:22 +02003742 fprintf(stderr, "RESULT:\n%s\n", (const char*)result);
William M. Brackca15a542005-07-06 20:41:33 +00003743 ret = -1;
3744 }
3745 }
3746 } else {
3747 fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret);
3748 ret = -1;
3749 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003750
William M. Brackca15a542005-07-06 20:41:33 +00003751 /*
3752 * Cleanup
Daniel Veillardaa6de472008-08-25 14:53:31 +00003753 */
William M. Brackca15a542005-07-06 20:41:33 +00003754 if (result != NULL) xmlFree(result);
3755 if(xpath != NULL) xmlXPathFreeObject(xpath);
3756 if (inclusive_namespaces != NULL) xmlFree(inclusive_namespaces);
3757 if (nslist != NULL) free((char *) nslist);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003758 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003759
3760 return(ret);
3761}
3762
3763static int
Aleksey Sanin83868242009-07-09 10:26:22 +02003764c14nCommonTest(const char *filename, int with_comments, int mode,
William M. Brackca15a542005-07-06 20:41:33 +00003765 const char *subdir) {
3766 char buf[500];
3767 char prefix[500];
3768 const char *base;
3769 int len;
3770 char *result = NULL;
3771 char *xpath = NULL;
3772 char *ns = NULL;
3773 int ret = 0;
3774
3775 base = baseFilename(filename);
3776 len = strlen(base);
3777 len -= 4;
3778 memcpy(prefix, base, len);
3779 prefix[len] = 0;
3780
3781 snprintf(buf, 499, "result/c14n/%s/%s", subdir,prefix);
3782 if (!checkTestFile(buf)) {
3783 fprintf(stderr, "Missing result file %s", buf);
3784 return(-1);
3785 }
3786 result = strdup(buf);
3787 snprintf(buf, 499, "test/c14n/%s/%s.xpath", subdir,prefix);
3788 if (checkTestFile(buf)) {
3789 xpath = strdup(buf);
3790 }
3791 snprintf(buf, 499, "test/c14n/%s/%s.ns", subdir,prefix);
3792 if (checkTestFile(buf)) {
3793 ns = strdup(buf);
3794 }
3795
3796 nb_tests++;
Aleksey Sanin83868242009-07-09 10:26:22 +02003797 if (c14nRunTest(filename, with_comments, mode,
William M. Brackca15a542005-07-06 20:41:33 +00003798 xpath, ns, result) < 0)
3799 ret = 1;
3800
3801 if (result != NULL) free(result);
3802 if (xpath != NULL) free(xpath);
3803 if (ns != NULL) free(ns);
3804 return(ret);
3805}
3806
3807static int
3808c14nWithCommentTest(const char *filename,
3809 const char *resul ATTRIBUTE_UNUSED,
3810 const char *err ATTRIBUTE_UNUSED,
3811 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003812 return(c14nCommonTest(filename, 1, XML_C14N_1_0, "with-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003813}
3814static int
3815c14nWithoutCommentTest(const char *filename,
3816 const char *resul ATTRIBUTE_UNUSED,
3817 const char *err ATTRIBUTE_UNUSED,
3818 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003819 return(c14nCommonTest(filename, 0, XML_C14N_1_0, "without-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003820}
3821static int
3822c14nExcWithoutCommentTest(const char *filename,
3823 const char *resul ATTRIBUTE_UNUSED,
3824 const char *err ATTRIBUTE_UNUSED,
3825 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003826 return(c14nCommonTest(filename, 0, XML_C14N_EXCLUSIVE_1_0, "exc-without-comments"));
3827}
3828static int
3829c14n11WithoutCommentTest(const char *filename,
3830 const char *resul ATTRIBUTE_UNUSED,
3831 const char *err ATTRIBUTE_UNUSED,
3832 int options ATTRIBUTE_UNUSED) {
3833 return(c14nCommonTest(filename, 0, XML_C14N_1_1, "1-1-without-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003834}
3835#endif
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003836#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) && defined (LIBXML_SAX1_ENABLED)
William M. Brackca15a542005-07-06 20:41:33 +00003837/************************************************************************
3838 * *
3839 * Catalog and threads test *
3840 * *
3841 ************************************************************************/
3842
3843/*
3844 * mostly a cut and paste from testThreads.c
3845 */
3846#define MAX_ARGC 20
3847
3848static const char *catalog = "test/threads/complex.xml";
3849static const char *testfiles[] = {
3850 "test/threads/abc.xml",
3851 "test/threads/acb.xml",
3852 "test/threads/bac.xml",
3853 "test/threads/bca.xml",
3854 "test/threads/cab.xml",
3855 "test/threads/cba.xml",
3856 "test/threads/invalid.xml",
3857};
3858
Daniel Veillard24505b02005-07-28 23:49:35 +00003859static const char *Okay = "OK";
3860static const char *Failed = "Failed";
William M. Brackca15a542005-07-06 20:41:33 +00003861
3862#ifndef xmlDoValidityCheckingDefaultValue
3863#error xmlDoValidityCheckingDefaultValue is not a macro
3864#endif
3865#ifndef xmlGenericErrorContext
3866#error xmlGenericErrorContext is not a macro
3867#endif
3868
3869static void *
3870thread_specific_data(void *private_data)
3871{
3872 xmlDocPtr myDoc;
3873 const char *filename = (const char *) private_data;
3874 int okay = 1;
3875
3876 if (!strcmp(filename, "test/threads/invalid.xml")) {
3877 xmlDoValidityCheckingDefaultValue = 0;
3878 xmlGenericErrorContext = stdout;
3879 } else {
3880 xmlDoValidityCheckingDefaultValue = 1;
3881 xmlGenericErrorContext = stderr;
3882 }
3883 myDoc = xmlParseFile(filename);
3884 if (myDoc) {
3885 xmlFreeDoc(myDoc);
3886 } else {
3887 printf("parse failed\n");
3888 okay = 0;
3889 }
3890 if (!strcmp(filename, "test/threads/invalid.xml")) {
3891 if (xmlDoValidityCheckingDefaultValue != 0) {
3892 printf("ValidityCheckingDefaultValue override failed\n");
3893 okay = 0;
3894 }
3895 if (xmlGenericErrorContext != stdout) {
3896 printf("xmlGenericErrorContext override failed\n");
3897 okay = 0;
3898 }
3899 } else {
3900 if (xmlDoValidityCheckingDefaultValue != 1) {
3901 printf("ValidityCheckingDefaultValue override failed\n");
3902 okay = 0;
3903 }
3904 if (xmlGenericErrorContext != stderr) {
3905 printf("xmlGenericErrorContext override failed\n");
3906 okay = 0;
3907 }
3908 }
3909 if (okay == 0)
3910 return ((void *) Failed);
3911 return ((void *) Okay);
3912}
3913
CEST 2008 Sven Herzbergdc41d862008-08-07 13:52:30 +00003914#if defined(linux) || defined(solaris) || defined(__APPLE_CC__)
William M. Brackca15a542005-07-06 20:41:33 +00003915
3916#include <pthread.h>
3917
3918static pthread_t tid[MAX_ARGC];
3919
3920static int
3921testThread(void)
3922{
3923 unsigned int i, repeat;
3924 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
3925 void *results[MAX_ARGC];
3926 int ret;
3927 int res = 0;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003928
William M. Brackca15a542005-07-06 20:41:33 +00003929 xmlInitParser();
3930
3931 for (repeat = 0; repeat < 500; repeat++) {
3932 xmlLoadCatalog(catalog);
3933 nb_tests++;
3934
3935 for (i = 0; i < num_threads; i++) {
3936 results[i] = NULL;
3937 tid[i] = (pthread_t) - 1;
3938 }
3939
3940 for (i = 0; i < num_threads; i++) {
3941 ret = pthread_create(&tid[i], 0, thread_specific_data,
3942 (void *) testfiles[i]);
3943 if (ret != 0) {
3944 fprintf(stderr, "pthread_create failed\n");
3945 return (1);
3946 }
3947 }
3948 for (i = 0; i < num_threads; i++) {
3949 ret = pthread_join(tid[i], &results[i]);
3950 if (ret != 0) {
3951 fprintf(stderr, "pthread_join failed\n");
3952 return (1);
3953 }
3954 }
3955
3956 xmlCatalogCleanup();
3957 for (i = 0; i < num_threads; i++)
3958 if (results[i] != (void *) Okay) {
3959 fprintf(stderr, "Thread %d handling %s failed\n",
3960 i, testfiles[i]);
3961 res = 1;
3962 }
3963 }
3964 return (res);
3965}
3966
3967#elif defined WIN32
3968#include <windows.h>
3969#include <string.h>
3970
3971#define TEST_REPEAT_COUNT 500
3972
3973static HANDLE tid[MAX_ARGC];
3974
3975static DWORD WINAPI
3976win32_thread_specific_data(void *private_data)
3977{
3978 return((DWORD) thread_specific_data(private_data));
3979}
3980
3981static int
3982testThread(void)
3983{
3984 unsigned int i, repeat;
3985 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
3986 DWORD results[MAX_ARGC];
3987 BOOL ret;
3988 int res = 0;
3989
3990 xmlInitParser();
3991 for (repeat = 0; repeat < TEST_REPEAT_COUNT; repeat++) {
3992 xmlLoadCatalog(catalog);
3993 nb_tests++;
3994
3995 for (i = 0; i < num_threads; i++) {
3996 results[i] = 0;
3997 tid[i] = (HANDLE) - 1;
3998 }
3999
4000 for (i = 0; i < num_threads; i++) {
4001 DWORD useless;
4002
4003 tid[i] = CreateThread(NULL, 0,
Daniel Veillardaa6de472008-08-25 14:53:31 +00004004 win32_thread_specific_data,
William M. Brackca15a542005-07-06 20:41:33 +00004005 (void *) testfiles[i], 0,
4006 &useless);
4007 if (tid[i] == NULL) {
4008 fprintf(stderr, "CreateThread failed\n");
4009 return(1);
4010 }
4011 }
4012
4013 if (WaitForMultipleObjects(num_threads, tid, TRUE, INFINITE) ==
4014 WAIT_FAILED) {
4015 fprintf(stderr, "WaitForMultipleObjects failed\n");
4016 return(1);
4017 }
4018
4019 for (i = 0; i < num_threads; i++) {
4020 ret = GetExitCodeThread(tid[i], &results[i]);
4021 if (ret == 0) {
4022 fprintf(stderr, "GetExitCodeThread failed\n");
4023 return(1);
4024 }
4025 CloseHandle(tid[i]);
4026 }
4027
4028 xmlCatalogCleanup();
4029 for (i = 0; i < num_threads; i++) {
4030 if (results[i] != (DWORD) Okay) {
4031 fprintf(stderr, "Thread %d handling %s failed\n",
4032 i, testfiles[i]);
4033 res = 1;
4034 }
4035 }
4036 }
4037
4038 return (res);
4039}
4040
4041#elif defined __BEOS__
4042#include <OS.h>
4043
4044static thread_id tid[MAX_ARGC];
4045
4046static int
4047testThread(void)
4048{
4049 unsigned int i, repeat;
4050 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
4051 void *results[MAX_ARGC];
4052 status_t ret;
4053 int res = 0;
4054
4055 xmlInitParser();
4056 for (repeat = 0; repeat < 500; repeat++) {
4057 xmlLoadCatalog(catalog);
4058 for (i = 0; i < num_threads; i++) {
4059 results[i] = NULL;
4060 tid[i] = (thread_id) - 1;
4061 }
4062 for (i = 0; i < num_threads; i++) {
4063 tid[i] =
4064 spawn_thread(thread_specific_data, "xmlTestThread",
4065 B_NORMAL_PRIORITY, (void *) testfiles[i]);
4066 if (tid[i] < B_OK) {
4067 fprintf(stderr, "beos_thread_create failed\n");
4068 return (1);
4069 }
4070 printf("beos_thread_create %d -> %d\n", i, tid[i]);
4071 }
4072 for (i = 0; i < num_threads; i++) {
4073 ret = wait_for_thread(tid[i], &results[i]);
4074 printf("beos_thread_wait %d -> %d\n", i, ret);
4075 if (ret != B_OK) {
4076 fprintf(stderr, "beos_thread_wait failed\n");
4077 return (1);
4078 }
4079 }
4080
4081 xmlCatalogCleanup();
4082 ret = B_OK;
4083 for (i = 0; i < num_threads; i++)
4084 if (results[i] != (void *) Okay) {
4085 printf("Thread %d handling %s failed\n", i, testfiles[i]);
4086 ret = B_ERROR;
4087 }
4088 }
4089 if (ret != B_OK)
4090 return(1);
4091 return (0);
4092}
4093#else
4094static int
4095testThread(void)
4096{
4097 fprintf(stderr,
4098 "Specific platform thread support not detected\n");
4099 return (-1);
4100}
4101#endif
Daniel Veillardaa6de472008-08-25 14:53:31 +00004102static int
William M. Brackca15a542005-07-06 20:41:33 +00004103threadsTest(const char *filename ATTRIBUTE_UNUSED,
4104 const char *resul ATTRIBUTE_UNUSED,
4105 const char *err ATTRIBUTE_UNUSED,
4106 int options ATTRIBUTE_UNUSED) {
4107 return(testThread());
4108}
4109#endif
4110/************************************************************************
4111 * *
4112 * Tests Descriptions *
4113 * *
4114 ************************************************************************/
4115
4116static
4117testDesc testDescriptions[] = {
4118 { "XML regression tests" ,
4119 oldParseTest, "./test/*", "result/", "", NULL,
4120 0 },
4121 { "XML regression tests on memory" ,
4122 memParseTest, "./test/*", "result/", "", NULL,
4123 0 },
4124 { "XML entity subst regression tests" ,
4125 noentParseTest, "./test/*", "result/noent/", "", NULL,
4126 XML_PARSE_NOENT },
4127 { "XML Namespaces regression tests",
4128 errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err",
4129 0 },
4130 { "Error cases regression tests",
4131 errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err",
4132 0 },
4133#ifdef LIBXML_READER_ENABLED
4134 { "Error cases stream regression tests",
4135 streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str",
4136 0 },
4137 { "Reader regression tests",
4138 streamParseTest, "./test/*", "result/", ".rdr", NULL,
4139 0 },
4140 { "Reader entities substitution regression tests",
4141 streamParseTest, "./test/*", "result/", ".rde", NULL,
4142 XML_PARSE_NOENT },
4143 { "Reader on memory regression tests",
4144 streamMemParseTest, "./test/*", "result/", ".rdr", NULL,
4145 0 },
4146 { "Walker regression tests",
4147 walkerParseTest, "./test/*", "result/", ".rdr", NULL,
4148 0 },
4149#endif
4150#ifdef LIBXML_SAX1_ENABLED
4151 { "SAX1 callbacks regression tests" ,
4152 saxParseTest, "./test/*", "result/", ".sax", NULL,
4153 XML_PARSE_SAX1 },
4154 { "SAX2 callbacks regression tests" ,
4155 saxParseTest, "./test/*", "result/", ".sax2", NULL,
4156 0 },
4157#endif
4158#ifdef LIBXML_PUSH_ENABLED
4159 { "XML push regression tests" ,
4160 pushParseTest, "./test/*", "result/", "", NULL,
4161 0 },
4162#endif
4163#ifdef LIBXML_HTML_ENABLED
4164 { "HTML regression tests" ,
4165 errParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4166 XML_PARSE_HTML },
4167#ifdef LIBXML_PUSH_ENABLED
4168 { "Push HTML regression tests" ,
4169 pushParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4170 XML_PARSE_HTML },
4171#endif
4172#ifdef LIBXML_SAX1_ENABLED
4173 { "HTML SAX regression tests" ,
4174 saxParseTest, "./test/HTML/*", "result/HTML/", ".sax", NULL,
4175 XML_PARSE_HTML },
4176#endif
4177#endif
4178#ifdef LIBXML_VALID_ENABLED
4179 { "Valid documents regression tests" ,
4180 errParseTest, "./test/VCM/*", NULL, NULL, NULL,
4181 XML_PARSE_DTDVALID },
4182 { "Validity checking regression tests" ,
4183 errParseTest, "./test/VC/*", "result/VC/", NULL, "",
4184 XML_PARSE_DTDVALID },
4185 { "General documents valid regression tests" ,
4186 errParseTest, "./test/valid/*", "result/valid/", "", ".err",
4187 XML_PARSE_DTDVALID },
4188#endif
4189#ifdef LIBXML_XINCLUDE_ENABLED
4190 { "XInclude regression tests" ,
4191 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4192 /* Ignore errors at this point ".err", */
4193 XML_PARSE_XINCLUDE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004194#ifdef LIBXML_READER_ENABLED
William M. Brackca15a542005-07-06 20:41:33 +00004195 { "XInclude xmlReader regression tests",
4196 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4197 /* Ignore errors at this point ".err", */
4198 NULL, XML_PARSE_XINCLUDE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004199#endif
William M. Brackca15a542005-07-06 20:41:33 +00004200 { "XInclude regression tests stripping include nodes" ,
4201 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4202 /* Ignore errors at this point ".err", */
4203 XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004204#ifdef LIBXML_READER_ENABLED
William M. Brackca15a542005-07-06 20:41:33 +00004205 { "XInclude xmlReader regression tests stripping include nodes",
4206 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4207 /* Ignore errors at this point ".err", */
4208 NULL, XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
4209#endif
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004210#endif
William M. Brackca15a542005-07-06 20:41:33 +00004211#ifdef LIBXML_XPATH_ENABLED
4212#ifdef LIBXML_DEBUG_ENABLED
4213 { "XPath expressions regression tests" ,
4214 xpathExprTest, "./test/XPath/expr/*", "result/XPath/expr/", "", NULL,
4215 0 },
4216 { "XPath document queries regression tests" ,
4217 xpathDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4218 0 },
4219#ifdef LIBXML_XPTR_ENABLED
4220 { "XPointer document queries regression tests" ,
4221 xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4222 0 },
4223#endif
4224 { "xml:id regression tests" ,
4225 xmlidDocTest, "./test/xmlid/*", "result/xmlid/", "", ".err",
4226 0 },
4227#endif
4228#endif
4229 { "URI parsing tests" ,
4230 uriParseTest, "./test/URI/*.uri", "result/URI/", "", NULL,
4231 0 },
4232 { "URI base composition tests" ,
4233 uriBaseTest, "./test/URI/*.data", "result/URI/", "", NULL,
4234 0 },
Daniel Veillard336a8e12005-08-07 10:46:19 +00004235 { "Path URI conversion tests" ,
4236 uriPathTest, NULL, NULL, NULL, NULL,
4237 0 },
William M. Brackca15a542005-07-06 20:41:33 +00004238#ifdef LIBXML_SCHEMAS_ENABLED
4239 { "Schemas regression tests" ,
4240 schemasTest, "./test/schemas/*_*.xsd", NULL, NULL, NULL,
4241 0 },
4242 { "Relax-NG regression tests" ,
4243 rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4244 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4245#ifdef LIBXML_READER_ENABLED
4246 { "Relax-NG streaming regression tests" ,
4247 rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4248 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4249#endif
4250#endif
4251#ifdef LIBXML_PATTERN_ENABLED
4252#ifdef LIBXML_READER_ENABLED
4253 { "Pattern regression tests" ,
4254 patternTest, "./test/pattern/*.pat", "result/pattern/", NULL, NULL,
4255 0 },
4256#endif
4257#endif
4258#ifdef LIBXML_C14N_ENABLED
4259 { "C14N with comments regression tests" ,
4260 c14nWithCommentTest, "./test/c14n/with-comments/*.xml", NULL, NULL, NULL,
4261 0 },
4262 { "C14N without comments regression tests" ,
4263 c14nWithoutCommentTest, "./test/c14n/without-comments/*.xml", NULL, NULL, NULL,
4264 0 },
4265 { "C14N exclusive without comments regression tests" ,
4266 c14nExcWithoutCommentTest, "./test/c14n/exc-without-comments/*.xml", NULL, NULL, NULL,
4267 0 },
Aleksey Sanin83868242009-07-09 10:26:22 +02004268 { "C14N 1.1 without comments regression tests" ,
4269 c14n11WithoutCommentTest, "./test/c14n/1-1-without-comments/*.xml", NULL, NULL, NULL,
4270 0 },
William M. Brackca15a542005-07-06 20:41:33 +00004271#endif
Daniel Veillardbca3ad22005-08-23 22:14:02 +00004272#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) && defined(LIBXML_SAX1_ENABLED)
William M. Brackca15a542005-07-06 20:41:33 +00004273 { "Catalog and Threads regression tests" ,
4274 threadsTest, NULL, NULL, NULL, NULL,
4275 0 },
4276#endif
4277 {NULL, NULL, NULL, NULL, NULL, NULL, 0}
4278};
4279
4280/************************************************************************
4281 * *
4282 * The main code driving the tests *
4283 * *
4284 ************************************************************************/
4285
4286static int
4287launchTests(testDescPtr tst) {
4288 int res = 0, err = 0;
4289 size_t i;
4290 char *result;
4291 char *error;
4292 int mem;
4293
4294 if (tst == NULL) return(-1);
4295 if (tst->in != NULL) {
4296 glob_t globbuf;
4297
4298 globbuf.gl_offs = 0;
4299 glob(tst->in, GLOB_DOOFFS, NULL, &globbuf);
4300 for (i = 0;i < globbuf.gl_pathc;i++) {
4301 if (!checkTestFile(globbuf.gl_pathv[i]))
4302 continue;
4303 if (tst->suffix != NULL) {
4304 result = resultFilename(globbuf.gl_pathv[i], tst->out,
4305 tst->suffix);
4306 if (result == NULL) {
4307 fprintf(stderr, "Out of memory !\n");
4308 fatalError();
4309 }
4310 } else {
4311 result = NULL;
4312 }
4313 if (tst->err != NULL) {
4314 error = resultFilename(globbuf.gl_pathv[i], tst->out,
4315 tst->err);
4316 if (error == NULL) {
4317 fprintf(stderr, "Out of memory !\n");
4318 fatalError();
4319 }
4320 } else {
4321 error = NULL;
4322 }
4323 if ((result) &&(!checkTestFile(result))) {
4324 fprintf(stderr, "Missing result file %s\n", result);
4325 } else if ((error) &&(!checkTestFile(error))) {
4326 fprintf(stderr, "Missing error file %s\n", error);
4327 } else {
4328 mem = xmlMemUsed();
4329 extraMemoryFromResolver = 0;
4330 testErrorsSize = 0;
4331 testErrors[0] = 0;
4332 res = tst->func(globbuf.gl_pathv[i], result, error,
Daniel Veillard8874b942005-08-25 13:19:21 +00004333 tst->options | XML_PARSE_COMPACT);
William M. Brackca15a542005-07-06 20:41:33 +00004334 xmlResetLastError();
4335 if (res != 0) {
4336 fprintf(stderr, "File %s generated an error\n",
4337 globbuf.gl_pathv[i]);
4338 nb_errors++;
4339 err++;
4340 }
4341 else if (xmlMemUsed() != mem) {
4342 if ((xmlMemUsed() != mem) &&
4343 (extraMemoryFromResolver == 0)) {
4344 fprintf(stderr, "File %s leaked %d bytes\n",
4345 globbuf.gl_pathv[i], xmlMemUsed() - mem);
4346 nb_leaks++;
4347 err++;
4348 }
4349 }
4350 testErrorsSize = 0;
4351 }
4352 if (result)
4353 free(result);
4354 if (error)
4355 free(error);
4356 }
4357 globfree(&globbuf);
4358 } else {
4359 testErrorsSize = 0;
4360 testErrors[0] = 0;
4361 extraMemoryFromResolver = 0;
4362 res = tst->func(NULL, NULL, NULL, tst->options);
4363 if (res != 0) {
4364 nb_errors++;
4365 err++;
4366 }
4367 }
4368 return(err);
4369}
4370
Daniel Veillarddb68b742005-07-30 13:18:24 +00004371static int verbose = 0;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004372static int tests_quiet = 0;
Daniel Veillarddb68b742005-07-30 13:18:24 +00004373
4374static int
4375runtest(int i) {
4376 int ret = 0, res;
4377 int old_errors, old_tests, old_leaks;
4378
4379 old_errors = nb_errors;
4380 old_tests = nb_tests;
4381 old_leaks = nb_leaks;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004382 if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
Daniel Veillarddb68b742005-07-30 13:18:24 +00004383 printf("## %s\n", testDescriptions[i].desc);
4384 res = launchTests(&testDescriptions[i]);
4385 if (res != 0)
4386 ret++;
4387 if (verbose) {
4388 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
4389 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
4390 else
4391 printf("Ran %d tests, %d errors, %d leaks\n",
4392 nb_tests - old_tests,
4393 nb_errors - old_errors,
4394 nb_leaks - old_leaks);
4395 }
4396 return(ret);
4397}
4398
William M. Brackca15a542005-07-06 20:41:33 +00004399int
4400main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
Daniel Veillarddb68b742005-07-30 13:18:24 +00004401 int i, a, ret = 0;
4402 int subset = 0;
William M. Brackca15a542005-07-06 20:41:33 +00004403
4404 initializeLibxml2();
4405
Daniel Veillarddb68b742005-07-30 13:18:24 +00004406 for (a = 1; a < argc;a++) {
4407 if (!strcmp(argv[a], "-v"))
4408 verbose = 1;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004409 else if (!strcmp(argv[a], "-quiet"))
4410 tests_quiet = 1;
Daniel Veillarddb68b742005-07-30 13:18:24 +00004411 else {
4412 for (i = 0; testDescriptions[i].func != NULL; i++) {
4413 if (strstr(testDescriptions[i].desc, argv[a])) {
4414 ret += runtest(i);
4415 subset++;
4416 }
4417 }
4418 }
4419 }
4420 if (subset == 0) {
4421 for (i = 0; testDescriptions[i].func != NULL; i++) {
4422 ret += runtest(i);
William M. Brackca15a542005-07-06 20:41:33 +00004423 }
4424 }
4425 if ((nb_errors == 0) && (nb_leaks == 0)) {
4426 ret = 0;
4427 printf("Total %d tests, no errors\n",
4428 nb_tests);
4429 } else {
4430 ret = 1;
4431 printf("Total %d tests, %d errors, %d leaks\n",
4432 nb_tests, nb_errors, nb_leaks);
4433 }
4434 xmlCleanupParser();
4435 xmlMemoryDump();
4436
4437 return(ret);
4438}
4439
4440#else /* ! LIBXML_OUTPUT_ENABLED */
4441int
4442main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
4443 fprintf(stderr, "runtest requires output to be enabled in libxml2\n");
4444 return(1);
4445}
4446#endif