blob: 7640aad208f51abced1267bc9df7a32c9a9c66b7 [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;
Daniel Veillard13cee4e2009-09-05 14:52:55 +02001707 }
1708 if (temp != NULL) {
1709 unlink(temp);
1710 free(temp);
1711 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00001712
William M. Brackca15a542005-07-06 20:41:33 +00001713 /* switch back to structured error handling */
1714 xmlSetGenericErrorFunc(NULL, NULL);
1715 xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
1716
1717 return(ret);
1718}
1719#endif
1720
1721/************************************************************************
1722 * *
1723 * Parse to tree based tests *
1724 * *
1725 ************************************************************************/
1726/**
1727 * oldParseTest:
1728 * @filename: the file to parse
1729 * @result: the file with expected result
1730 * @err: the file with error messages: unused
1731 *
1732 * Parse a file using the old xmlParseFile API, then serialize back
1733 * reparse the result and serialize again, then check for deviation
1734 * in serialization.
1735 *
1736 * Returns 0 in case of success, an error code otherwise
1737 */
1738static int
1739oldParseTest(const char *filename, const char *result,
1740 const char *err ATTRIBUTE_UNUSED,
1741 int options ATTRIBUTE_UNUSED) {
1742 xmlDocPtr doc;
1743 char *temp;
1744 int res = 0;
1745
1746 nb_tests++;
1747 /*
1748 * base of the test, parse with the old API
1749 */
1750#ifdef LIBXML_SAX1_ENABLED
1751 doc = xmlParseFile(filename);
1752#else
1753 doc = xmlReadFile(filename, NULL, 0);
1754#endif
1755 if (doc == NULL)
1756 return(1);
1757 temp = resultFilename(filename, "", ".res");
1758 if (temp == NULL) {
1759 fprintf(stderr, "out of memory\n");
1760 fatalError();
1761 }
1762 xmlSaveFile(temp, doc);
1763 if (compareFiles(temp, result)) {
1764 res = 1;
1765 }
1766 xmlFreeDoc(doc);
1767
1768 /*
1769 * Parse the saved result to make sure the round trip is okay
1770 */
1771#ifdef LIBXML_SAX1_ENABLED
1772 doc = xmlParseFile(temp);
1773#else
1774 doc = xmlReadFile(temp, NULL, 0);
1775#endif
1776 if (doc == NULL)
1777 return(1);
1778 xmlSaveFile(temp, doc);
1779 if (compareFiles(temp, result)) {
1780 res = 1;
1781 }
1782 xmlFreeDoc(doc);
1783
Daniel Veillard13cee4e2009-09-05 14:52:55 +02001784 if (temp != NULL) {
1785 unlink(temp);
1786 free(temp);
1787 }
William M. Brackca15a542005-07-06 20:41:33 +00001788 return(res);
1789}
1790
1791#ifdef LIBXML_PUSH_ENABLED
1792/**
1793 * pushParseTest:
1794 * @filename: the file to parse
1795 * @result: the file with expected result
1796 * @err: the file with error messages: unused
1797 *
1798 * Parse a file using the Push API, then serialize back
1799 * to check for content.
1800 *
1801 * Returns 0 in case of success, an error code otherwise
1802 */
1803static int
1804pushParseTest(const char *filename, const char *result,
1805 const char *err ATTRIBUTE_UNUSED,
1806 int options) {
1807 xmlParserCtxtPtr ctxt;
1808 xmlDocPtr doc;
1809 const char *base;
1810 int size, res;
1811 int cur = 0;
1812
1813 nb_tests++;
1814 /*
1815 * load the document in memory and work from there.
1816 */
1817 if (loadMem(filename, &base, &size) != 0) {
1818 fprintf(stderr, "Failed to load %s\n", filename);
1819 return(-1);
1820 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00001821
William M. Brackca15a542005-07-06 20:41:33 +00001822#ifdef LIBXML_HTML_ENABLED
1823 if (options & XML_PARSE_HTML)
1824 ctxt = htmlCreatePushParserCtxt(NULL, NULL, base + cur, 4, filename,
1825 XML_CHAR_ENCODING_NONE);
1826 else
1827#endif
1828 ctxt = xmlCreatePushParserCtxt(NULL, NULL, base + cur, 4, filename);
1829 xmlCtxtUseOptions(ctxt, options);
1830 cur += 4;
1831 while (cur < size) {
1832 if (cur + 1024 >= size) {
1833#ifdef LIBXML_HTML_ENABLED
1834 if (options & XML_PARSE_HTML)
1835 htmlParseChunk(ctxt, base + cur, size - cur, 1);
1836 else
1837#endif
1838 xmlParseChunk(ctxt, base + cur, size - cur, 1);
1839 break;
1840 } else {
1841#ifdef LIBXML_HTML_ENABLED
1842 if (options & XML_PARSE_HTML)
1843 htmlParseChunk(ctxt, base + cur, 1024, 0);
1844 else
1845#endif
1846 xmlParseChunk(ctxt, base + cur, 1024, 0);
1847 cur += 1024;
1848 }
1849 }
1850 doc = ctxt->myDoc;
1851#ifdef LIBXML_HTML_ENABLED
1852 if (options & XML_PARSE_HTML)
1853 res = 1;
1854 else
1855#endif
1856 res = ctxt->wellFormed;
1857 xmlFreeParserCtxt(ctxt);
1858 free((char *)base);
1859 if (!res) {
1860 xmlFreeDoc(doc);
1861 fprintf(stderr, "Failed to parse %s\n", filename);
1862 return(-1);
1863 }
1864#ifdef LIBXML_HTML_ENABLED
1865 if (options & XML_PARSE_HTML)
1866 htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1867 else
1868#endif
1869 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1870 xmlFreeDoc(doc);
1871 res = compareFileMem(result, base, size);
1872 if ((base == NULL) || (res != 0)) {
1873 if (base != NULL)
1874 xmlFree((char *)base);
1875 fprintf(stderr, "Result for %s failed\n", filename);
1876 return(-1);
1877 }
1878 xmlFree((char *)base);
1879 if (err != NULL) {
1880 res = compareFileMem(err, testErrors, testErrorsSize);
1881 if (res != 0) {
1882 fprintf(stderr, "Error for %s failed\n", filename);
1883 return(-1);
1884 }
1885 }
1886 return(0);
1887}
1888#endif
1889
1890/**
1891 * memParseTest:
1892 * @filename: the file to parse
1893 * @result: the file with expected result
1894 * @err: the file with error messages: unused
1895 *
1896 * Parse a file using the old xmlReadMemory API, then serialize back
1897 * reparse the result and serialize again, then check for deviation
1898 * in serialization.
1899 *
1900 * Returns 0 in case of success, an error code otherwise
1901 */
1902static int
1903memParseTest(const char *filename, const char *result,
1904 const char *err ATTRIBUTE_UNUSED,
1905 int options ATTRIBUTE_UNUSED) {
1906 xmlDocPtr doc;
1907 const char *base;
1908 int size, res;
1909
1910 nb_tests++;
1911 /*
1912 * load and parse the memory
1913 */
1914 if (loadMem(filename, &base, &size) != 0) {
1915 fprintf(stderr, "Failed to load %s\n", filename);
1916 return(-1);
1917 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00001918
William M. Brackca15a542005-07-06 20:41:33 +00001919 doc = xmlReadMemory(base, size, filename, NULL, 0);
1920 unloadMem(base);
1921 if (doc == NULL) {
1922 return(1);
1923 }
1924 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1925 xmlFreeDoc(doc);
1926 res = compareFileMem(result, base, size);
1927 if ((base == NULL) || (res != 0)) {
1928 if (base != NULL)
1929 xmlFree((char *)base);
1930 fprintf(stderr, "Result for %s failed\n", filename);
1931 return(-1);
1932 }
1933 xmlFree((char *)base);
1934 return(0);
1935}
1936
1937/**
1938 * noentParseTest:
1939 * @filename: the file to parse
1940 * @result: the file with expected result
1941 * @err: the file with error messages: unused
1942 *
1943 * Parse a file with entity resolution, then serialize back
1944 * reparse the result and serialize again, then check for deviation
1945 * in serialization.
1946 *
1947 * Returns 0 in case of success, an error code otherwise
1948 */
1949static int
1950noentParseTest(const char *filename, const char *result,
1951 const char *err ATTRIBUTE_UNUSED,
1952 int options) {
1953 xmlDocPtr doc;
1954 char *temp;
1955 int res = 0;
1956
1957 nb_tests++;
1958 /*
1959 * base of the test, parse with the old API
1960 */
1961 doc = xmlReadFile(filename, NULL, options);
1962 if (doc == NULL)
1963 return(1);
1964 temp = resultFilename(filename, "", ".res");
1965 if (temp == NULL) {
1966 fprintf(stderr, "Out of memory\n");
1967 fatalError();
1968 }
1969 xmlSaveFile(temp, doc);
1970 if (compareFiles(temp, result)) {
1971 res = 1;
1972 }
1973 xmlFreeDoc(doc);
1974
1975 /*
1976 * Parse the saved result to make sure the round trip is okay
1977 */
1978 doc = xmlReadFile(filename, NULL, options);
1979 if (doc == NULL)
1980 return(1);
1981 xmlSaveFile(temp, doc);
1982 if (compareFiles(temp, result)) {
1983 res = 1;
1984 }
1985 xmlFreeDoc(doc);
1986
Daniel Veillard13cee4e2009-09-05 14:52:55 +02001987 if (temp != NULL) {
1988 unlink(temp);
1989 free(temp);
1990 }
William M. Brackca15a542005-07-06 20:41:33 +00001991 return(res);
1992}
1993
1994/**
1995 * errParseTest:
1996 * @filename: the file to parse
1997 * @result: the file with expected result
1998 * @err: the file with error messages
1999 *
2000 * Parse a file using the xmlReadFile API and check for errors.
2001 *
2002 * Returns 0 in case of success, an error code otherwise
2003 */
2004static int
2005errParseTest(const char *filename, const char *result, const char *err,
2006 int options) {
2007 xmlDocPtr doc;
2008 const char *base = NULL;
2009 int size, res = 0;
2010
2011 nb_tests++;
2012#ifdef LIBXML_HTML_ENABLED
2013 if (options & XML_PARSE_HTML) {
2014 doc = htmlReadFile(filename, NULL, options);
2015 } else
2016#endif
2017#ifdef LIBXML_XINCLUDE_ENABLED
2018 if (options & XML_PARSE_XINCLUDE) {
2019 doc = xmlReadFile(filename, NULL, options);
2020 xmlXIncludeProcessFlags(doc, options);
2021 } else
2022#endif
2023 {
2024 xmlGetWarningsDefaultValue = 1;
2025 doc = xmlReadFile(filename, NULL, options);
2026 }
2027 xmlGetWarningsDefaultValue = 0;
2028 if (result) {
2029 if (doc == NULL) {
2030 base = "";
2031 size = 0;
2032 } else {
2033#ifdef LIBXML_HTML_ENABLED
2034 if (options & XML_PARSE_HTML) {
2035 htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2036 } else
2037#endif
2038 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2039 }
2040 res = compareFileMem(result, base, size);
2041 }
2042 if (doc != NULL) {
2043 if (base != NULL)
2044 xmlFree((char *)base);
2045 xmlFreeDoc(doc);
2046 }
2047 if (res != 0) {
2048 fprintf(stderr, "Result for %s failed\n", filename);
2049 return(-1);
2050 }
2051 if (err != NULL) {
2052 res = compareFileMem(err, testErrors, testErrorsSize);
2053 if (res != 0) {
2054 fprintf(stderr, "Error for %s failed\n", filename);
2055 return(-1);
2056 }
2057 } else if (options & XML_PARSE_DTDVALID) {
2058 if (testErrorsSize != 0)
2059 fprintf(stderr, "Validation for %s failed\n", filename);
2060 }
2061
2062 return(0);
2063}
2064
2065#ifdef LIBXML_READER_ENABLED
2066/************************************************************************
2067 * *
2068 * Reader based tests *
2069 * *
2070 ************************************************************************/
2071
2072static void processNode(FILE *out, xmlTextReaderPtr reader) {
2073 const xmlChar *name, *value;
2074 int type, empty;
2075
2076 type = xmlTextReaderNodeType(reader);
2077 empty = xmlTextReaderIsEmptyElement(reader);
2078
2079 name = xmlTextReaderConstName(reader);
2080 if (name == NULL)
2081 name = BAD_CAST "--";
2082
2083 value = xmlTextReaderConstValue(reader);
2084
Daniel Veillardaa6de472008-08-25 14:53:31 +00002085
2086 fprintf(out, "%d %d %s %d %d",
William M. Brackca15a542005-07-06 20:41:33 +00002087 xmlTextReaderDepth(reader),
2088 type,
2089 name,
2090 empty,
2091 xmlTextReaderHasValue(reader));
2092 if (value == NULL)
2093 fprintf(out, "\n");
2094 else {
2095 fprintf(out, " %s\n", value);
2096 }
2097}
2098static int
2099streamProcessTest(const char *filename, const char *result, const char *err,
2100 xmlTextReaderPtr reader, const char *rng) {
2101 int ret;
2102 char *temp = NULL;
2103 FILE *t = NULL;
2104
2105 if (reader == NULL)
2106 return(-1);
2107
2108 nb_tests++;
2109 if (result != NULL) {
2110 temp = resultFilename(filename, "", ".res");
2111 if (temp == NULL) {
2112 fprintf(stderr, "Out of memory\n");
2113 fatalError();
2114 }
2115 t = fopen(temp, "wb");
2116 if (t == NULL) {
2117 fprintf(stderr, "Can't open temp file %s\n", temp);
2118 free(temp);
2119 return(-1);
2120 }
2121 }
2122#ifdef LIBXML_SCHEMAS_ENABLED
2123 if (rng != NULL) {
2124 ret = xmlTextReaderRelaxNGValidate(reader, rng);
2125 if (ret < 0) {
2126 testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n",
2127 rng);
2128 fclose(t);
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002129 if (temp != NULL) {
2130 unlink(temp);
2131 free(temp);
2132 }
William M. Brackca15a542005-07-06 20:41:33 +00002133 return(0);
2134 }
2135 }
2136#endif
2137 xmlGetWarningsDefaultValue = 1;
2138 ret = xmlTextReaderRead(reader);
2139 while (ret == 1) {
2140 if ((t != NULL) && (rng == NULL))
2141 processNode(t, reader);
2142 ret = xmlTextReaderRead(reader);
2143 }
2144 if (ret != 0) {
2145 testErrorHandler(NULL, "%s : failed to parse\n", filename);
2146 }
2147 if (rng != NULL) {
2148 if (xmlTextReaderIsValid(reader) != 1) {
2149 testErrorHandler(NULL, "%s fails to validate\n", filename);
2150 } else {
2151 testErrorHandler(NULL, "%s validates\n", filename);
2152 }
2153 }
2154 xmlGetWarningsDefaultValue = 0;
2155 if (t != NULL) {
2156 fclose(t);
2157 ret = compareFiles(temp, result);
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002158 if (temp != NULL) {
2159 unlink(temp);
2160 free(temp);
2161 }
William M. Brackca15a542005-07-06 20:41:33 +00002162 if (ret) {
2163 fprintf(stderr, "Result for %s failed\n", filename);
2164 return(-1);
2165 }
2166 }
2167 if (err != NULL) {
2168 ret = compareFileMem(err, testErrors, testErrorsSize);
2169 if (ret != 0) {
2170 fprintf(stderr, "Error for %s failed\n", filename);
2171 printf("%s", testErrors);
2172 return(-1);
2173 }
2174 }
2175
2176 return(0);
2177}
2178
2179/**
2180 * streamParseTest:
2181 * @filename: the file to parse
2182 * @result: the file with expected result
2183 * @err: the file with error messages
2184 *
2185 * Parse a file using the reader API and check for errors.
2186 *
2187 * Returns 0 in case of success, an error code otherwise
2188 */
2189static int
2190streamParseTest(const char *filename, const char *result, const char *err,
2191 int options) {
2192 xmlTextReaderPtr reader;
2193 int ret;
2194
2195 reader = xmlReaderForFile(filename, NULL, options);
2196 ret = streamProcessTest(filename, result, err, reader, NULL);
2197 xmlFreeTextReader(reader);
2198 return(ret);
2199}
2200
2201/**
2202 * walkerParseTest:
2203 * @filename: the file to parse
2204 * @result: the file with expected result
2205 * @err: the file with error messages
2206 *
2207 * Parse a file using the walker, i.e. a reader built from a atree.
2208 *
2209 * Returns 0 in case of success, an error code otherwise
2210 */
2211static int
2212walkerParseTest(const char *filename, const char *result, const char *err,
2213 int options) {
2214 xmlDocPtr doc;
2215 xmlTextReaderPtr reader;
2216 int ret;
2217
2218 doc = xmlReadFile(filename, NULL, options);
2219 if (doc == NULL) {
2220 fprintf(stderr, "Failed to parse %s\n", filename);
2221 return(-1);
2222 }
2223 reader = xmlReaderWalker(doc);
2224 ret = streamProcessTest(filename, result, err, reader, NULL);
2225 xmlFreeTextReader(reader);
2226 xmlFreeDoc(doc);
2227 return(ret);
2228}
2229
2230/**
2231 * streamMemParseTest:
2232 * @filename: the file to parse
2233 * @result: the file with expected result
2234 * @err: the file with error messages
2235 *
2236 * Parse a file using the reader API from memory and check for errors.
2237 *
2238 * Returns 0 in case of success, an error code otherwise
2239 */
2240static int
2241streamMemParseTest(const char *filename, const char *result, const char *err,
2242 int options) {
2243 xmlTextReaderPtr reader;
2244 int ret;
2245 const char *base;
2246 int size;
2247
2248 /*
2249 * load and parse the memory
2250 */
2251 if (loadMem(filename, &base, &size) != 0) {
2252 fprintf(stderr, "Failed to load %s\n", filename);
2253 return(-1);
2254 }
2255 reader = xmlReaderForMemory(base, size, filename, NULL, options);
2256 ret = streamProcessTest(filename, result, err, reader, NULL);
2257 free((char *)base);
2258 xmlFreeTextReader(reader);
2259 return(ret);
2260}
2261#endif
2262
2263#ifdef LIBXML_XPATH_ENABLED
2264#ifdef LIBXML_DEBUG_ENABLED
2265/************************************************************************
2266 * *
2267 * XPath and XPointer based tests *
2268 * *
2269 ************************************************************************/
2270
Daniel Veillard24505b02005-07-28 23:49:35 +00002271static FILE *xpathOutput;
2272static xmlDocPtr xpathDocument;
William M. Brackca15a542005-07-06 20:41:33 +00002273
2274static void
2275testXPath(const char *str, int xptr, int expr) {
2276 xmlXPathObjectPtr res;
2277 xmlXPathContextPtr ctxt;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002278
William M. Brackca15a542005-07-06 20:41:33 +00002279 nb_tests++;
2280#if defined(LIBXML_XPTR_ENABLED)
2281 if (xptr) {
2282 ctxt = xmlXPtrNewContext(xpathDocument, NULL, NULL);
2283 res = xmlXPtrEval(BAD_CAST str, ctxt);
2284 } else {
2285#endif
2286 ctxt = xmlXPathNewContext(xpathDocument);
2287 ctxt->node = xmlDocGetRootElement(xpathDocument);
2288 if (expr)
2289 res = xmlXPathEvalExpression(BAD_CAST str, ctxt);
2290 else {
2291 /* res = xmlXPathEval(BAD_CAST str, ctxt); */
2292 xmlXPathCompExprPtr comp;
2293
2294 comp = xmlXPathCompile(BAD_CAST str);
2295 if (comp != NULL) {
2296 res = xmlXPathCompiledEval(comp, ctxt);
2297 xmlXPathFreeCompExpr(comp);
2298 } else
2299 res = NULL;
2300 }
2301#if defined(LIBXML_XPTR_ENABLED)
2302 }
2303#endif
2304 xmlXPathDebugDumpObject(xpathOutput, res, 0);
2305 xmlXPathFreeObject(res);
2306 xmlXPathFreeContext(ctxt);
2307}
2308
2309/**
2310 * xpathExprTest:
2311 * @filename: the file to parse
2312 * @result: the file with expected result
2313 * @err: the file with error messages
2314 *
2315 * Parse a file containing XPath standalone expressions and evaluate them
2316 *
2317 * Returns 0 in case of success, an error code otherwise
2318 */
2319static int
2320xpathCommonTest(const char *filename, const char *result,
2321 int xptr, int expr) {
2322 FILE *input;
2323 char expression[5000];
2324 int len, ret = 0;
2325 char *temp;
2326
2327 temp = resultFilename(filename, "", ".res");
2328 if (temp == NULL) {
2329 fprintf(stderr, "Out of memory\n");
2330 fatalError();
2331 }
2332 xpathOutput = fopen(temp, "wb");
2333 if (xpathOutput == NULL) {
2334 fprintf(stderr, "failed to open output file %s\n", temp);
2335 free(temp);
2336 return(-1);
2337 }
2338
2339 input = fopen(filename, "rb");
2340 if (input == NULL) {
2341 xmlGenericError(xmlGenericErrorContext,
2342 "Cannot open %s for reading\n", filename);
2343 free(temp);
2344 return(-1);
2345 }
2346 while (fgets(expression, 4500, input) != NULL) {
2347 len = strlen(expression);
2348 len--;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002349 while ((len >= 0) &&
William M. Brackca15a542005-07-06 20:41:33 +00002350 ((expression[len] == '\n') || (expression[len] == '\t') ||
2351 (expression[len] == '\r') || (expression[len] == ' '))) len--;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002352 expression[len + 1] = 0;
William M. Brackca15a542005-07-06 20:41:33 +00002353 if (len >= 0) {
2354 fprintf(xpathOutput,
2355 "\n========================\nExpression: %s\n",
2356 expression) ;
2357 testXPath(expression, xptr, expr);
2358 }
2359 }
2360
2361 fclose(input);
2362 fclose(xpathOutput);
2363 if (result != NULL) {
2364 ret = compareFiles(temp, result);
2365 if (ret) {
2366 fprintf(stderr, "Result for %s failed\n", filename);
2367 }
2368 }
2369
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002370 if (temp != NULL) {
2371 unlink(temp);
2372 free(temp);
2373 }
William M. Brackca15a542005-07-06 20:41:33 +00002374 return(ret);
2375}
2376
2377/**
2378 * xpathExprTest:
2379 * @filename: the file to parse
2380 * @result: the file with expected result
2381 * @err: the file with error messages
2382 *
2383 * Parse a file containing XPath standalone expressions and evaluate them
2384 *
2385 * Returns 0 in case of success, an error code otherwise
2386 */
2387static int
2388xpathExprTest(const char *filename, const char *result,
2389 const char *err ATTRIBUTE_UNUSED,
2390 int options ATTRIBUTE_UNUSED) {
2391 return(xpathCommonTest(filename, result, 0, 1));
2392}
2393
2394/**
2395 * xpathDocTest:
2396 * @filename: the file to parse
2397 * @result: the file with expected result
2398 * @err: the file with error messages
2399 *
2400 * Parse a file containing XPath expressions and evaluate them against
2401 * a set of corresponding documents.
2402 *
2403 * Returns 0 in case of success, an error code otherwise
2404 */
2405static int
2406xpathDocTest(const char *filename,
2407 const char *resul ATTRIBUTE_UNUSED,
2408 const char *err ATTRIBUTE_UNUSED,
2409 int options) {
2410
2411 char pattern[500];
2412 char result[500];
2413 glob_t globbuf;
2414 size_t i;
2415 int ret = 0, res;
2416
2417 xpathDocument = xmlReadFile(filename, NULL,
2418 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2419 if (xpathDocument == NULL) {
2420 fprintf(stderr, "Failed to load %s\n", filename);
2421 return(-1);
2422 }
2423
2424 snprintf(pattern, 499, "./test/XPath/tests/%s*", baseFilename(filename));
2425 pattern[499] = 0;
2426 globbuf.gl_offs = 0;
2427 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2428 for (i = 0;i < globbuf.gl_pathc;i++) {
2429 snprintf(result, 499, "result/XPath/tests/%s",
2430 baseFilename(globbuf.gl_pathv[i]));
2431 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 0, 0);
2432 if (res != 0)
2433 ret = res;
2434 }
2435 globfree(&globbuf);
2436
2437 xmlFreeDoc(xpathDocument);
2438 return(ret);
2439}
2440
2441#ifdef LIBXML_XPTR_ENABLED
2442/**
2443 * xptrDocTest:
2444 * @filename: the file to parse
2445 * @result: the file with expected result
2446 * @err: the file with error messages
2447 *
2448 * Parse a file containing XPath expressions and evaluate them against
2449 * a set of corresponding documents.
2450 *
2451 * Returns 0 in case of success, an error code otherwise
2452 */
2453static int
2454xptrDocTest(const char *filename,
2455 const char *resul ATTRIBUTE_UNUSED,
2456 const char *err ATTRIBUTE_UNUSED,
2457 int options) {
2458
2459 char pattern[500];
2460 char result[500];
2461 glob_t globbuf;
2462 size_t i;
2463 int ret = 0, res;
2464
2465 xpathDocument = xmlReadFile(filename, NULL,
2466 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2467 if (xpathDocument == NULL) {
2468 fprintf(stderr, "Failed to load %s\n", filename);
2469 return(-1);
2470 }
2471
2472 snprintf(pattern, 499, "./test/XPath/xptr/%s*", baseFilename(filename));
2473 pattern[499] = 0;
2474 globbuf.gl_offs = 0;
2475 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2476 for (i = 0;i < globbuf.gl_pathc;i++) {
2477 snprintf(result, 499, "result/XPath/xptr/%s",
2478 baseFilename(globbuf.gl_pathv[i]));
2479 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 1, 0);
2480 if (res != 0)
2481 ret = res;
2482 }
2483 globfree(&globbuf);
2484
2485 xmlFreeDoc(xpathDocument);
2486 return(ret);
2487}
2488#endif /* LIBXML_XPTR_ENABLED */
2489
2490/**
2491 * xmlidDocTest:
2492 * @filename: the file to parse
2493 * @result: the file with expected result
2494 * @err: the file with error messages
2495 *
2496 * Parse a file containing xml:id and check for errors and verify
2497 * that XPath queries will work on them as expected.
2498 *
2499 * Returns 0 in case of success, an error code otherwise
2500 */
2501static int
2502xmlidDocTest(const char *filename,
2503 const char *result,
2504 const char *err,
2505 int options) {
2506
2507 int res = 0;
2508 int ret = 0;
2509 char *temp;
2510
2511 xpathDocument = xmlReadFile(filename, NULL,
2512 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2513 if (xpathDocument == NULL) {
2514 fprintf(stderr, "Failed to load %s\n", filename);
2515 return(-1);
2516 }
2517
2518 temp = resultFilename(filename, "", ".res");
2519 if (temp == NULL) {
2520 fprintf(stderr, "Out of memory\n");
2521 fatalError();
2522 }
2523 xpathOutput = fopen(temp, "wb");
2524 if (xpathOutput == NULL) {
2525 fprintf(stderr, "failed to open output file %s\n", temp);
2526 xmlFreeDoc(xpathDocument);
2527 free(temp);
2528 return(-1);
2529 }
2530
2531 testXPath("id('bar')", 0, 0);
2532
2533 fclose(xpathOutput);
2534 if (result != NULL) {
2535 ret = compareFiles(temp, result);
2536 if (ret) {
2537 fprintf(stderr, "Result for %s failed\n", filename);
2538 res = 1;
2539 }
2540 }
2541
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002542 if (temp != NULL) {
2543 unlink(temp);
2544 free(temp);
2545 }
William M. Brackca15a542005-07-06 20:41:33 +00002546 xmlFreeDoc(xpathDocument);
2547
2548 if (err != NULL) {
2549 ret = compareFileMem(err, testErrors, testErrorsSize);
2550 if (ret != 0) {
2551 fprintf(stderr, "Error for %s failed\n", filename);
2552 res = 1;
2553 }
2554 }
2555 return(res);
2556}
2557
2558#endif /* LIBXML_DEBUG_ENABLED */
2559#endif /* XPATH */
2560/************************************************************************
2561 * *
2562 * URI based tests *
2563 * *
2564 ************************************************************************/
2565
2566static void
2567handleURI(const char *str, const char *base, FILE *o) {
2568 int ret;
2569 xmlURIPtr uri;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002570 xmlChar *res = NULL;
William M. Brackca15a542005-07-06 20:41:33 +00002571
2572 uri = xmlCreateURI();
2573
2574 if (base == NULL) {
2575 ret = xmlParseURIReference(uri, str);
2576 if (ret != 0)
2577 fprintf(o, "%s : error %d\n", str, ret);
2578 else {
2579 xmlNormalizeURIPath(uri->path);
2580 xmlPrintURI(o, uri);
2581 fprintf(o, "\n");
2582 }
2583 } else {
2584 res = xmlBuildURI((xmlChar *)str, (xmlChar *) base);
2585 if (res != NULL) {
2586 fprintf(o, "%s\n", (char *) res);
2587 }
2588 else
2589 fprintf(o, "::ERROR::\n");
2590 }
2591 if (res != NULL)
2592 xmlFree(res);
William M. Brackca15a542005-07-06 20:41:33 +00002593 xmlFreeURI(uri);
2594}
2595
2596/**
2597 * uriCommonTest:
2598 * @filename: the file to parse
2599 * @result: the file with expected result
2600 * @err: the file with error messages
2601 *
2602 * Parse a file containing URI and check for errors
2603 *
2604 * Returns 0 in case of success, an error code otherwise
2605 */
2606static int
2607uriCommonTest(const char *filename,
2608 const char *result,
2609 const char *err,
2610 const char *base) {
2611 char *temp;
2612 FILE *o, *f;
2613 char str[1024];
2614 int res = 0, i, ret;
2615
2616 temp = resultFilename(filename, "", ".res");
2617 if (temp == NULL) {
2618 fprintf(stderr, "Out of memory\n");
2619 fatalError();
2620 }
2621 o = fopen(temp, "wb");
2622 if (o == NULL) {
2623 fprintf(stderr, "failed to open output file %s\n", temp);
2624 free(temp);
2625 return(-1);
2626 }
2627 f = fopen(filename, "rb");
2628 if (f == NULL) {
2629 fprintf(stderr, "failed to open input file %s\n", filename);
2630 fclose(o);
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002631 if (temp != NULL) {
2632 unlink(temp);
2633 free(temp);
2634 }
William M. Brackca15a542005-07-06 20:41:33 +00002635 return(-1);
2636 }
2637
2638 while (1) {
2639 /*
2640 * read one line in string buffer.
2641 */
2642 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
2643 break;
2644
2645 /*
2646 * remove the ending spaces
2647 */
2648 i = strlen(str);
2649 while ((i > 0) &&
2650 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
2651 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
2652 i--;
2653 str[i] = 0;
2654 }
2655 nb_tests++;
2656 handleURI(str, base, o);
2657 }
2658
2659 fclose(f);
2660 fclose(o);
2661
2662 if (result != NULL) {
2663 ret = compareFiles(temp, result);
2664 if (ret) {
2665 fprintf(stderr, "Result for %s failed\n", filename);
2666 res = 1;
2667 }
2668 }
2669 if (err != NULL) {
2670 ret = compareFileMem(err, testErrors, testErrorsSize);
2671 if (ret != 0) {
2672 fprintf(stderr, "Error for %s failed\n", filename);
2673 res = 1;
2674 }
2675 }
2676
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002677 if (temp != NULL) {
2678 unlink(temp);
2679 free(temp);
2680 }
William M. Brackca15a542005-07-06 20:41:33 +00002681 return(res);
2682}
2683
2684/**
2685 * uriParseTest:
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 and check for errors
2691 *
2692 * Returns 0 in case of success, an error code otherwise
2693 */
2694static int
2695uriParseTest(const char *filename,
2696 const char *result,
2697 const char *err,
2698 int options ATTRIBUTE_UNUSED) {
2699 return(uriCommonTest(filename, result, err, NULL));
2700}
2701
2702/**
2703 * uriBaseTest:
2704 * @filename: the file to parse
2705 * @result: the file with expected result
2706 * @err: the file with error messages
2707 *
2708 * Parse a file containing URI, compose them against a fixed base and
2709 * check for errors
2710 *
2711 * Returns 0 in case of success, an error code otherwise
2712 */
2713static int
2714uriBaseTest(const char *filename,
2715 const char *result,
2716 const char *err,
2717 int options ATTRIBUTE_UNUSED) {
2718 return(uriCommonTest(filename, result, err,
2719 "http://foo.com/path/to/index.html?orig#help"));
2720}
2721
Daniel Veillard336a8e12005-08-07 10:46:19 +00002722static int urip_success = 1;
2723static int urip_current = 0;
2724static const char *urip_testURLs[] = {
2725 "urip://example.com/a b.html",
2726 "urip://example.com/a%20b.html",
2727 "file:///path/to/a b.html",
2728 "file:///path/to/a%20b.html",
2729 "/path/to/a b.html",
2730 "/path/to/a%20b.html",
2731 "urip://example.com/résumé.html",
2732 "urip://example.com/test?a=1&b=2%263&c=4#foo",
2733 NULL
2734};
2735static const char *urip_rcvsURLs[] = {
2736 /* it is an URI the strings must be escaped */
2737 "urip://example.com/a%20b.html",
2738 /* check that % escaping is not broken */
2739 "urip://example.com/a%20b.html",
2740 /* it's an URI path the strings must be escaped */
2741 "file:///path/to/a%20b.html",
2742 /* check that % escaping is not broken */
2743 "file:///path/to/a%20b.html",
2744 /* this is not an URI, this is a path, so this should not be escaped */
2745 "/path/to/a b.html",
2746 /* check that paths with % are not broken */
2747 "/path/to/a%20b.html",
2748 /* out of context the encoding can't be guessed byte by byte conversion */
2749 "urip://example.com/r%E9sum%E9.html",
2750 /* verify we don't destroy URIs especially the query part */
2751 "urip://example.com/test?a=1&b=2%263&c=4#foo",
2752 NULL
2753};
2754static const char *urip_res = "<list/>";
2755static const char *urip_cur = NULL;
2756static int urip_rlen;
2757
2758/**
2759 * uripMatch:
2760 * @URI: an URI to test
2761 *
2762 * Check for an urip: query
2763 *
2764 * Returns 1 if yes and 0 if another Input module should be used
2765 */
2766static int
2767uripMatch(const char * URI) {
2768 if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog")))
2769 return(0);
2770 /* Verify we received the escaped URL */
2771 if (strcmp(urip_rcvsURLs[urip_current], URI))
2772 urip_success = 0;
2773 return(1);
2774}
2775
2776/**
2777 * uripOpen:
2778 * @URI: an URI to test
2779 *
2780 * Return a pointer to the urip: query handler, in this example simply
2781 * the urip_current pointer...
2782 *
2783 * Returns an Input context or NULL in case or error
2784 */
2785static void *
2786uripOpen(const char * URI) {
2787 if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog")))
2788 return(NULL);
2789 /* Verify we received the escaped URL */
2790 if (strcmp(urip_rcvsURLs[urip_current], URI))
2791 urip_success = 0;
2792 urip_cur = urip_res;
2793 urip_rlen = strlen(urip_res);
2794 return((void *) urip_cur);
2795}
2796
2797/**
2798 * uripClose:
2799 * @context: the read context
2800 *
2801 * Close the urip: query handler
2802 *
2803 * Returns 0 or -1 in case of error
2804 */
2805static int
2806uripClose(void * context) {
2807 if (context == NULL) return(-1);
2808 urip_cur = NULL;
2809 urip_rlen = 0;
2810 return(0);
2811}
2812
2813/**
2814 * uripRead:
2815 * @context: the read context
2816 * @buffer: where to store data
2817 * @len: number of bytes to read
2818 *
2819 * Implement an urip: query read.
2820 *
2821 * Returns the number of bytes read or -1 in case of error
2822 */
2823static int
2824uripRead(void * context, char * buffer, int len) {
2825 const char *ptr = (const char *) context;
2826
2827 if ((context == NULL) || (buffer == NULL) || (len < 0))
2828 return(-1);
2829
2830 if (len > urip_rlen) len = urip_rlen;
2831 memcpy(buffer, ptr, len);
2832 urip_rlen -= len;
2833 return(len);
2834}
2835
2836static int
2837urip_checkURL(const char *URL) {
2838 xmlDocPtr doc;
2839
2840 doc = xmlReadFile(URL, NULL, 0);
2841 if (doc == NULL)
2842 return(-1);
2843 xmlFreeDoc(doc);
2844 return(1);
2845}
2846
2847/**
2848 * uriPathTest:
2849 * @filename: ignored
2850 * @result: ignored
2851 * @err: ignored
2852 *
2853 * Run a set of tests to check how Path and URI are handled before
2854 * being passed to the I/O layer
2855 *
2856 * Returns 0 in case of success, an error code otherwise
2857 */
2858static int
2859uriPathTest(const char *filename ATTRIBUTE_UNUSED,
2860 const char *result ATTRIBUTE_UNUSED,
2861 const char *err ATTRIBUTE_UNUSED,
2862 int options ATTRIBUTE_UNUSED) {
2863 int parsed;
2864 int failures = 0;
2865
2866 /*
2867 * register the new I/O handlers
2868 */
2869 if (xmlRegisterInputCallbacks(uripMatch, uripOpen, uripRead, uripClose) < 0)
2870 {
2871 fprintf(stderr, "failed to register HTTP handler\n");
2872 return(-1);
2873 }
2874
2875 for (urip_current = 0;urip_testURLs[urip_current] != NULL;urip_current++) {
2876 urip_success = 1;
2877 parsed = urip_checkURL(urip_testURLs[urip_current]);
2878 if (urip_success != 1) {
2879 fprintf(stderr, "failed the URL passing test for %s",
2880 urip_testURLs[urip_current]);
2881 failures++;
2882 } else if (parsed != 1) {
2883 fprintf(stderr, "failed the parsing test for %s",
2884 urip_testURLs[urip_current]);
2885 failures++;
2886 }
2887 nb_tests++;
2888 }
2889
2890 xmlPopInputCallbacks();
2891 return(failures);
2892}
2893
William M. Brackca15a542005-07-06 20:41:33 +00002894#ifdef LIBXML_SCHEMAS_ENABLED
2895/************************************************************************
2896 * *
2897 * Schemas tests *
2898 * *
2899 ************************************************************************/
2900static int
2901schemasOneTest(const char *sch,
2902 const char *filename,
2903 const char *result,
2904 const char *err,
2905 int options,
2906 xmlSchemaPtr schemas) {
2907 xmlDocPtr doc;
2908 xmlSchemaValidCtxtPtr ctxt;
2909 int ret = 0;
Daniel Veillard381ff362006-06-18 17:31:31 +00002910 int validResult = 0;
William M. Brackca15a542005-07-06 20:41:33 +00002911 char *temp;
2912 FILE *schemasOutput;
2913
2914 doc = xmlReadFile(filename, NULL, options);
2915 if (doc == NULL) {
2916 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
2917 return(-1);
2918 }
2919
2920 temp = resultFilename(result, "", ".res");
2921 if (temp == NULL) {
2922 fprintf(stderr, "Out of memory\n");
2923 fatalError();
2924 }
2925 schemasOutput = fopen(temp, "wb");
2926 if (schemasOutput == NULL) {
2927 fprintf(stderr, "failed to open output file %s\n", temp);
2928 xmlFreeDoc(doc);
2929 free(temp);
2930 return(-1);
2931 }
2932
2933 ctxt = xmlSchemaNewValidCtxt(schemas);
2934 xmlSchemaSetValidErrors(ctxt,
2935 (xmlSchemaValidityErrorFunc) testErrorHandler,
2936 (xmlSchemaValidityWarningFunc) testErrorHandler,
2937 ctxt);
Daniel Veillard381ff362006-06-18 17:31:31 +00002938 validResult = xmlSchemaValidateDoc(ctxt, doc);
2939 if (validResult == 0) {
William M. Brackca15a542005-07-06 20:41:33 +00002940 fprintf(schemasOutput, "%s validates\n", filename);
Daniel Veillard381ff362006-06-18 17:31:31 +00002941 } else if (validResult > 0) {
William M. Brackca15a542005-07-06 20:41:33 +00002942 fprintf(schemasOutput, "%s fails to validate\n", filename);
2943 } else {
2944 fprintf(schemasOutput, "%s validation generated an internal error\n",
2945 filename);
2946 }
2947 fclose(schemasOutput);
2948 if (result) {
2949 if (compareFiles(temp, result)) {
2950 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
2951 ret = 1;
2952 }
2953 }
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002954 if (temp != NULL) {
2955 unlink(temp);
2956 free(temp);
2957 }
William M. Brackca15a542005-07-06 20:41:33 +00002958
Daniel Veillard381ff362006-06-18 17:31:31 +00002959 if ((validResult != 0) && (err != NULL)) {
William M. Brackca15a542005-07-06 20:41:33 +00002960 if (compareFileMem(err, testErrors, testErrorsSize)) {
2961 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
2962 ret = 1;
2963 }
2964 }
2965
William M. Brackca15a542005-07-06 20:41:33 +00002966 xmlSchemaFreeValidCtxt(ctxt);
2967 xmlFreeDoc(doc);
2968 return(ret);
2969}
2970/**
2971 * schemasTest:
2972 * @filename: the schemas file
2973 * @result: the file with expected result
2974 * @err: the file with error messages
2975 *
2976 * Parse a file containing URI, compose them against a fixed base and
2977 * check for errors
2978 *
2979 * Returns 0 in case of success, an error code otherwise
2980 */
2981static int
2982schemasTest(const char *filename,
2983 const char *resul ATTRIBUTE_UNUSED,
2984 const char *errr ATTRIBUTE_UNUSED,
2985 int options) {
2986 const char *base = baseFilename(filename);
2987 const char *base2;
2988 const char *instance;
2989 xmlSchemaParserCtxtPtr ctxt;
2990 xmlSchemaPtr schemas;
2991 int res = 0, len, ret;
2992 char pattern[500];
2993 char prefix[500];
2994 char result[500];
2995 char err[500];
2996 glob_t globbuf;
2997 size_t i;
2998 char count = 0;
2999
3000 /* first compile the schemas if possible */
3001 ctxt = xmlSchemaNewParserCtxt(filename);
3002 xmlSchemaSetParserErrors(ctxt,
3003 (xmlSchemaValidityErrorFunc) testErrorHandler,
3004 (xmlSchemaValidityWarningFunc) testErrorHandler,
3005 ctxt);
3006 schemas = xmlSchemaParse(ctxt);
3007 xmlSchemaFreeParserCtxt(ctxt);
3008
3009 /*
3010 * most of the mess is about the output filenames generated by the Makefile
3011 */
3012 len = strlen(base);
3013 if ((len > 499) || (len < 5)) {
3014 xmlSchemaFree(schemas);
3015 return(-1);
3016 }
3017 len -= 4; /* remove trailing .xsd */
3018 if (base[len - 2] == '_') {
3019 len -= 2; /* remove subtest number */
3020 }
3021 if (base[len - 2] == '_') {
3022 len -= 2; /* remove subtest number */
3023 }
3024 memcpy(prefix, base, len);
3025 prefix[len] = 0;
3026
3027 snprintf(pattern, 499, "./test/schemas/%s_?.xml", prefix);
3028 pattern[499] = 0;
3029
3030 if (base[len] == '_') {
3031 len += 2;
3032 memcpy(prefix, base, len);
3033 prefix[len] = 0;
3034 }
3035
3036 globbuf.gl_offs = 0;
3037 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3038 for (i = 0;i < globbuf.gl_pathc;i++) {
3039 testErrorsSize = 0;
3040 testErrors[0] = 0;
3041 instance = globbuf.gl_pathv[i];
3042 base2 = baseFilename(instance);
3043 len = strlen(base2);
3044 if ((len > 6) && (base2[len - 6] == '_')) {
3045 count = base2[len - 5];
3046 snprintf(result, 499, "result/schemas/%s_%c",
3047 prefix, count);
3048 result[499] = 0;
3049 snprintf(err, 499, "result/schemas/%s_%c.err",
3050 prefix, count);
3051 err[499] = 0;
3052 } else {
3053 fprintf(stderr, "don't know how to process %s\n", instance);
3054 continue;
3055 }
3056 if (schemas == NULL) {
3057 } else {
3058 nb_tests++;
3059 ret = schemasOneTest(filename, instance, result, err,
3060 options, schemas);
Daniel Veillard93e577f2005-11-15 08:50:04 +00003061 if (ret != 0)
3062 res = ret;
William M. Brackca15a542005-07-06 20:41:33 +00003063 }
3064 }
3065 globfree(&globbuf);
3066 xmlSchemaFree(schemas);
3067
3068 return(res);
3069}
3070
3071/************************************************************************
3072 * *
3073 * Schemas tests *
3074 * *
3075 ************************************************************************/
3076static int
3077rngOneTest(const char *sch,
3078 const char *filename,
3079 const char *result,
3080 const char *err,
3081 int options,
3082 xmlRelaxNGPtr schemas) {
3083 xmlDocPtr doc;
3084 xmlRelaxNGValidCtxtPtr ctxt;
3085 int ret = 0;
3086 char *temp;
3087 FILE *schemasOutput;
3088
3089 doc = xmlReadFile(filename, NULL, options);
3090 if (doc == NULL) {
3091 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
3092 return(-1);
3093 }
3094
3095 temp = resultFilename(result, "", ".res");
3096 if (temp == NULL) {
3097 fprintf(stderr, "Out of memory\n");
3098 fatalError();
3099 }
3100 schemasOutput = fopen(temp, "wb");
3101 if (schemasOutput == NULL) {
3102 fprintf(stderr, "failed to open output file %s\n", temp);
3103 xmlFreeDoc(doc);
3104 free(temp);
3105 return(-1);
3106 }
3107
3108 ctxt = xmlRelaxNGNewValidCtxt(schemas);
3109 xmlRelaxNGSetValidErrors(ctxt,
3110 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
3111 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
3112 ctxt);
3113 ret = xmlRelaxNGValidateDoc(ctxt, doc);
3114 if (ret == 0) {
3115 testErrorHandler(NULL, "%s validates\n", filename);
3116 } else if (ret > 0) {
3117 testErrorHandler(NULL, "%s fails to validate\n", filename);
3118 } else {
3119 testErrorHandler(NULL, "%s validation generated an internal error\n",
3120 filename);
3121 }
3122 fclose(schemasOutput);
3123 if (result) {
3124 if (compareFiles(temp, result)) {
3125 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
3126 ret = 1;
3127 }
3128 }
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003129 if (temp != NULL) {
3130 unlink(temp);
3131 free(temp);
3132 }
William M. Brackca15a542005-07-06 20:41:33 +00003133
3134 if (err != NULL) {
3135 if (compareFileMem(err, testErrors, testErrorsSize)) {
3136 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
3137 ret = 1;
3138 printf("%s", testErrors);
3139 }
3140 }
3141
3142
3143 xmlRelaxNGFreeValidCtxt(ctxt);
3144 xmlFreeDoc(doc);
3145 return(ret);
3146}
3147/**
3148 * rngTest:
3149 * @filename: the schemas file
3150 * @result: the file with expected result
3151 * @err: the file with error messages
3152 *
3153 * Parse an RNG schemas and then apply it to the related .xml
3154 *
3155 * Returns 0 in case of success, an error code otherwise
3156 */
3157static int
3158rngTest(const char *filename,
3159 const char *resul ATTRIBUTE_UNUSED,
3160 const char *errr ATTRIBUTE_UNUSED,
3161 int options) {
3162 const char *base = baseFilename(filename);
3163 const char *base2;
3164 const char *instance;
3165 xmlRelaxNGParserCtxtPtr ctxt;
3166 xmlRelaxNGPtr schemas;
3167 int res = 0, len, ret;
3168 char pattern[500];
3169 char prefix[500];
3170 char result[500];
3171 char err[500];
3172 glob_t globbuf;
3173 size_t i;
3174 char count = 0;
3175
3176 /* first compile the schemas if possible */
3177 ctxt = xmlRelaxNGNewParserCtxt(filename);
3178 xmlRelaxNGSetParserErrors(ctxt,
3179 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
3180 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
3181 ctxt);
3182 schemas = xmlRelaxNGParse(ctxt);
3183 xmlRelaxNGFreeParserCtxt(ctxt);
3184
3185 /*
3186 * most of the mess is about the output filenames generated by the Makefile
3187 */
3188 len = strlen(base);
3189 if ((len > 499) || (len < 5)) {
3190 xmlRelaxNGFree(schemas);
3191 return(-1);
3192 }
3193 len -= 4; /* remove trailing .rng */
3194 memcpy(prefix, base, len);
3195 prefix[len] = 0;
3196
3197 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
3198 pattern[499] = 0;
3199
3200 globbuf.gl_offs = 0;
3201 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3202 for (i = 0;i < globbuf.gl_pathc;i++) {
3203 testErrorsSize = 0;
3204 testErrors[0] = 0;
3205 instance = globbuf.gl_pathv[i];
3206 base2 = baseFilename(instance);
3207 len = strlen(base2);
3208 if ((len > 6) && (base2[len - 6] == '_')) {
3209 count = base2[len - 5];
3210 snprintf(result, 499, "result/relaxng/%s_%c",
3211 prefix, count);
3212 result[499] = 0;
3213 snprintf(err, 499, "result/relaxng/%s_%c.err",
3214 prefix, count);
3215 err[499] = 0;
3216 } else {
3217 fprintf(stderr, "don't know how to process %s\n", instance);
3218 continue;
3219 }
3220 if (schemas == NULL) {
3221 } else {
3222 nb_tests++;
3223 ret = rngOneTest(filename, instance, result, err,
3224 options, schemas);
3225 if (res != 0)
3226 ret = res;
3227 }
3228 }
3229 globfree(&globbuf);
3230 xmlRelaxNGFree(schemas);
3231
3232 return(res);
3233}
3234
3235#ifdef LIBXML_READER_ENABLED
3236/**
3237 * rngStreamTest:
3238 * @filename: the schemas file
3239 * @result: the file with expected result
3240 * @err: the file with error messages
3241 *
Daniel Veillardaa6de472008-08-25 14:53:31 +00003242 * Parse a set of files with streaming, applying an RNG schemas
William M. Brackca15a542005-07-06 20:41:33 +00003243 *
3244 * Returns 0 in case of success, an error code otherwise
3245 */
3246static int
3247rngStreamTest(const char *filename,
3248 const char *resul ATTRIBUTE_UNUSED,
3249 const char *errr ATTRIBUTE_UNUSED,
3250 int options) {
3251 const char *base = baseFilename(filename);
3252 const char *base2;
3253 const char *instance;
3254 int res = 0, len, ret;
3255 char pattern[500];
3256 char prefix[500];
3257 char result[500];
3258 char err[500];
3259 glob_t globbuf;
3260 size_t i;
3261 char count = 0;
3262 xmlTextReaderPtr reader;
3263 int disable_err = 0;
3264
3265 /*
3266 * most of the mess is about the output filenames generated by the Makefile
3267 */
3268 len = strlen(base);
3269 if ((len > 499) || (len < 5)) {
3270 fprintf(stderr, "len(base) == %d !\n", len);
3271 return(-1);
3272 }
3273 len -= 4; /* remove trailing .rng */
3274 memcpy(prefix, base, len);
3275 prefix[len] = 0;
3276
3277 /*
3278 * strictly unifying the error messages is nearly impossible this
3279 * hack is also done in the Makefile
3280 */
3281 if ((!strcmp(prefix, "tutor10_1")) || (!strcmp(prefix, "tutor10_2")) ||
Daniel Veillardec18c962009-08-26 18:37:43 +02003282 (!strcmp(prefix, "tutor3_2")) || (!strcmp(prefix, "307377")) ||
3283 (!strcmp(prefix, "tutor8_2")))
William M. Brackca15a542005-07-06 20:41:33 +00003284 disable_err = 1;
3285
3286 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
3287 pattern[499] = 0;
3288
3289 globbuf.gl_offs = 0;
3290 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3291 for (i = 0;i < globbuf.gl_pathc;i++) {
3292 testErrorsSize = 0;
3293 testErrors[0] = 0;
3294 instance = globbuf.gl_pathv[i];
3295 base2 = baseFilename(instance);
3296 len = strlen(base2);
3297 if ((len > 6) && (base2[len - 6] == '_')) {
3298 count = base2[len - 5];
3299 snprintf(result, 499, "result/relaxng/%s_%c",
3300 prefix, count);
3301 result[499] = 0;
3302 snprintf(err, 499, "result/relaxng/%s_%c.err",
3303 prefix, count);
3304 err[499] = 0;
3305 } else {
3306 fprintf(stderr, "don't know how to process %s\n", instance);
3307 continue;
3308 }
3309 reader = xmlReaderForFile(instance, NULL, options);
3310 if (reader == NULL) {
3311 fprintf(stderr, "Failed to build reder for %s\n", instance);
3312 }
3313 if (disable_err == 1)
3314 ret = streamProcessTest(instance, result, NULL, reader, filename);
3315 else
3316 ret = streamProcessTest(instance, result, err, reader, filename);
3317 xmlFreeTextReader(reader);
3318 if (ret != 0) {
3319 fprintf(stderr, "instance %s failed\n", instance);
3320 res = ret;
3321 }
3322 }
3323 globfree(&globbuf);
3324
3325 return(res);
3326}
3327#endif /* READER */
3328
3329#endif
3330
3331#ifdef LIBXML_PATTERN_ENABLED
3332#ifdef LIBXML_READER_ENABLED
3333/************************************************************************
3334 * *
3335 * Patterns tests *
3336 * *
3337 ************************************************************************/
3338static void patternNode(FILE *out, xmlTextReaderPtr reader,
3339 const char *pattern, xmlPatternPtr patternc,
3340 xmlStreamCtxtPtr patstream) {
3341 xmlChar *path = NULL;
3342 int match = -1;
3343 int type, empty;
3344
3345 type = xmlTextReaderNodeType(reader);
3346 empty = xmlTextReaderIsEmptyElement(reader);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003347
William M. Brackca15a542005-07-06 20:41:33 +00003348 if (type == XML_READER_TYPE_ELEMENT) {
3349 /* do the check only on element start */
3350 match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader));
3351
3352 if (match) {
3353 path = xmlGetNodePath(xmlTextReaderCurrentNode(reader));
3354 fprintf(out, "Node %s matches pattern %s\n", path, pattern);
3355 }
3356 }
3357 if (patstream != NULL) {
3358 int ret;
3359
3360 if (type == XML_READER_TYPE_ELEMENT) {
3361 ret = xmlStreamPush(patstream,
3362 xmlTextReaderConstLocalName(reader),
3363 xmlTextReaderConstNamespaceUri(reader));
3364 if (ret < 0) {
3365 fprintf(out, "xmlStreamPush() failure\n");
3366 xmlFreeStreamCtxt(patstream);
3367 patstream = NULL;
3368 } else if (ret != match) {
3369 if (path == NULL) {
3370 path = xmlGetNodePath(
3371 xmlTextReaderCurrentNode(reader));
3372 }
3373 fprintf(out,
3374 "xmlPatternMatch and xmlStreamPush disagree\n");
3375 fprintf(out,
3376 " pattern %s node %s\n",
3377 pattern, path);
3378 }
William M. Brackca15a542005-07-06 20:41:33 +00003379
Daniel Veillardaa6de472008-08-25 14:53:31 +00003380
3381 }
William M. Brackca15a542005-07-06 20:41:33 +00003382 if ((type == XML_READER_TYPE_END_ELEMENT) ||
3383 ((type == XML_READER_TYPE_ELEMENT) && (empty))) {
3384 ret = xmlStreamPop(patstream);
3385 if (ret < 0) {
3386 fprintf(out, "xmlStreamPop() failure\n");
3387 xmlFreeStreamCtxt(patstream);
3388 patstream = NULL;
3389 }
3390 }
3391 }
3392 if (path != NULL)
3393 xmlFree(path);
3394}
3395
3396/**
3397 * patternTest:
3398 * @filename: the schemas file
3399 * @result: the file with expected result
3400 * @err: the file with error messages
3401 *
Daniel Veillardaa6de472008-08-25 14:53:31 +00003402 * Parse a set of files with streaming, applying an RNG schemas
William M. Brackca15a542005-07-06 20:41:33 +00003403 *
3404 * Returns 0 in case of success, an error code otherwise
3405 */
3406static int
3407patternTest(const char *filename,
3408 const char *resul ATTRIBUTE_UNUSED,
3409 const char *err ATTRIBUTE_UNUSED,
3410 int options) {
3411 xmlPatternPtr patternc = NULL;
3412 xmlStreamCtxtPtr patstream = NULL;
3413 FILE *o, *f;
3414 char str[1024];
3415 char xml[500];
3416 char result[500];
3417 int len, i;
3418 int ret = 0, res;
3419 char *temp;
3420 xmlTextReaderPtr reader;
3421 xmlDocPtr doc;
3422
3423 len = strlen(filename);
3424 len -= 4;
3425 memcpy(xml, filename, len);
3426 xml[len] = 0;
3427 snprintf(result, 499, "result/pattern/%s", baseFilename(xml));
3428 result[499] = 0;
3429 memcpy(xml + len, ".xml", 5);
3430
3431 if (!checkTestFile(xml)) {
3432 fprintf(stderr, "Missing xml file %s\n", xml);
3433 return(-1);
3434 }
3435 if (!checkTestFile(result)) {
3436 fprintf(stderr, "Missing result file %s\n", result);
3437 return(-1);
3438 }
3439 f = fopen(filename, "rb");
3440 if (f == NULL) {
3441 fprintf(stderr, "Failed to open %s\n", filename);
3442 return(-1);
3443 }
3444 temp = resultFilename(filename, "", ".res");
3445 if (temp == NULL) {
3446 fprintf(stderr, "Out of memory\n");
3447 fatalError();
3448 }
3449 o = fopen(temp, "wb");
3450 if (o == NULL) {
3451 fprintf(stderr, "failed to open output file %s\n", temp);
3452 fclose(f);
3453 free(temp);
3454 return(-1);
3455 }
3456 while (1) {
3457 /*
3458 * read one line in string buffer.
3459 */
3460 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
3461 break;
3462
3463 /*
3464 * remove the ending spaces
3465 */
3466 i = strlen(str);
3467 while ((i > 0) &&
3468 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
3469 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
3470 i--;
3471 str[i] = 0;
3472 }
3473 doc = xmlReadFile(xml, NULL, options);
3474 if (doc == NULL) {
3475 fprintf(stderr, "Failed to parse %s\n", xml);
3476 ret = 1;
3477 } else {
3478 xmlNodePtr root;
3479 const xmlChar *namespaces[22];
3480 int j;
3481 xmlNsPtr ns;
3482
3483 root = xmlDocGetRootElement(doc);
3484 for (ns = root->nsDef, j = 0;ns != NULL && j < 20;ns=ns->next) {
3485 namespaces[j++] = ns->href;
3486 namespaces[j++] = ns->prefix;
3487 }
3488 namespaces[j++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003489 namespaces[j] = NULL;
William M. Brackca15a542005-07-06 20:41:33 +00003490
3491 patternc = xmlPatterncompile((const xmlChar *) str, doc->dict,
3492 0, &namespaces[0]);
3493 if (patternc == NULL) {
3494 testErrorHandler(NULL,
3495 "Pattern %s failed to compile\n", str);
3496 xmlFreeDoc(doc);
3497 ret = 1;
3498 continue;
3499 }
3500 patstream = xmlPatternGetStreamCtxt(patternc);
3501 if (patstream != NULL) {
3502 ret = xmlStreamPush(patstream, NULL, NULL);
3503 if (ret < 0) {
3504 fprintf(stderr, "xmlStreamPush() failure\n");
3505 xmlFreeStreamCtxt(patstream);
3506 patstream = NULL;
3507 }
3508 }
3509 nb_tests++;
3510
3511 reader = xmlReaderWalker(doc);
3512 res = xmlTextReaderRead(reader);
3513 while (res == 1) {
3514 patternNode(o, reader, str, patternc, patstream);
3515 res = xmlTextReaderRead(reader);
3516 }
3517 if (res != 0) {
3518 fprintf(o, "%s : failed to parse\n", filename);
3519 }
3520 xmlFreeTextReader(reader);
3521 xmlFreeDoc(doc);
3522 xmlFreeStreamCtxt(patstream);
3523 patstream = NULL;
3524 xmlFreePattern(patternc);
3525
3526 }
3527 }
3528
3529 fclose(f);
3530 fclose(o);
3531
3532 ret = compareFiles(temp, result);
3533 if (ret) {
3534 fprintf(stderr, "Result for %s failed\n", filename);
3535 ret = 1;
3536 }
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003537 if (temp != NULL) {
3538 unlink(temp);
3539 free(temp);
3540 }
William M. Brackca15a542005-07-06 20:41:33 +00003541 return(ret);
3542}
3543#endif /* READER */
3544#endif /* PATTERN */
3545#ifdef LIBXML_C14N_ENABLED
3546/************************************************************************
3547 * *
3548 * Canonicalization tests *
3549 * *
3550 ************************************************************************/
3551static xmlXPathObjectPtr
3552load_xpath_expr (xmlDocPtr parent_doc, const char* filename) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00003553 xmlXPathObjectPtr xpath;
William M. Brackca15a542005-07-06 20:41:33 +00003554 xmlDocPtr doc;
3555 xmlChar *expr;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003556 xmlXPathContextPtr ctx;
William M. Brackca15a542005-07-06 20:41:33 +00003557 xmlNodePtr node;
3558 xmlNsPtr ns;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003559
William M. Brackca15a542005-07-06 20:41:33 +00003560 /*
3561 * load XPath expr as a file
3562 */
3563 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3564 xmlSubstituteEntitiesDefault(1);
3565
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003566 doc = xmlReadFile(filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
William M. Brackca15a542005-07-06 20:41:33 +00003567 if (doc == NULL) {
3568 fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
3569 return(NULL);
3570 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003571
William M. Brackca15a542005-07-06 20:41:33 +00003572 /*
3573 * Check the document is of the right kind
Daniel Veillardaa6de472008-08-25 14:53:31 +00003574 */
William M. Brackca15a542005-07-06 20:41:33 +00003575 if(xmlDocGetRootElement(doc) == NULL) {
3576 fprintf(stderr,"Error: empty document for file \"%s\"\n", filename);
3577 xmlFreeDoc(doc);
3578 return(NULL);
3579 }
3580
3581 node = doc->children;
3582 while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) {
3583 node = node->next;
3584 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003585
3586 if(node == NULL) {
William M. Brackca15a542005-07-06 20:41:33 +00003587 fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename);
3588 xmlFreeDoc(doc);
3589 return(NULL);
3590 }
3591
3592 expr = xmlNodeGetContent(node);
3593 if(expr == NULL) {
3594 fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename);
3595 xmlFreeDoc(doc);
3596 return(NULL);
3597 }
3598
3599 ctx = xmlXPathNewContext(parent_doc);
3600 if(ctx == NULL) {
3601 fprintf(stderr,"Error: unable to create new context\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003602 xmlFree(expr);
3603 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003604 return(NULL);
3605 }
3606
3607 /*
3608 * Register namespaces
3609 */
3610 ns = node->nsDef;
3611 while(ns != NULL) {
3612 if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) {
3613 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 +00003614 xmlFree(expr);
3615 xmlXPathFreeContext(ctx);
3616 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003617 return(NULL);
3618 }
3619 ns = ns->next;
3620 }
3621
Daniel Veillardaa6de472008-08-25 14:53:31 +00003622 /*
William M. Brackca15a542005-07-06 20:41:33 +00003623 * Evaluate xpath
3624 */
3625 xpath = xmlXPathEvalExpression(expr, ctx);
3626 if(xpath == NULL) {
3627 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003628xmlFree(expr);
3629 xmlXPathFreeContext(ctx);
3630 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003631 return(NULL);
3632 }
3633
3634 /* print_xpath_nodes(xpath->nodesetval); */
3635
Daniel Veillardaa6de472008-08-25 14:53:31 +00003636 xmlFree(expr);
3637 xmlXPathFreeContext(ctx);
3638 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003639 return(xpath);
3640}
3641
3642/*
3643 * Macro used to grow the current buffer.
3644 */
3645#define xxx_growBufferReentrant() { \
3646 buffer_size *= 2; \
3647 buffer = (xmlChar **) \
Daniel Veillardaa6de472008-08-25 14:53:31 +00003648 xmlRealloc(buffer, buffer_size * sizeof(xmlChar*)); \
William M. Brackca15a542005-07-06 20:41:33 +00003649 if (buffer == NULL) { \
3650 perror("realloc failed"); \
3651 return(NULL); \
3652 } \
3653}
3654
3655static xmlChar **
3656parse_list(xmlChar *str) {
3657 xmlChar **buffer;
3658 xmlChar **out = NULL;
3659 int buffer_size = 0;
3660 int len;
3661
3662 if(str == NULL) {
3663 return(NULL);
3664 }
3665
3666 len = xmlStrlen(str);
3667 if((str[0] == '\'') && (str[len - 1] == '\'')) {
3668 str[len - 1] = '\0';
3669 str++;
William M. Brackca15a542005-07-06 20:41:33 +00003670 }
3671 /*
3672 * allocate an translation buffer.
3673 */
3674 buffer_size = 1000;
3675 buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*));
3676 if (buffer == NULL) {
3677 perror("malloc failed");
3678 return(NULL);
3679 }
3680 out = buffer;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003681
William M. Brackca15a542005-07-06 20:41:33 +00003682 while(*str != '\0') {
3683 if (out - buffer > buffer_size - 10) {
3684 int indx = out - buffer;
3685
3686 xxx_growBufferReentrant();
3687 out = &buffer[indx];
3688 }
3689 (*out++) = str;
3690 while(*str != ',' && *str != '\0') ++str;
3691 if(*str == ',') *(str++) = '\0';
3692 }
3693 (*out) = NULL;
3694 return buffer;
3695}
3696
Daniel Veillardaa6de472008-08-25 14:53:31 +00003697static int
Aleksey Sanin83868242009-07-09 10:26:22 +02003698c14nRunTest(const char* xml_filename, int with_comments, int mode,
William M. Brackca15a542005-07-06 20:41:33 +00003699 const char* xpath_filename, const char *ns_filename,
3700 const char* result_file) {
3701 xmlDocPtr doc;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003702 xmlXPathObjectPtr xpath = NULL;
William M. Brackca15a542005-07-06 20:41:33 +00003703 xmlChar *result = NULL;
3704 int ret;
3705 xmlChar **inclusive_namespaces = NULL;
3706 const char *nslist = NULL;
3707 int nssize;
3708
3709
3710 /*
3711 * build an XML tree from a the file; we need to add default
3712 * attributes and resolve all character and entities references
3713 */
3714 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3715 xmlSubstituteEntitiesDefault(1);
3716
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003717 doc = xmlReadFile(xml_filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
William M. Brackca15a542005-07-06 20:41:33 +00003718 if (doc == NULL) {
3719 fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename);
3720 return(-1);
3721 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003722
William M. Brackca15a542005-07-06 20:41:33 +00003723 /*
3724 * Check the document is of the right kind
Daniel Veillardaa6de472008-08-25 14:53:31 +00003725 */
William M. Brackca15a542005-07-06 20:41:33 +00003726 if(xmlDocGetRootElement(doc) == NULL) {
3727 fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename);
3728 xmlFreeDoc(doc);
3729 return(-1);
3730 }
3731
Daniel Veillardaa6de472008-08-25 14:53:31 +00003732 /*
3733 * load xpath file if specified
William M. Brackca15a542005-07-06 20:41:33 +00003734 */
3735 if(xpath_filename) {
3736 xpath = load_xpath_expr(doc, xpath_filename);
3737 if(xpath == NULL) {
3738 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003739 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003740 return(-1);
3741 }
3742 }
3743
3744 if (ns_filename != NULL) {
3745 if (loadMem(ns_filename, &nslist, &nssize)) {
3746 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3747 if(xpath != NULL) xmlXPathFreeObject(xpath);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003748 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003749 return(-1);
3750 }
3751 inclusive_namespaces = parse_list((xmlChar *) nslist);
3752 }
3753
3754 /*
3755 * Canonical form
Daniel Veillardaa6de472008-08-25 14:53:31 +00003756 */
William M. Brackca15a542005-07-06 20:41:33 +00003757 /* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */
Daniel Veillardaa6de472008-08-25 14:53:31 +00003758 ret = xmlC14NDocDumpMemory(doc,
3759 (xpath) ? xpath->nodesetval : NULL,
Aleksey Sanin83868242009-07-09 10:26:22 +02003760 mode, inclusive_namespaces,
William M. Brackca15a542005-07-06 20:41:33 +00003761 with_comments, &result);
3762 if (ret >= 0) {
3763 if(result != NULL) {
3764 if (compareFileMem(result_file, (const char *) result, ret)) {
3765 fprintf(stderr, "Result mismatch for %s\n", xml_filename);
Aleksey Sanin83868242009-07-09 10:26:22 +02003766 fprintf(stderr, "RESULT:\n%s\n", (const char*)result);
William M. Brackca15a542005-07-06 20:41:33 +00003767 ret = -1;
3768 }
3769 }
3770 } else {
3771 fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret);
3772 ret = -1;
3773 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003774
William M. Brackca15a542005-07-06 20:41:33 +00003775 /*
3776 * Cleanup
Daniel Veillardaa6de472008-08-25 14:53:31 +00003777 */
William M. Brackca15a542005-07-06 20:41:33 +00003778 if (result != NULL) xmlFree(result);
3779 if(xpath != NULL) xmlXPathFreeObject(xpath);
3780 if (inclusive_namespaces != NULL) xmlFree(inclusive_namespaces);
3781 if (nslist != NULL) free((char *) nslist);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003782 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003783
3784 return(ret);
3785}
3786
3787static int
Aleksey Sanin83868242009-07-09 10:26:22 +02003788c14nCommonTest(const char *filename, int with_comments, int mode,
William M. Brackca15a542005-07-06 20:41:33 +00003789 const char *subdir) {
3790 char buf[500];
3791 char prefix[500];
3792 const char *base;
3793 int len;
3794 char *result = NULL;
3795 char *xpath = NULL;
3796 char *ns = NULL;
3797 int ret = 0;
3798
3799 base = baseFilename(filename);
3800 len = strlen(base);
3801 len -= 4;
3802 memcpy(prefix, base, len);
3803 prefix[len] = 0;
3804
3805 snprintf(buf, 499, "result/c14n/%s/%s", subdir,prefix);
3806 if (!checkTestFile(buf)) {
3807 fprintf(stderr, "Missing result file %s", buf);
3808 return(-1);
3809 }
3810 result = strdup(buf);
3811 snprintf(buf, 499, "test/c14n/%s/%s.xpath", subdir,prefix);
3812 if (checkTestFile(buf)) {
3813 xpath = strdup(buf);
3814 }
3815 snprintf(buf, 499, "test/c14n/%s/%s.ns", subdir,prefix);
3816 if (checkTestFile(buf)) {
3817 ns = strdup(buf);
3818 }
3819
3820 nb_tests++;
Aleksey Sanin83868242009-07-09 10:26:22 +02003821 if (c14nRunTest(filename, with_comments, mode,
William M. Brackca15a542005-07-06 20:41:33 +00003822 xpath, ns, result) < 0)
3823 ret = 1;
3824
3825 if (result != NULL) free(result);
3826 if (xpath != NULL) free(xpath);
3827 if (ns != NULL) free(ns);
3828 return(ret);
3829}
3830
3831static int
3832c14nWithCommentTest(const char *filename,
3833 const char *resul ATTRIBUTE_UNUSED,
3834 const char *err ATTRIBUTE_UNUSED,
3835 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003836 return(c14nCommonTest(filename, 1, XML_C14N_1_0, "with-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003837}
3838static int
3839c14nWithoutCommentTest(const char *filename,
3840 const char *resul ATTRIBUTE_UNUSED,
3841 const char *err ATTRIBUTE_UNUSED,
3842 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003843 return(c14nCommonTest(filename, 0, XML_C14N_1_0, "without-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003844}
3845static int
3846c14nExcWithoutCommentTest(const char *filename,
3847 const char *resul ATTRIBUTE_UNUSED,
3848 const char *err ATTRIBUTE_UNUSED,
3849 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003850 return(c14nCommonTest(filename, 0, XML_C14N_EXCLUSIVE_1_0, "exc-without-comments"));
3851}
3852static int
3853c14n11WithoutCommentTest(const char *filename,
3854 const char *resul ATTRIBUTE_UNUSED,
3855 const char *err ATTRIBUTE_UNUSED,
3856 int options ATTRIBUTE_UNUSED) {
3857 return(c14nCommonTest(filename, 0, XML_C14N_1_1, "1-1-without-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003858}
3859#endif
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003860#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) && defined (LIBXML_SAX1_ENABLED)
William M. Brackca15a542005-07-06 20:41:33 +00003861/************************************************************************
3862 * *
3863 * Catalog and threads test *
3864 * *
3865 ************************************************************************/
3866
3867/*
3868 * mostly a cut and paste from testThreads.c
3869 */
3870#define MAX_ARGC 20
3871
3872static const char *catalog = "test/threads/complex.xml";
3873static const char *testfiles[] = {
3874 "test/threads/abc.xml",
3875 "test/threads/acb.xml",
3876 "test/threads/bac.xml",
3877 "test/threads/bca.xml",
3878 "test/threads/cab.xml",
3879 "test/threads/cba.xml",
3880 "test/threads/invalid.xml",
3881};
3882
Daniel Veillard24505b02005-07-28 23:49:35 +00003883static const char *Okay = "OK";
3884static const char *Failed = "Failed";
William M. Brackca15a542005-07-06 20:41:33 +00003885
3886#ifndef xmlDoValidityCheckingDefaultValue
3887#error xmlDoValidityCheckingDefaultValue is not a macro
3888#endif
3889#ifndef xmlGenericErrorContext
3890#error xmlGenericErrorContext is not a macro
3891#endif
3892
3893static void *
3894thread_specific_data(void *private_data)
3895{
3896 xmlDocPtr myDoc;
3897 const char *filename = (const char *) private_data;
3898 int okay = 1;
3899
3900 if (!strcmp(filename, "test/threads/invalid.xml")) {
3901 xmlDoValidityCheckingDefaultValue = 0;
3902 xmlGenericErrorContext = stdout;
3903 } else {
3904 xmlDoValidityCheckingDefaultValue = 1;
3905 xmlGenericErrorContext = stderr;
3906 }
3907 myDoc = xmlParseFile(filename);
3908 if (myDoc) {
3909 xmlFreeDoc(myDoc);
3910 } else {
3911 printf("parse failed\n");
3912 okay = 0;
3913 }
3914 if (!strcmp(filename, "test/threads/invalid.xml")) {
3915 if (xmlDoValidityCheckingDefaultValue != 0) {
3916 printf("ValidityCheckingDefaultValue override failed\n");
3917 okay = 0;
3918 }
3919 if (xmlGenericErrorContext != stdout) {
3920 printf("xmlGenericErrorContext override failed\n");
3921 okay = 0;
3922 }
3923 } else {
3924 if (xmlDoValidityCheckingDefaultValue != 1) {
3925 printf("ValidityCheckingDefaultValue override failed\n");
3926 okay = 0;
3927 }
3928 if (xmlGenericErrorContext != stderr) {
3929 printf("xmlGenericErrorContext override failed\n");
3930 okay = 0;
3931 }
3932 }
3933 if (okay == 0)
3934 return ((void *) Failed);
3935 return ((void *) Okay);
3936}
3937
Tim Rice85b07d12009-08-25 12:38:29 +02003938#if defined(linux) || defined(__sun) || defined(__APPLE_CC__)
William M. Brackca15a542005-07-06 20:41:33 +00003939
3940#include <pthread.h>
3941
3942static pthread_t tid[MAX_ARGC];
3943
3944static int
3945testThread(void)
3946{
3947 unsigned int i, repeat;
3948 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
3949 void *results[MAX_ARGC];
3950 int ret;
3951 int res = 0;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003952
William M. Brackca15a542005-07-06 20:41:33 +00003953 xmlInitParser();
3954
3955 for (repeat = 0; repeat < 500; repeat++) {
3956 xmlLoadCatalog(catalog);
3957 nb_tests++;
3958
3959 for (i = 0; i < num_threads; i++) {
3960 results[i] = NULL;
3961 tid[i] = (pthread_t) - 1;
3962 }
3963
3964 for (i = 0; i < num_threads; i++) {
3965 ret = pthread_create(&tid[i], 0, thread_specific_data,
3966 (void *) testfiles[i]);
3967 if (ret != 0) {
3968 fprintf(stderr, "pthread_create failed\n");
3969 return (1);
3970 }
3971 }
3972 for (i = 0; i < num_threads; i++) {
3973 ret = pthread_join(tid[i], &results[i]);
3974 if (ret != 0) {
3975 fprintf(stderr, "pthread_join failed\n");
3976 return (1);
3977 }
3978 }
3979
3980 xmlCatalogCleanup();
3981 for (i = 0; i < num_threads; i++)
3982 if (results[i] != (void *) Okay) {
3983 fprintf(stderr, "Thread %d handling %s failed\n",
3984 i, testfiles[i]);
3985 res = 1;
3986 }
3987 }
3988 return (res);
3989}
3990
3991#elif defined WIN32
3992#include <windows.h>
3993#include <string.h>
3994
3995#define TEST_REPEAT_COUNT 500
3996
3997static HANDLE tid[MAX_ARGC];
3998
3999static DWORD WINAPI
4000win32_thread_specific_data(void *private_data)
4001{
4002 return((DWORD) thread_specific_data(private_data));
4003}
4004
4005static int
4006testThread(void)
4007{
4008 unsigned int i, repeat;
4009 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
4010 DWORD results[MAX_ARGC];
4011 BOOL ret;
4012 int res = 0;
4013
4014 xmlInitParser();
4015 for (repeat = 0; repeat < TEST_REPEAT_COUNT; repeat++) {
4016 xmlLoadCatalog(catalog);
4017 nb_tests++;
4018
4019 for (i = 0; i < num_threads; i++) {
4020 results[i] = 0;
4021 tid[i] = (HANDLE) - 1;
4022 }
4023
4024 for (i = 0; i < num_threads; i++) {
4025 DWORD useless;
4026
4027 tid[i] = CreateThread(NULL, 0,
Daniel Veillardaa6de472008-08-25 14:53:31 +00004028 win32_thread_specific_data,
William M. Brackca15a542005-07-06 20:41:33 +00004029 (void *) testfiles[i], 0,
4030 &useless);
4031 if (tid[i] == NULL) {
4032 fprintf(stderr, "CreateThread failed\n");
4033 return(1);
4034 }
4035 }
4036
4037 if (WaitForMultipleObjects(num_threads, tid, TRUE, INFINITE) ==
4038 WAIT_FAILED) {
4039 fprintf(stderr, "WaitForMultipleObjects failed\n");
4040 return(1);
4041 }
4042
4043 for (i = 0; i < num_threads; i++) {
4044 ret = GetExitCodeThread(tid[i], &results[i]);
4045 if (ret == 0) {
4046 fprintf(stderr, "GetExitCodeThread failed\n");
4047 return(1);
4048 }
4049 CloseHandle(tid[i]);
4050 }
4051
4052 xmlCatalogCleanup();
4053 for (i = 0; i < num_threads; i++) {
4054 if (results[i] != (DWORD) Okay) {
4055 fprintf(stderr, "Thread %d handling %s failed\n",
4056 i, testfiles[i]);
4057 res = 1;
4058 }
4059 }
4060 }
4061
4062 return (res);
4063}
4064
4065#elif defined __BEOS__
4066#include <OS.h>
4067
4068static thread_id tid[MAX_ARGC];
4069
4070static int
4071testThread(void)
4072{
4073 unsigned int i, repeat;
4074 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
4075 void *results[MAX_ARGC];
4076 status_t ret;
4077 int res = 0;
4078
4079 xmlInitParser();
4080 for (repeat = 0; repeat < 500; repeat++) {
4081 xmlLoadCatalog(catalog);
4082 for (i = 0; i < num_threads; i++) {
4083 results[i] = NULL;
4084 tid[i] = (thread_id) - 1;
4085 }
4086 for (i = 0; i < num_threads; i++) {
4087 tid[i] =
4088 spawn_thread(thread_specific_data, "xmlTestThread",
4089 B_NORMAL_PRIORITY, (void *) testfiles[i]);
4090 if (tid[i] < B_OK) {
4091 fprintf(stderr, "beos_thread_create failed\n");
4092 return (1);
4093 }
4094 printf("beos_thread_create %d -> %d\n", i, tid[i]);
4095 }
4096 for (i = 0; i < num_threads; i++) {
4097 ret = wait_for_thread(tid[i], &results[i]);
4098 printf("beos_thread_wait %d -> %d\n", i, ret);
4099 if (ret != B_OK) {
4100 fprintf(stderr, "beos_thread_wait failed\n");
4101 return (1);
4102 }
4103 }
4104
4105 xmlCatalogCleanup();
4106 ret = B_OK;
4107 for (i = 0; i < num_threads; i++)
4108 if (results[i] != (void *) Okay) {
4109 printf("Thread %d handling %s failed\n", i, testfiles[i]);
4110 ret = B_ERROR;
4111 }
4112 }
4113 if (ret != B_OK)
4114 return(1);
4115 return (0);
4116}
4117#else
4118static int
4119testThread(void)
4120{
4121 fprintf(stderr,
4122 "Specific platform thread support not detected\n");
4123 return (-1);
4124}
4125#endif
Daniel Veillardaa6de472008-08-25 14:53:31 +00004126static int
William M. Brackca15a542005-07-06 20:41:33 +00004127threadsTest(const char *filename ATTRIBUTE_UNUSED,
4128 const char *resul ATTRIBUTE_UNUSED,
4129 const char *err ATTRIBUTE_UNUSED,
4130 int options ATTRIBUTE_UNUSED) {
4131 return(testThread());
4132}
4133#endif
4134/************************************************************************
4135 * *
4136 * Tests Descriptions *
4137 * *
4138 ************************************************************************/
4139
4140static
4141testDesc testDescriptions[] = {
4142 { "XML regression tests" ,
4143 oldParseTest, "./test/*", "result/", "", NULL,
4144 0 },
4145 { "XML regression tests on memory" ,
4146 memParseTest, "./test/*", "result/", "", NULL,
4147 0 },
4148 { "XML entity subst regression tests" ,
4149 noentParseTest, "./test/*", "result/noent/", "", NULL,
4150 XML_PARSE_NOENT },
4151 { "XML Namespaces regression tests",
4152 errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err",
4153 0 },
4154 { "Error cases regression tests",
4155 errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err",
4156 0 },
4157#ifdef LIBXML_READER_ENABLED
4158 { "Error cases stream regression tests",
4159 streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str",
4160 0 },
4161 { "Reader regression tests",
4162 streamParseTest, "./test/*", "result/", ".rdr", NULL,
4163 0 },
4164 { "Reader entities substitution regression tests",
4165 streamParseTest, "./test/*", "result/", ".rde", NULL,
4166 XML_PARSE_NOENT },
4167 { "Reader on memory regression tests",
4168 streamMemParseTest, "./test/*", "result/", ".rdr", NULL,
4169 0 },
4170 { "Walker regression tests",
4171 walkerParseTest, "./test/*", "result/", ".rdr", NULL,
4172 0 },
4173#endif
4174#ifdef LIBXML_SAX1_ENABLED
4175 { "SAX1 callbacks regression tests" ,
4176 saxParseTest, "./test/*", "result/", ".sax", NULL,
4177 XML_PARSE_SAX1 },
4178 { "SAX2 callbacks regression tests" ,
4179 saxParseTest, "./test/*", "result/", ".sax2", NULL,
4180 0 },
4181#endif
4182#ifdef LIBXML_PUSH_ENABLED
4183 { "XML push regression tests" ,
4184 pushParseTest, "./test/*", "result/", "", NULL,
4185 0 },
4186#endif
4187#ifdef LIBXML_HTML_ENABLED
4188 { "HTML regression tests" ,
4189 errParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4190 XML_PARSE_HTML },
4191#ifdef LIBXML_PUSH_ENABLED
4192 { "Push HTML regression tests" ,
4193 pushParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4194 XML_PARSE_HTML },
4195#endif
4196#ifdef LIBXML_SAX1_ENABLED
4197 { "HTML SAX regression tests" ,
4198 saxParseTest, "./test/HTML/*", "result/HTML/", ".sax", NULL,
4199 XML_PARSE_HTML },
4200#endif
4201#endif
4202#ifdef LIBXML_VALID_ENABLED
4203 { "Valid documents regression tests" ,
4204 errParseTest, "./test/VCM/*", NULL, NULL, NULL,
4205 XML_PARSE_DTDVALID },
4206 { "Validity checking regression tests" ,
4207 errParseTest, "./test/VC/*", "result/VC/", NULL, "",
4208 XML_PARSE_DTDVALID },
4209 { "General documents valid regression tests" ,
4210 errParseTest, "./test/valid/*", "result/valid/", "", ".err",
4211 XML_PARSE_DTDVALID },
4212#endif
4213#ifdef LIBXML_XINCLUDE_ENABLED
4214 { "XInclude regression tests" ,
4215 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4216 /* Ignore errors at this point ".err", */
4217 XML_PARSE_XINCLUDE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004218#ifdef LIBXML_READER_ENABLED
William M. Brackca15a542005-07-06 20:41:33 +00004219 { "XInclude xmlReader regression tests",
4220 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4221 /* Ignore errors at this point ".err", */
4222 NULL, XML_PARSE_XINCLUDE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004223#endif
William M. Brackca15a542005-07-06 20:41:33 +00004224 { "XInclude regression tests stripping include nodes" ,
4225 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4226 /* Ignore errors at this point ".err", */
4227 XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004228#ifdef LIBXML_READER_ENABLED
William M. Brackca15a542005-07-06 20:41:33 +00004229 { "XInclude xmlReader regression tests stripping include nodes",
4230 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4231 /* Ignore errors at this point ".err", */
4232 NULL, XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
4233#endif
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004234#endif
William M. Brackca15a542005-07-06 20:41:33 +00004235#ifdef LIBXML_XPATH_ENABLED
4236#ifdef LIBXML_DEBUG_ENABLED
4237 { "XPath expressions regression tests" ,
4238 xpathExprTest, "./test/XPath/expr/*", "result/XPath/expr/", "", NULL,
4239 0 },
4240 { "XPath document queries regression tests" ,
4241 xpathDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4242 0 },
4243#ifdef LIBXML_XPTR_ENABLED
4244 { "XPointer document queries regression tests" ,
4245 xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4246 0 },
4247#endif
4248 { "xml:id regression tests" ,
4249 xmlidDocTest, "./test/xmlid/*", "result/xmlid/", "", ".err",
4250 0 },
4251#endif
4252#endif
4253 { "URI parsing tests" ,
4254 uriParseTest, "./test/URI/*.uri", "result/URI/", "", NULL,
4255 0 },
4256 { "URI base composition tests" ,
4257 uriBaseTest, "./test/URI/*.data", "result/URI/", "", NULL,
4258 0 },
Daniel Veillard336a8e12005-08-07 10:46:19 +00004259 { "Path URI conversion tests" ,
4260 uriPathTest, NULL, NULL, NULL, NULL,
4261 0 },
William M. Brackca15a542005-07-06 20:41:33 +00004262#ifdef LIBXML_SCHEMAS_ENABLED
4263 { "Schemas regression tests" ,
4264 schemasTest, "./test/schemas/*_*.xsd", NULL, NULL, NULL,
4265 0 },
4266 { "Relax-NG regression tests" ,
4267 rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4268 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4269#ifdef LIBXML_READER_ENABLED
4270 { "Relax-NG streaming regression tests" ,
4271 rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4272 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4273#endif
4274#endif
4275#ifdef LIBXML_PATTERN_ENABLED
4276#ifdef LIBXML_READER_ENABLED
4277 { "Pattern regression tests" ,
4278 patternTest, "./test/pattern/*.pat", "result/pattern/", NULL, NULL,
4279 0 },
4280#endif
4281#endif
4282#ifdef LIBXML_C14N_ENABLED
4283 { "C14N with comments regression tests" ,
4284 c14nWithCommentTest, "./test/c14n/with-comments/*.xml", NULL, NULL, NULL,
4285 0 },
4286 { "C14N without comments regression tests" ,
4287 c14nWithoutCommentTest, "./test/c14n/without-comments/*.xml", NULL, NULL, NULL,
4288 0 },
4289 { "C14N exclusive without comments regression tests" ,
4290 c14nExcWithoutCommentTest, "./test/c14n/exc-without-comments/*.xml", NULL, NULL, NULL,
4291 0 },
Aleksey Sanin83868242009-07-09 10:26:22 +02004292 { "C14N 1.1 without comments regression tests" ,
4293 c14n11WithoutCommentTest, "./test/c14n/1-1-without-comments/*.xml", NULL, NULL, NULL,
4294 0 },
William M. Brackca15a542005-07-06 20:41:33 +00004295#endif
Daniel Veillardbca3ad22005-08-23 22:14:02 +00004296#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) && defined(LIBXML_SAX1_ENABLED)
William M. Brackca15a542005-07-06 20:41:33 +00004297 { "Catalog and Threads regression tests" ,
4298 threadsTest, NULL, NULL, NULL, NULL,
4299 0 },
4300#endif
4301 {NULL, NULL, NULL, NULL, NULL, NULL, 0}
4302};
4303
4304/************************************************************************
4305 * *
4306 * The main code driving the tests *
4307 * *
4308 ************************************************************************/
4309
4310static int
4311launchTests(testDescPtr tst) {
4312 int res = 0, err = 0;
4313 size_t i;
4314 char *result;
4315 char *error;
4316 int mem;
4317
4318 if (tst == NULL) return(-1);
4319 if (tst->in != NULL) {
4320 glob_t globbuf;
4321
4322 globbuf.gl_offs = 0;
4323 glob(tst->in, GLOB_DOOFFS, NULL, &globbuf);
4324 for (i = 0;i < globbuf.gl_pathc;i++) {
4325 if (!checkTestFile(globbuf.gl_pathv[i]))
4326 continue;
4327 if (tst->suffix != NULL) {
4328 result = resultFilename(globbuf.gl_pathv[i], tst->out,
4329 tst->suffix);
4330 if (result == NULL) {
4331 fprintf(stderr, "Out of memory !\n");
4332 fatalError();
4333 }
4334 } else {
4335 result = NULL;
4336 }
4337 if (tst->err != NULL) {
4338 error = resultFilename(globbuf.gl_pathv[i], tst->out,
4339 tst->err);
4340 if (error == NULL) {
4341 fprintf(stderr, "Out of memory !\n");
4342 fatalError();
4343 }
4344 } else {
4345 error = NULL;
4346 }
4347 if ((result) &&(!checkTestFile(result))) {
4348 fprintf(stderr, "Missing result file %s\n", result);
4349 } else if ((error) &&(!checkTestFile(error))) {
4350 fprintf(stderr, "Missing error file %s\n", error);
4351 } else {
4352 mem = xmlMemUsed();
4353 extraMemoryFromResolver = 0;
4354 testErrorsSize = 0;
4355 testErrors[0] = 0;
4356 res = tst->func(globbuf.gl_pathv[i], result, error,
Daniel Veillard8874b942005-08-25 13:19:21 +00004357 tst->options | XML_PARSE_COMPACT);
William M. Brackca15a542005-07-06 20:41:33 +00004358 xmlResetLastError();
4359 if (res != 0) {
4360 fprintf(stderr, "File %s generated an error\n",
4361 globbuf.gl_pathv[i]);
4362 nb_errors++;
4363 err++;
4364 }
4365 else if (xmlMemUsed() != mem) {
4366 if ((xmlMemUsed() != mem) &&
4367 (extraMemoryFromResolver == 0)) {
4368 fprintf(stderr, "File %s leaked %d bytes\n",
4369 globbuf.gl_pathv[i], xmlMemUsed() - mem);
4370 nb_leaks++;
4371 err++;
4372 }
4373 }
4374 testErrorsSize = 0;
4375 }
4376 if (result)
4377 free(result);
4378 if (error)
4379 free(error);
4380 }
4381 globfree(&globbuf);
4382 } else {
4383 testErrorsSize = 0;
4384 testErrors[0] = 0;
4385 extraMemoryFromResolver = 0;
4386 res = tst->func(NULL, NULL, NULL, tst->options);
4387 if (res != 0) {
4388 nb_errors++;
4389 err++;
4390 }
4391 }
4392 return(err);
4393}
4394
Daniel Veillarddb68b742005-07-30 13:18:24 +00004395static int verbose = 0;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004396static int tests_quiet = 0;
Daniel Veillarddb68b742005-07-30 13:18:24 +00004397
4398static int
4399runtest(int i) {
4400 int ret = 0, res;
4401 int old_errors, old_tests, old_leaks;
4402
4403 old_errors = nb_errors;
4404 old_tests = nb_tests;
4405 old_leaks = nb_leaks;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004406 if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
Daniel Veillarddb68b742005-07-30 13:18:24 +00004407 printf("## %s\n", testDescriptions[i].desc);
4408 res = launchTests(&testDescriptions[i]);
4409 if (res != 0)
4410 ret++;
4411 if (verbose) {
4412 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
4413 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
4414 else
4415 printf("Ran %d tests, %d errors, %d leaks\n",
4416 nb_tests - old_tests,
4417 nb_errors - old_errors,
4418 nb_leaks - old_leaks);
4419 }
4420 return(ret);
4421}
4422
William M. Brackca15a542005-07-06 20:41:33 +00004423int
4424main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
Daniel Veillarddb68b742005-07-30 13:18:24 +00004425 int i, a, ret = 0;
4426 int subset = 0;
William M. Brackca15a542005-07-06 20:41:33 +00004427
4428 initializeLibxml2();
4429
Daniel Veillarddb68b742005-07-30 13:18:24 +00004430 for (a = 1; a < argc;a++) {
4431 if (!strcmp(argv[a], "-v"))
4432 verbose = 1;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004433 else if (!strcmp(argv[a], "-quiet"))
4434 tests_quiet = 1;
Daniel Veillarddb68b742005-07-30 13:18:24 +00004435 else {
4436 for (i = 0; testDescriptions[i].func != NULL; i++) {
4437 if (strstr(testDescriptions[i].desc, argv[a])) {
4438 ret += runtest(i);
4439 subset++;
4440 }
4441 }
4442 }
4443 }
4444 if (subset == 0) {
4445 for (i = 0; testDescriptions[i].func != NULL; i++) {
4446 ret += runtest(i);
William M. Brackca15a542005-07-06 20:41:33 +00004447 }
4448 }
4449 if ((nb_errors == 0) && (nb_leaks == 0)) {
4450 ret = 0;
4451 printf("Total %d tests, no errors\n",
4452 nb_tests);
4453 } else {
4454 ret = 1;
4455 printf("Total %d tests, %d errors, %d leaks\n",
4456 nb_tests, nb_errors, nb_leaks);
4457 }
4458 xmlCleanupParser();
4459 xmlMemoryDump();
4460
4461 return(ret);
4462}
4463
4464#else /* ! LIBXML_OUTPUT_ENABLED */
4465int
4466main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
4467 fprintf(stderr, "runtest requires output to be enabled in libxml2\n");
4468 return(1);
4469}
4470#endif