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