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