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