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