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