blob: 18615773228b0cc85522d6cb8037f5598c92a8d4 [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);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800676 if (fd < 0) {
677 fprintf(stderr, "failed to open %s for writing", filename);
David Kilzer5c373822016-05-22 09:58:30 +0800678 return(-1);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800679 }
David Kilzer5c373822016-05-22 09:58:30 +0800680 res = write(fd, mem, size);
681 close(fd);
682 return(res != size);
683 }
684
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800685 if (stat(filename, &info) < 0) {
686 fprintf(stderr, "failed to stat %s\n", filename);
William M. Brackca15a542005-07-06 20:41:33 +0000687 return(-1);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800688 }
689 if (info.st_size != size) {
690 fprintf(stderr, "file %s is %ld bytes, result is %d bytes\n",
691 filename, info.st_size, size);
William M. Brackca15a542005-07-06 20:41:33 +0000692 return(-1);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800693 }
William M. Brackca15a542005-07-06 20:41:33 +0000694 fd = open(filename, RD_FLAGS);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800695 if (fd < 0) {
696 fprintf(stderr, "failed to open %s for reading", filename);
William M. Brackca15a542005-07-06 20:41:33 +0000697 return(-1);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800698 }
William M. Brackca15a542005-07-06 20:41:33 +0000699 while (idx < size) {
700 res = read(fd, bytes, 4096);
701 if (res <= 0)
702 break;
Daniel Veillardaa6de472008-08-25 14:53:31 +0000703 if (res + idx > size)
William M. Brackca15a542005-07-06 20:41:33 +0000704 break;
705 if (memcmp(bytes, &mem[idx], res) != 0) {
706 int ix;
707 for (ix=0; ix<res; ix++)
708 if (bytes[ix] != mem[idx+ix])
709 break;
710 fprintf(stderr,"Compare error at position %d\n", idx+ix);
711 close(fd);
712 return(1);
713 }
714 idx += res;
715 }
716 close(fd);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800717 if (idx != size) {
718 fprintf(stderr,"Compare error index %d, size %d\n", idx, size);
719 }
William M. Brackca15a542005-07-06 20:41:33 +0000720 return(idx != size);
721}
722
723static int loadMem(const char *filename, const char **mem, int *size) {
724 int fd, res;
725 struct stat info;
726 char *base;
727 int siz = 0;
Daniel Veillardaa6de472008-08-25 14:53:31 +0000728 if (stat(filename, &info) < 0)
William M. Brackca15a542005-07-06 20:41:33 +0000729 return(-1);
730 base = malloc(info.st_size + 1);
731 if (base == NULL)
732 return(-1);
733 if ((fd = open(filename, RD_FLAGS)) < 0) {
734 free(base);
735 return(-1);
736 }
737 while ((res = read(fd, &base[siz], info.st_size - siz)) > 0) {
738 siz += res;
739 }
740 close(fd);
741#if !defined(_WIN32)
742 if (siz != info.st_size) {
743 free(base);
744 return(-1);
745 }
746#endif
747 base[siz] = 0;
748 *mem = base;
749 *size = siz;
750 return(0);
751}
752
753static int unloadMem(const char *mem) {
754 free((char *)mem);
755 return(0);
756}
757
758/************************************************************************
759 * *
760 * Tests implementations *
761 * *
762 ************************************************************************/
763
764/************************************************************************
765 * *
766 * Parse to SAX based tests *
767 * *
768 ************************************************************************/
769
Daniel Veillard24505b02005-07-28 23:49:35 +0000770static FILE *SAXdebug = NULL;
William M. Brackca15a542005-07-06 20:41:33 +0000771
772/*
773 * empty SAX block
774 */
Daniel Veillard24505b02005-07-28 23:49:35 +0000775static xmlSAXHandler emptySAXHandlerStruct = {
William M. Brackca15a542005-07-06 20:41:33 +0000776 NULL, /* internalSubset */
777 NULL, /* isStandalone */
778 NULL, /* hasInternalSubset */
779 NULL, /* hasExternalSubset */
780 NULL, /* resolveEntity */
781 NULL, /* getEntity */
782 NULL, /* entityDecl */
783 NULL, /* notationDecl */
784 NULL, /* attributeDecl */
785 NULL, /* elementDecl */
786 NULL, /* unparsedEntityDecl */
787 NULL, /* setDocumentLocator */
788 NULL, /* startDocument */
789 NULL, /* endDocument */
790 NULL, /* startElement */
791 NULL, /* endElement */
792 NULL, /* reference */
793 NULL, /* characters */
794 NULL, /* ignorableWhitespace */
795 NULL, /* processingInstruction */
796 NULL, /* comment */
797 NULL, /* xmlParserWarning */
798 NULL, /* xmlParserError */
799 NULL, /* xmlParserError */
800 NULL, /* getParameterEntity */
801 NULL, /* cdataBlock; */
802 NULL, /* externalSubset; */
803 1,
804 NULL,
805 NULL, /* startElementNs */
806 NULL, /* endElementNs */
807 NULL /* xmlStructuredErrorFunc */
808};
809
810static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct;
Daniel Veillard24505b02005-07-28 23:49:35 +0000811static int callbacks = 0;
812static int quiet = 0;
William M. Brackca15a542005-07-06 20:41:33 +0000813
814/**
815 * isStandaloneDebug:
816 * @ctxt: An XML parser context
817 *
818 * Is this document tagged standalone ?
819 *
820 * Returns 1 if true
821 */
822static int
823isStandaloneDebug(void *ctx ATTRIBUTE_UNUSED)
824{
825 callbacks++;
826 if (quiet)
827 return(0);
828 fprintf(SAXdebug, "SAX.isStandalone()\n");
829 return(0);
830}
831
832/**
833 * hasInternalSubsetDebug:
834 * @ctxt: An XML parser context
835 *
836 * Does this document has an internal subset
837 *
838 * Returns 1 if true
839 */
840static int
841hasInternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
842{
843 callbacks++;
844 if (quiet)
845 return(0);
846 fprintf(SAXdebug, "SAX.hasInternalSubset()\n");
847 return(0);
848}
849
850/**
851 * hasExternalSubsetDebug:
852 * @ctxt: An XML parser context
853 *
854 * Does this document has an external subset
855 *
856 * Returns 1 if true
857 */
858static int
859hasExternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
860{
861 callbacks++;
862 if (quiet)
863 return(0);
864 fprintf(SAXdebug, "SAX.hasExternalSubset()\n");
865 return(0);
866}
867
868/**
869 * internalSubsetDebug:
870 * @ctxt: An XML parser context
871 *
872 * Does this document has an internal subset
873 */
874static void
875internalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
876 const xmlChar *ExternalID, const xmlChar *SystemID)
877{
878 callbacks++;
879 if (quiet)
880 return;
881 fprintf(SAXdebug, "SAX.internalSubset(%s,", name);
882 if (ExternalID == NULL)
883 fprintf(SAXdebug, " ,");
884 else
885 fprintf(SAXdebug, " %s,", ExternalID);
886 if (SystemID == NULL)
887 fprintf(SAXdebug, " )\n");
888 else
889 fprintf(SAXdebug, " %s)\n", SystemID);
890}
891
892/**
893 * externalSubsetDebug:
894 * @ctxt: An XML parser context
895 *
896 * Does this document has an external subset
897 */
898static void
899externalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
900 const xmlChar *ExternalID, const xmlChar *SystemID)
901{
902 callbacks++;
903 if (quiet)
904 return;
905 fprintf(SAXdebug, "SAX.externalSubset(%s,", name);
906 if (ExternalID == NULL)
907 fprintf(SAXdebug, " ,");
908 else
909 fprintf(SAXdebug, " %s,", ExternalID);
910 if (SystemID == NULL)
911 fprintf(SAXdebug, " )\n");
912 else
913 fprintf(SAXdebug, " %s)\n", SystemID);
914}
915
916/**
917 * resolveEntityDebug:
918 * @ctxt: An XML parser context
919 * @publicId: The public ID of the entity
920 * @systemId: The system ID of the entity
921 *
922 * Special entity resolver, better left to the parser, it has
923 * more context than the application layer.
924 * The default behaviour is to NOT resolve the entities, in that case
925 * the ENTITY_REF nodes are built in the structure (and the parameter
926 * values).
927 *
928 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
929 */
930static xmlParserInputPtr
931resolveEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *publicId, const xmlChar *systemId)
932{
933 callbacks++;
934 if (quiet)
935 return(NULL);
936 /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
937
Daniel Veillardaa6de472008-08-25 14:53:31 +0000938
William M. Brackca15a542005-07-06 20:41:33 +0000939 fprintf(SAXdebug, "SAX.resolveEntity(");
940 if (publicId != NULL)
941 fprintf(SAXdebug, "%s", (char *)publicId);
942 else
943 fprintf(SAXdebug, " ");
944 if (systemId != NULL)
945 fprintf(SAXdebug, ", %s)\n", (char *)systemId);
946 else
947 fprintf(SAXdebug, ", )\n");
948/*********
949 if (systemId != NULL) {
950 return(xmlNewInputFromFile(ctxt, (char *) systemId));
951 }
952 *********/
953 return(NULL);
954}
955
956/**
957 * getEntityDebug:
958 * @ctxt: An XML parser context
959 * @name: The entity name
960 *
961 * Get an entity by name
962 *
963 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
964 */
965static xmlEntityPtr
966getEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
967{
968 callbacks++;
969 if (quiet)
970 return(NULL);
971 fprintf(SAXdebug, "SAX.getEntity(%s)\n", name);
972 return(NULL);
973}
974
975/**
976 * getParameterEntityDebug:
977 * @ctxt: An XML parser context
978 * @name: The entity name
979 *
980 * Get a parameter entity by name
981 *
982 * Returns the xmlParserInputPtr
983 */
984static xmlEntityPtr
985getParameterEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
986{
987 callbacks++;
988 if (quiet)
989 return(NULL);
990 fprintf(SAXdebug, "SAX.getParameterEntity(%s)\n", name);
991 return(NULL);
992}
993
994
995/**
996 * entityDeclDebug:
997 * @ctxt: An XML parser context
Daniel Veillardaa6de472008-08-25 14:53:31 +0000998 * @name: the entity name
999 * @type: the entity type
William M. Brackca15a542005-07-06 20:41:33 +00001000 * @publicId: The public ID of the entity
1001 * @systemId: The system ID of the entity
1002 * @content: the entity value (without processing).
1003 *
1004 * An entity definition has been parsed
1005 */
1006static void
1007entityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
1008 const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
1009{
1010const xmlChar *nullstr = BAD_CAST "(null)";
1011 /* not all libraries handle printing null pointers nicely */
1012 if (publicId == NULL)
1013 publicId = nullstr;
1014 if (systemId == NULL)
1015 systemId = nullstr;
1016 if (content == NULL)
1017 content = (xmlChar *)nullstr;
1018 callbacks++;
1019 if (quiet)
1020 return;
1021 fprintf(SAXdebug, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
1022 name, type, publicId, systemId, content);
1023}
1024
1025/**
1026 * attributeDeclDebug:
1027 * @ctxt: An XML parser context
Daniel Veillardaa6de472008-08-25 14:53:31 +00001028 * @name: the attribute name
1029 * @type: the attribute type
William M. Brackca15a542005-07-06 20:41:33 +00001030 *
1031 * An attribute definition has been parsed
1032 */
1033static void
1034attributeDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar * elem,
1035 const xmlChar * name, int type, int def,
1036 const xmlChar * defaultValue, xmlEnumerationPtr tree)
1037{
1038 callbacks++;
1039 if (quiet)
1040 return;
1041 if (defaultValue == NULL)
1042 fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, NULL, ...)\n",
1043 elem, name, type, def);
1044 else
1045 fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
1046 elem, name, type, def, defaultValue);
1047 xmlFreeEnumeration(tree);
1048}
1049
1050/**
1051 * elementDeclDebug:
1052 * @ctxt: An XML parser context
Daniel Veillardaa6de472008-08-25 14:53:31 +00001053 * @name: the element name
1054 * @type: the element type
William M. Brackca15a542005-07-06 20:41:33 +00001055 * @content: the element value (without processing).
1056 *
1057 * An element definition has been parsed
1058 */
1059static void
1060elementDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
1061 xmlElementContentPtr content ATTRIBUTE_UNUSED)
1062{
1063 callbacks++;
1064 if (quiet)
1065 return;
1066 fprintf(SAXdebug, "SAX.elementDecl(%s, %d, ...)\n",
1067 name, type);
1068}
1069
1070/**
1071 * notationDeclDebug:
1072 * @ctxt: An XML parser context
1073 * @name: The name of the notation
1074 * @publicId: The public ID of the entity
1075 * @systemId: The system ID of the entity
1076 *
1077 * What to do when a notation declaration has been parsed.
1078 */
1079static void
1080notationDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
1081 const xmlChar *publicId, const xmlChar *systemId)
1082{
1083 callbacks++;
1084 if (quiet)
1085 return;
1086 fprintf(SAXdebug, "SAX.notationDecl(%s, %s, %s)\n",
1087 (char *) name, (char *) publicId, (char *) systemId);
1088}
1089
1090/**
1091 * unparsedEntityDeclDebug:
1092 * @ctxt: An XML parser context
1093 * @name: The name of the entity
1094 * @publicId: The public ID of the entity
1095 * @systemId: The system ID of the entity
1096 * @notationName: the name of the notation
1097 *
1098 * What to do when an unparsed entity declaration is parsed
1099 */
1100static void
1101unparsedEntityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
1102 const xmlChar *publicId, const xmlChar *systemId,
1103 const xmlChar *notationName)
1104{
1105const xmlChar *nullstr = BAD_CAST "(null)";
1106
1107 if (publicId == NULL)
1108 publicId = nullstr;
1109 if (systemId == NULL)
1110 systemId = nullstr;
1111 if (notationName == NULL)
1112 notationName = nullstr;
1113 callbacks++;
1114 if (quiet)
1115 return;
1116 fprintf(SAXdebug, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
1117 (char *) name, (char *) publicId, (char *) systemId,
1118 (char *) notationName);
1119}
1120
1121/**
1122 * setDocumentLocatorDebug:
1123 * @ctxt: An XML parser context
1124 * @loc: A SAX Locator
1125 *
1126 * Receive the document locator at startup, actually xmlDefaultSAXLocator
1127 * Everything is available on the context, so this is useless in our case.
1128 */
1129static void
1130setDocumentLocatorDebug(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
1131{
1132 callbacks++;
1133 if (quiet)
1134 return;
1135 fprintf(SAXdebug, "SAX.setDocumentLocator()\n");
1136}
1137
1138/**
1139 * startDocumentDebug:
1140 * @ctxt: An XML parser context
1141 *
1142 * called when the document start being processed.
1143 */
1144static void
1145startDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
1146{
1147 callbacks++;
1148 if (quiet)
1149 return;
1150 fprintf(SAXdebug, "SAX.startDocument()\n");
1151}
1152
1153/**
1154 * endDocumentDebug:
1155 * @ctxt: An XML parser context
1156 *
1157 * called when the document end has been detected.
1158 */
1159static void
1160endDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
1161{
1162 callbacks++;
1163 if (quiet)
1164 return;
1165 fprintf(SAXdebug, "SAX.endDocument()\n");
1166}
1167
1168/**
1169 * startElementDebug:
1170 * @ctxt: An XML parser context
1171 * @name: The element name
1172 *
1173 * called when an opening tag has been processed.
1174 */
1175static void
1176startElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
1177{
1178 int i;
1179
1180 callbacks++;
1181 if (quiet)
1182 return;
1183 fprintf(SAXdebug, "SAX.startElement(%s", (char *) name);
1184 if (atts != NULL) {
1185 for (i = 0;(atts[i] != NULL);i++) {
1186 fprintf(SAXdebug, ", %s='", atts[i++]);
1187 if (atts[i] != NULL)
1188 fprintf(SAXdebug, "%s'", atts[i]);
1189 }
1190 }
1191 fprintf(SAXdebug, ")\n");
1192}
1193
1194/**
1195 * endElementDebug:
1196 * @ctxt: An XML parser context
1197 * @name: The element name
1198 *
1199 * called when the end of an element has been detected.
1200 */
1201static void
1202endElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
1203{
1204 callbacks++;
1205 if (quiet)
1206 return;
1207 fprintf(SAXdebug, "SAX.endElement(%s)\n", (char *) name);
1208}
1209
1210/**
1211 * charactersDebug:
1212 * @ctxt: An XML parser context
1213 * @ch: a xmlChar string
1214 * @len: the number of xmlChar
1215 *
1216 * receiving some chars from the parser.
1217 * Question: how much at a time ???
1218 */
1219static void
1220charactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1221{
1222 char output[40];
1223 int i;
1224
1225 callbacks++;
1226 if (quiet)
1227 return;
1228 for (i = 0;(i<len) && (i < 30);i++)
1229 output[i] = ch[i];
1230 output[i] = 0;
1231
1232 fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len);
1233}
1234
1235/**
1236 * referenceDebug:
1237 * @ctxt: An XML parser context
1238 * @name: The entity name
1239 *
Daniel Veillardaa6de472008-08-25 14:53:31 +00001240 * called when an entity reference is detected.
William M. Brackca15a542005-07-06 20:41:33 +00001241 */
1242static void
1243referenceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
1244{
1245 callbacks++;
1246 if (quiet)
1247 return;
1248 fprintf(SAXdebug, "SAX.reference(%s)\n", name);
1249}
1250
1251/**
1252 * ignorableWhitespaceDebug:
1253 * @ctxt: An XML parser context
1254 * @ch: a xmlChar string
1255 * @start: the first char in the string
1256 * @len: the number of xmlChar
1257 *
1258 * receiving some ignorable whitespaces from the parser.
1259 * Question: how much at a time ???
1260 */
1261static void
1262ignorableWhitespaceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1263{
1264 char output[40];
1265 int i;
1266
1267 callbacks++;
1268 if (quiet)
1269 return;
1270 for (i = 0;(i<len) && (i < 30);i++)
1271 output[i] = ch[i];
1272 output[i] = 0;
1273 fprintf(SAXdebug, "SAX.ignorableWhitespace(%s, %d)\n", output, len);
1274}
1275
1276/**
1277 * processingInstructionDebug:
1278 * @ctxt: An XML parser context
1279 * @target: the target name
1280 * @data: the PI data's
1281 * @len: the number of xmlChar
1282 *
1283 * A processing instruction has been parsed.
1284 */
1285static void
1286processingInstructionDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *target,
1287 const xmlChar *data)
1288{
1289 callbacks++;
1290 if (quiet)
1291 return;
1292 if (data != NULL)
1293 fprintf(SAXdebug, "SAX.processingInstruction(%s, %s)\n",
1294 (char *) target, (char *) data);
1295 else
1296 fprintf(SAXdebug, "SAX.processingInstruction(%s, NULL)\n",
1297 (char *) target);
1298}
1299
1300/**
1301 * cdataBlockDebug:
1302 * @ctx: the user data (XML parser context)
1303 * @value: The pcdata content
1304 * @len: the block length
1305 *
1306 * called when a pcdata block has been parsed
1307 */
1308static void
1309cdataBlockDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value, int len)
1310{
1311 callbacks++;
1312 if (quiet)
1313 return;
1314 fprintf(SAXdebug, "SAX.pcdata(%.20s, %d)\n",
1315 (char *) value, len);
1316}
1317
1318/**
1319 * commentDebug:
1320 * @ctxt: An XML parser context
1321 * @value: the comment content
1322 *
1323 * A comment has been parsed.
1324 */
1325static void
1326commentDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value)
1327{
1328 callbacks++;
1329 if (quiet)
1330 return;
1331 fprintf(SAXdebug, "SAX.comment(%s)\n", value);
1332}
1333
1334/**
1335 * warningDebug:
1336 * @ctxt: An XML parser context
1337 * @msg: the message to display/transmit
1338 * @...: extra parameters for the message display
1339 *
1340 * Display and format a warning messages, gives file, line, position and
1341 * extra parameters.
1342 */
Daniel Veillardffa3c742005-07-21 13:24:09 +00001343static void XMLCDECL
William M. Brackca15a542005-07-06 20:41:33 +00001344warningDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1345{
1346 va_list args;
1347
1348 callbacks++;
1349 if (quiet)
1350 return;
1351 va_start(args, msg);
1352 fprintf(SAXdebug, "SAX.warning: ");
1353 vfprintf(SAXdebug, msg, args);
1354 va_end(args);
1355}
1356
1357/**
1358 * errorDebug:
1359 * @ctxt: An XML parser context
1360 * @msg: the message to display/transmit
1361 * @...: extra parameters for the message display
1362 *
1363 * Display and format a error messages, gives file, line, position and
1364 * extra parameters.
1365 */
Daniel Veillardffa3c742005-07-21 13:24:09 +00001366static void XMLCDECL
William M. Brackca15a542005-07-06 20:41:33 +00001367errorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1368{
1369 va_list args;
1370
1371 callbacks++;
1372 if (quiet)
1373 return;
1374 va_start(args, msg);
1375 fprintf(SAXdebug, "SAX.error: ");
1376 vfprintf(SAXdebug, msg, args);
1377 va_end(args);
1378}
1379
1380/**
1381 * fatalErrorDebug:
1382 * @ctxt: An XML parser context
1383 * @msg: the message to display/transmit
1384 * @...: extra parameters for the message display
1385 *
1386 * Display and format a fatalError messages, gives file, line, position and
1387 * extra parameters.
1388 */
Daniel Veillardffa3c742005-07-21 13:24:09 +00001389static void XMLCDECL
William M. Brackca15a542005-07-06 20:41:33 +00001390fatalErrorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1391{
1392 va_list args;
1393
1394 callbacks++;
1395 if (quiet)
1396 return;
1397 va_start(args, msg);
1398 fprintf(SAXdebug, "SAX.fatalError: ");
1399 vfprintf(SAXdebug, msg, args);
1400 va_end(args);
1401}
1402
Daniel Veillard24505b02005-07-28 23:49:35 +00001403static xmlSAXHandler debugSAXHandlerStruct = {
William M. Brackca15a542005-07-06 20:41:33 +00001404 internalSubsetDebug,
1405 isStandaloneDebug,
1406 hasInternalSubsetDebug,
1407 hasExternalSubsetDebug,
1408 resolveEntityDebug,
1409 getEntityDebug,
1410 entityDeclDebug,
1411 notationDeclDebug,
1412 attributeDeclDebug,
1413 elementDeclDebug,
1414 unparsedEntityDeclDebug,
1415 setDocumentLocatorDebug,
1416 startDocumentDebug,
1417 endDocumentDebug,
1418 startElementDebug,
1419 endElementDebug,
1420 referenceDebug,
1421 charactersDebug,
1422 ignorableWhitespaceDebug,
1423 processingInstructionDebug,
1424 commentDebug,
1425 warningDebug,
1426 errorDebug,
1427 fatalErrorDebug,
1428 getParameterEntityDebug,
1429 cdataBlockDebug,
1430 externalSubsetDebug,
1431 1,
1432 NULL,
1433 NULL,
1434 NULL,
1435 NULL
1436};
1437
Daniel Veillard24505b02005-07-28 23:49:35 +00001438static xmlSAXHandlerPtr debugSAXHandler = &debugSAXHandlerStruct;
William M. Brackca15a542005-07-06 20:41:33 +00001439
1440/*
1441 * SAX2 specific callbacks
1442 */
1443/**
1444 * startElementNsDebug:
1445 * @ctxt: An XML parser context
1446 * @name: The element name
1447 *
1448 * called when an opening tag has been processed.
1449 */
1450static void
1451startElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
1452 const xmlChar *localname,
1453 const xmlChar *prefix,
1454 const xmlChar *URI,
1455 int nb_namespaces,
1456 const xmlChar **namespaces,
1457 int nb_attributes,
1458 int nb_defaulted,
1459 const xmlChar **attributes)
1460{
1461 int i;
1462
1463 callbacks++;
1464 if (quiet)
1465 return;
1466 fprintf(SAXdebug, "SAX.startElementNs(%s", (char *) localname);
1467 if (prefix == NULL)
1468 fprintf(SAXdebug, ", NULL");
1469 else
1470 fprintf(SAXdebug, ", %s", (char *) prefix);
1471 if (URI == NULL)
1472 fprintf(SAXdebug, ", NULL");
1473 else
1474 fprintf(SAXdebug, ", '%s'", (char *) URI);
1475 fprintf(SAXdebug, ", %d", nb_namespaces);
Daniel Veillardaa6de472008-08-25 14:53:31 +00001476
William M. Brackca15a542005-07-06 20:41:33 +00001477 if (namespaces != NULL) {
1478 for (i = 0;i < nb_namespaces * 2;i++) {
1479 fprintf(SAXdebug, ", xmlns");
1480 if (namespaces[i] != NULL)
1481 fprintf(SAXdebug, ":%s", namespaces[i]);
1482 i++;
1483 fprintf(SAXdebug, "='%s'", namespaces[i]);
1484 }
1485 }
1486 fprintf(SAXdebug, ", %d, %d", nb_attributes, nb_defaulted);
1487 if (attributes != NULL) {
1488 for (i = 0;i < nb_attributes * 5;i += 5) {
1489 if (attributes[i + 1] != NULL)
1490 fprintf(SAXdebug, ", %s:%s='", attributes[i + 1], attributes[i]);
1491 else
1492 fprintf(SAXdebug, ", %s='", attributes[i]);
1493 fprintf(SAXdebug, "%.4s...', %d", attributes[i + 3],
1494 (int)(attributes[i + 4] - attributes[i + 3]));
1495 }
1496 }
1497 fprintf(SAXdebug, ")\n");
1498}
1499
1500/**
1501 * endElementDebug:
1502 * @ctxt: An XML parser context
1503 * @name: The element name
1504 *
1505 * called when the end of an element has been detected.
1506 */
1507static void
1508endElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
1509 const xmlChar *localname,
1510 const xmlChar *prefix,
1511 const xmlChar *URI)
1512{
1513 callbacks++;
1514 if (quiet)
1515 return;
1516 fprintf(SAXdebug, "SAX.endElementNs(%s", (char *) localname);
1517 if (prefix == NULL)
1518 fprintf(SAXdebug, ", NULL");
1519 else
1520 fprintf(SAXdebug, ", %s", (char *) prefix);
1521 if (URI == NULL)
1522 fprintf(SAXdebug, ", NULL)\n");
1523 else
1524 fprintf(SAXdebug, ", '%s')\n", (char *) URI);
1525}
1526
Daniel Veillard24505b02005-07-28 23:49:35 +00001527static xmlSAXHandler debugSAX2HandlerStruct = {
William M. Brackca15a542005-07-06 20:41:33 +00001528 internalSubsetDebug,
1529 isStandaloneDebug,
1530 hasInternalSubsetDebug,
1531 hasExternalSubsetDebug,
1532 resolveEntityDebug,
1533 getEntityDebug,
1534 entityDeclDebug,
1535 notationDeclDebug,
1536 attributeDeclDebug,
1537 elementDeclDebug,
1538 unparsedEntityDeclDebug,
1539 setDocumentLocatorDebug,
1540 startDocumentDebug,
1541 endDocumentDebug,
1542 NULL,
1543 NULL,
1544 referenceDebug,
1545 charactersDebug,
1546 ignorableWhitespaceDebug,
1547 processingInstructionDebug,
1548 commentDebug,
1549 warningDebug,
1550 errorDebug,
1551 fatalErrorDebug,
1552 getParameterEntityDebug,
1553 cdataBlockDebug,
1554 externalSubsetDebug,
1555 XML_SAX2_MAGIC,
1556 NULL,
1557 startElementNsDebug,
1558 endElementNsDebug,
1559 NULL
1560};
1561
Daniel Veillard24505b02005-07-28 23:49:35 +00001562static xmlSAXHandlerPtr debugSAX2Handler = &debugSAX2HandlerStruct;
William M. Brackca15a542005-07-06 20:41:33 +00001563
1564#ifdef LIBXML_HTML_ENABLED
1565/**
1566 * htmlstartElementDebug:
1567 * @ctxt: An XML parser context
1568 * @name: The element name
1569 *
1570 * called when an opening tag has been processed.
1571 */
1572static void
1573htmlstartElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
1574{
1575 int i;
1576
1577 fprintf(SAXdebug, "SAX.startElement(%s", (char *) name);
1578 if (atts != NULL) {
1579 for (i = 0;(atts[i] != NULL);i++) {
1580 fprintf(SAXdebug, ", %s", atts[i++]);
1581 if (atts[i] != NULL) {
1582 unsigned char output[40];
1583 const unsigned char *att = atts[i];
1584 int outlen, attlen;
1585 fprintf(SAXdebug, "='");
1586 while ((attlen = strlen((char*)att)) > 0) {
1587 outlen = sizeof output - 1;
1588 htmlEncodeEntities(output, &outlen, att, &attlen, '\'');
1589 output[outlen] = 0;
1590 fprintf(SAXdebug, "%s", (char *) output);
1591 att += attlen;
1592 }
1593 fprintf(SAXdebug, "'");
1594 }
1595 }
1596 }
1597 fprintf(SAXdebug, ")\n");
1598}
1599
1600/**
1601 * htmlcharactersDebug:
1602 * @ctxt: An XML parser context
1603 * @ch: a xmlChar string
1604 * @len: the number of xmlChar
1605 *
1606 * receiving some chars from the parser.
1607 * Question: how much at a time ???
1608 */
1609static void
1610htmlcharactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1611{
1612 unsigned char output[40];
1613 int inlen = len, outlen = 30;
1614
1615 htmlEncodeEntities(output, &outlen, ch, &inlen, 0);
1616 output[outlen] = 0;
1617
1618 fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len);
1619}
1620
1621/**
1622 * htmlcdataDebug:
1623 * @ctxt: An XML parser context
1624 * @ch: a xmlChar string
1625 * @len: the number of xmlChar
1626 *
1627 * receiving some cdata chars from the parser.
1628 * Question: how much at a time ???
1629 */
1630static void
1631htmlcdataDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1632{
1633 unsigned char output[40];
1634 int inlen = len, outlen = 30;
1635
1636 htmlEncodeEntities(output, &outlen, ch, &inlen, 0);
1637 output[outlen] = 0;
1638
1639 fprintf(SAXdebug, "SAX.cdata(%s, %d)\n", output, len);
1640}
1641
Daniel Veillard24505b02005-07-28 23:49:35 +00001642static xmlSAXHandler debugHTMLSAXHandlerStruct = {
William M. Brackca15a542005-07-06 20:41:33 +00001643 internalSubsetDebug,
1644 isStandaloneDebug,
1645 hasInternalSubsetDebug,
1646 hasExternalSubsetDebug,
1647 resolveEntityDebug,
1648 getEntityDebug,
1649 entityDeclDebug,
1650 notationDeclDebug,
1651 attributeDeclDebug,
1652 elementDeclDebug,
1653 unparsedEntityDeclDebug,
1654 setDocumentLocatorDebug,
1655 startDocumentDebug,
1656 endDocumentDebug,
1657 htmlstartElementDebug,
1658 endElementDebug,
1659 referenceDebug,
1660 htmlcharactersDebug,
1661 ignorableWhitespaceDebug,
1662 processingInstructionDebug,
1663 commentDebug,
1664 warningDebug,
1665 errorDebug,
1666 fatalErrorDebug,
1667 getParameterEntityDebug,
1668 htmlcdataDebug,
1669 externalSubsetDebug,
1670 1,
1671 NULL,
1672 NULL,
1673 NULL,
1674 NULL
1675};
1676
Daniel Veillard24505b02005-07-28 23:49:35 +00001677static xmlSAXHandlerPtr debugHTMLSAXHandler = &debugHTMLSAXHandlerStruct;
William M. Brackca15a542005-07-06 20:41:33 +00001678#endif /* LIBXML_HTML_ENABLED */
1679
1680#ifdef LIBXML_SAX1_ENABLED
1681/**
1682 * saxParseTest:
1683 * @filename: the file to parse
1684 * @result: the file with expected result
1685 * @err: the file with error messages
1686 *
1687 * Parse a file using the SAX API and check for errors.
1688 *
1689 * Returns 0 in case of success, an error code otherwise
1690 */
1691static int
1692saxParseTest(const char *filename, const char *result,
1693 const char *err ATTRIBUTE_UNUSED,
1694 int options) {
1695 int ret;
1696 char *temp;
1697
1698 nb_tests++;
1699 temp = resultFilename(filename, "", ".res");
1700 if (temp == NULL) {
1701 fprintf(stderr, "out of memory\n");
1702 fatalError();
1703 }
1704 SAXdebug = fopen(temp, "wb");
1705 if (SAXdebug == NULL) {
1706 fprintf(stderr, "Failed to write to %s\n", temp);
1707 free(temp);
1708 return(-1);
1709 }
1710
1711 /* for SAX we really want the callbacks though the context handlers */
1712 xmlSetStructuredErrorFunc(NULL, NULL);
1713 xmlSetGenericErrorFunc(NULL, testErrorHandler);
1714
1715#ifdef LIBXML_HTML_ENABLED
1716 if (options & XML_PARSE_HTML) {
1717 htmlSAXParseFile(filename, NULL, emptySAXHandler, NULL);
1718 ret = 0;
1719 } else
1720#endif
1721 ret = xmlSAXUserParseFile(emptySAXHandler, NULL, filename);
1722 if (ret == XML_WAR_UNDECLARED_ENTITY) {
1723 fprintf(SAXdebug, "xmlSAXUserParseFile returned error %d\n", ret);
1724 ret = 0;
1725 }
1726 if (ret != 0) {
1727 fprintf(stderr, "Failed to parse %s\n", filename);
Philip Withnall5777ae72014-06-20 21:15:16 +01001728 ret = 1;
1729 goto done;
William M. Brackca15a542005-07-06 20:41:33 +00001730 }
1731#ifdef LIBXML_HTML_ENABLED
1732 if (options & XML_PARSE_HTML) {
1733 htmlSAXParseFile(filename, NULL, debugHTMLSAXHandler, NULL);
1734 ret = 0;
1735 } else
1736#endif
1737 if (options & XML_PARSE_SAX1) {
1738 ret = xmlSAXUserParseFile(debugSAXHandler, NULL, filename);
1739 } else {
1740 ret = xmlSAXUserParseFile(debugSAX2Handler, NULL, filename);
1741 }
1742 if (ret == XML_WAR_UNDECLARED_ENTITY) {
1743 fprintf(SAXdebug, "xmlSAXUserParseFile returned error %d\n", ret);
1744 ret = 0;
1745 }
1746 fclose(SAXdebug);
1747 if (compareFiles(temp, result)) {
1748 fprintf(stderr, "Got a difference for %s\n", filename);
1749 ret = 1;
Daniel Veillard13cee4e2009-09-05 14:52:55 +02001750 }
Philip Withnall5777ae72014-06-20 21:15:16 +01001751
1752done:
Daniel Veillard13cee4e2009-09-05 14:52:55 +02001753 if (temp != NULL) {
1754 unlink(temp);
1755 free(temp);
1756 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00001757
William M. Brackca15a542005-07-06 20:41:33 +00001758 /* switch back to structured error handling */
1759 xmlSetGenericErrorFunc(NULL, NULL);
1760 xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
1761
1762 return(ret);
1763}
1764#endif
1765
1766/************************************************************************
1767 * *
1768 * Parse to tree based tests *
1769 * *
1770 ************************************************************************/
1771/**
1772 * oldParseTest:
1773 * @filename: the file to parse
1774 * @result: the file with expected result
1775 * @err: the file with error messages: unused
1776 *
1777 * Parse a file using the old xmlParseFile API, then serialize back
1778 * reparse the result and serialize again, then check for deviation
1779 * in serialization.
1780 *
1781 * Returns 0 in case of success, an error code otherwise
1782 */
1783static int
1784oldParseTest(const char *filename, const char *result,
1785 const char *err ATTRIBUTE_UNUSED,
1786 int options ATTRIBUTE_UNUSED) {
1787 xmlDocPtr doc;
1788 char *temp;
1789 int res = 0;
1790
1791 nb_tests++;
1792 /*
1793 * base of the test, parse with the old API
1794 */
1795#ifdef LIBXML_SAX1_ENABLED
1796 doc = xmlParseFile(filename);
1797#else
1798 doc = xmlReadFile(filename, NULL, 0);
1799#endif
1800 if (doc == NULL)
1801 return(1);
1802 temp = resultFilename(filename, "", ".res");
1803 if (temp == NULL) {
1804 fprintf(stderr, "out of memory\n");
1805 fatalError();
1806 }
1807 xmlSaveFile(temp, doc);
1808 if (compareFiles(temp, result)) {
1809 res = 1;
1810 }
1811 xmlFreeDoc(doc);
1812
1813 /*
1814 * Parse the saved result to make sure the round trip is okay
1815 */
1816#ifdef LIBXML_SAX1_ENABLED
1817 doc = xmlParseFile(temp);
1818#else
1819 doc = xmlReadFile(temp, NULL, 0);
1820#endif
1821 if (doc == NULL)
1822 return(1);
1823 xmlSaveFile(temp, doc);
1824 if (compareFiles(temp, result)) {
1825 res = 1;
1826 }
1827 xmlFreeDoc(doc);
1828
Daniel Veillard13cee4e2009-09-05 14:52:55 +02001829 if (temp != NULL) {
1830 unlink(temp);
1831 free(temp);
1832 }
William M. Brackca15a542005-07-06 20:41:33 +00001833 return(res);
1834}
1835
1836#ifdef LIBXML_PUSH_ENABLED
1837/**
1838 * pushParseTest:
1839 * @filename: the file to parse
1840 * @result: the file with expected result
1841 * @err: the file with error messages: unused
1842 *
1843 * Parse a file using the Push API, then serialize back
1844 * to check for content.
1845 *
1846 * Returns 0 in case of success, an error code otherwise
1847 */
1848static int
1849pushParseTest(const char *filename, const char *result,
1850 const char *err ATTRIBUTE_UNUSED,
1851 int options) {
1852 xmlParserCtxtPtr ctxt;
1853 xmlDocPtr doc;
1854 const char *base;
1855 int size, res;
1856 int cur = 0;
1857
1858 nb_tests++;
1859 /*
1860 * load the document in memory and work from there.
1861 */
1862 if (loadMem(filename, &base, &size) != 0) {
1863 fprintf(stderr, "Failed to load %s\n", filename);
1864 return(-1);
1865 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00001866
William M. Brackca15a542005-07-06 20:41:33 +00001867#ifdef LIBXML_HTML_ENABLED
1868 if (options & XML_PARSE_HTML)
1869 ctxt = htmlCreatePushParserCtxt(NULL, NULL, base + cur, 4, filename,
1870 XML_CHAR_ENCODING_NONE);
1871 else
1872#endif
1873 ctxt = xmlCreatePushParserCtxt(NULL, NULL, base + cur, 4, filename);
1874 xmlCtxtUseOptions(ctxt, options);
1875 cur += 4;
Pranjal Jumdea820dbe2016-03-01 11:34:04 -08001876 do {
William M. Brackca15a542005-07-06 20:41:33 +00001877 if (cur + 1024 >= size) {
1878#ifdef LIBXML_HTML_ENABLED
1879 if (options & XML_PARSE_HTML)
1880 htmlParseChunk(ctxt, base + cur, size - cur, 1);
1881 else
1882#endif
1883 xmlParseChunk(ctxt, base + cur, size - cur, 1);
1884 break;
1885 } else {
1886#ifdef LIBXML_HTML_ENABLED
1887 if (options & XML_PARSE_HTML)
1888 htmlParseChunk(ctxt, base + cur, 1024, 0);
1889 else
1890#endif
1891 xmlParseChunk(ctxt, base + cur, 1024, 0);
1892 cur += 1024;
1893 }
Pranjal Jumdea820dbe2016-03-01 11:34:04 -08001894 } while (cur < size);
William M. Brackca15a542005-07-06 20:41:33 +00001895 doc = ctxt->myDoc;
1896#ifdef LIBXML_HTML_ENABLED
1897 if (options & XML_PARSE_HTML)
1898 res = 1;
1899 else
1900#endif
1901 res = ctxt->wellFormed;
1902 xmlFreeParserCtxt(ctxt);
1903 free((char *)base);
1904 if (!res) {
1905 xmlFreeDoc(doc);
1906 fprintf(stderr, "Failed to parse %s\n", filename);
1907 return(-1);
1908 }
1909#ifdef LIBXML_HTML_ENABLED
1910 if (options & XML_PARSE_HTML)
1911 htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1912 else
1913#endif
1914 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1915 xmlFreeDoc(doc);
1916 res = compareFileMem(result, base, size);
1917 if ((base == NULL) || (res != 0)) {
1918 if (base != NULL)
1919 xmlFree((char *)base);
Daniel Veillard9f2416c2016-05-22 11:14:45 +08001920 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00001921 return(-1);
1922 }
1923 xmlFree((char *)base);
1924 if (err != NULL) {
1925 res = compareFileMem(err, testErrors, testErrorsSize);
1926 if (res != 0) {
1927 fprintf(stderr, "Error for %s failed\n", filename);
1928 return(-1);
1929 }
1930 }
1931 return(0);
1932}
1933#endif
1934
1935/**
1936 * memParseTest:
1937 * @filename: the file to parse
1938 * @result: the file with expected result
1939 * @err: the file with error messages: unused
1940 *
1941 * Parse a file using the old xmlReadMemory API, then serialize back
1942 * reparse the result and serialize again, then check for deviation
1943 * in serialization.
1944 *
1945 * Returns 0 in case of success, an error code otherwise
1946 */
1947static int
1948memParseTest(const char *filename, const char *result,
1949 const char *err ATTRIBUTE_UNUSED,
1950 int options ATTRIBUTE_UNUSED) {
1951 xmlDocPtr doc;
1952 const char *base;
1953 int size, res;
1954
1955 nb_tests++;
1956 /*
1957 * load and parse the memory
1958 */
1959 if (loadMem(filename, &base, &size) != 0) {
1960 fprintf(stderr, "Failed to load %s\n", filename);
1961 return(-1);
1962 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00001963
William M. Brackca15a542005-07-06 20:41:33 +00001964 doc = xmlReadMemory(base, size, filename, NULL, 0);
1965 unloadMem(base);
1966 if (doc == NULL) {
1967 return(1);
1968 }
1969 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1970 xmlFreeDoc(doc);
1971 res = compareFileMem(result, base, size);
1972 if ((base == NULL) || (res != 0)) {
1973 if (base != NULL)
1974 xmlFree((char *)base);
Daniel Veillard9f2416c2016-05-22 11:14:45 +08001975 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00001976 return(-1);
1977 }
1978 xmlFree((char *)base);
1979 return(0);
1980}
1981
1982/**
1983 * noentParseTest:
1984 * @filename: the file to parse
1985 * @result: the file with expected result
1986 * @err: the file with error messages: unused
1987 *
1988 * Parse a file with entity resolution, then serialize back
1989 * reparse the result and serialize again, then check for deviation
1990 * in serialization.
1991 *
1992 * Returns 0 in case of success, an error code otherwise
1993 */
1994static int
1995noentParseTest(const char *filename, const char *result,
1996 const char *err ATTRIBUTE_UNUSED,
1997 int options) {
1998 xmlDocPtr doc;
1999 char *temp;
2000 int res = 0;
2001
2002 nb_tests++;
2003 /*
2004 * base of the test, parse with the old API
2005 */
2006 doc = xmlReadFile(filename, NULL, options);
2007 if (doc == NULL)
2008 return(1);
2009 temp = resultFilename(filename, "", ".res");
2010 if (temp == NULL) {
2011 fprintf(stderr, "Out of memory\n");
2012 fatalError();
2013 }
2014 xmlSaveFile(temp, doc);
2015 if (compareFiles(temp, result)) {
2016 res = 1;
2017 }
2018 xmlFreeDoc(doc);
2019
2020 /*
2021 * Parse the saved result to make sure the round trip is okay
2022 */
2023 doc = xmlReadFile(filename, NULL, options);
2024 if (doc == NULL)
2025 return(1);
2026 xmlSaveFile(temp, doc);
2027 if (compareFiles(temp, result)) {
2028 res = 1;
2029 }
2030 xmlFreeDoc(doc);
2031
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002032 if (temp != NULL) {
2033 unlink(temp);
2034 free(temp);
2035 }
William M. Brackca15a542005-07-06 20:41:33 +00002036 return(res);
2037}
2038
2039/**
2040 * errParseTest:
2041 * @filename: the file to parse
2042 * @result: the file with expected result
2043 * @err: the file with error messages
2044 *
2045 * Parse a file using the xmlReadFile API and check for errors.
2046 *
2047 * Returns 0 in case of success, an error code otherwise
2048 */
2049static int
2050errParseTest(const char *filename, const char *result, const char *err,
2051 int options) {
2052 xmlDocPtr doc;
2053 const char *base = NULL;
2054 int size, res = 0;
2055
2056 nb_tests++;
2057#ifdef LIBXML_HTML_ENABLED
2058 if (options & XML_PARSE_HTML) {
2059 doc = htmlReadFile(filename, NULL, options);
2060 } else
2061#endif
2062#ifdef LIBXML_XINCLUDE_ENABLED
2063 if (options & XML_PARSE_XINCLUDE) {
2064 doc = xmlReadFile(filename, NULL, options);
2065 xmlXIncludeProcessFlags(doc, options);
2066 } else
2067#endif
2068 {
2069 xmlGetWarningsDefaultValue = 1;
2070 doc = xmlReadFile(filename, NULL, options);
2071 }
2072 xmlGetWarningsDefaultValue = 0;
2073 if (result) {
2074 if (doc == NULL) {
2075 base = "";
2076 size = 0;
2077 } else {
2078#ifdef LIBXML_HTML_ENABLED
2079 if (options & XML_PARSE_HTML) {
2080 htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2081 } else
2082#endif
2083 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2084 }
2085 res = compareFileMem(result, base, size);
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002086 if (res != 0) {
2087 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
2088 return(-1);
2089 }
William M. Brackca15a542005-07-06 20:41:33 +00002090 }
2091 if (doc != NULL) {
2092 if (base != NULL)
2093 xmlFree((char *)base);
2094 xmlFreeDoc(doc);
2095 }
William M. Brackca15a542005-07-06 20:41:33 +00002096 if (err != NULL) {
2097 res = compareFileMem(err, testErrors, testErrorsSize);
2098 if (res != 0) {
2099 fprintf(stderr, "Error for %s failed\n", filename);
2100 return(-1);
2101 }
2102 } else if (options & XML_PARSE_DTDVALID) {
2103 if (testErrorsSize != 0)
2104 fprintf(stderr, "Validation for %s failed\n", filename);
2105 }
2106
2107 return(0);
2108}
2109
2110#ifdef LIBXML_READER_ENABLED
2111/************************************************************************
2112 * *
2113 * Reader based tests *
2114 * *
2115 ************************************************************************/
2116
2117static void processNode(FILE *out, xmlTextReaderPtr reader) {
2118 const xmlChar *name, *value;
2119 int type, empty;
2120
2121 type = xmlTextReaderNodeType(reader);
2122 empty = xmlTextReaderIsEmptyElement(reader);
2123
2124 name = xmlTextReaderConstName(reader);
2125 if (name == NULL)
2126 name = BAD_CAST "--";
2127
2128 value = xmlTextReaderConstValue(reader);
2129
Daniel Veillardaa6de472008-08-25 14:53:31 +00002130
2131 fprintf(out, "%d %d %s %d %d",
William M. Brackca15a542005-07-06 20:41:33 +00002132 xmlTextReaderDepth(reader),
2133 type,
2134 name,
2135 empty,
2136 xmlTextReaderHasValue(reader));
2137 if (value == NULL)
2138 fprintf(out, "\n");
2139 else {
2140 fprintf(out, " %s\n", value);
2141 }
2142}
2143static int
2144streamProcessTest(const char *filename, const char *result, const char *err,
Daniel Veillarda7982ce2012-10-25 15:39:39 +08002145 xmlTextReaderPtr reader, const char *rng, int options) {
William M. Brackca15a542005-07-06 20:41:33 +00002146 int ret;
2147 char *temp = NULL;
2148 FILE *t = NULL;
2149
2150 if (reader == NULL)
2151 return(-1);
2152
2153 nb_tests++;
2154 if (result != NULL) {
2155 temp = resultFilename(filename, "", ".res");
2156 if (temp == NULL) {
2157 fprintf(stderr, "Out of memory\n");
2158 fatalError();
2159 }
2160 t = fopen(temp, "wb");
2161 if (t == NULL) {
2162 fprintf(stderr, "Can't open temp file %s\n", temp);
2163 free(temp);
2164 return(-1);
2165 }
2166 }
2167#ifdef LIBXML_SCHEMAS_ENABLED
2168 if (rng != NULL) {
2169 ret = xmlTextReaderRelaxNGValidate(reader, rng);
2170 if (ret < 0) {
2171 testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n",
2172 rng);
2173 fclose(t);
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002174 if (temp != NULL) {
2175 unlink(temp);
2176 free(temp);
2177 }
William M. Brackca15a542005-07-06 20:41:33 +00002178 return(0);
2179 }
2180 }
2181#endif
2182 xmlGetWarningsDefaultValue = 1;
2183 ret = xmlTextReaderRead(reader);
2184 while (ret == 1) {
2185 if ((t != NULL) && (rng == NULL))
2186 processNode(t, reader);
2187 ret = xmlTextReaderRead(reader);
2188 }
2189 if (ret != 0) {
2190 testErrorHandler(NULL, "%s : failed to parse\n", filename);
2191 }
2192 if (rng != NULL) {
2193 if (xmlTextReaderIsValid(reader) != 1) {
2194 testErrorHandler(NULL, "%s fails to validate\n", filename);
2195 } else {
2196 testErrorHandler(NULL, "%s validates\n", filename);
2197 }
2198 }
2199 xmlGetWarningsDefaultValue = 0;
2200 if (t != NULL) {
2201 fclose(t);
2202 ret = compareFiles(temp, result);
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002203 if (temp != NULL) {
2204 unlink(temp);
2205 free(temp);
2206 }
William M. Brackca15a542005-07-06 20:41:33 +00002207 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002208 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002209 return(-1);
2210 }
2211 }
2212 if (err != NULL) {
2213 ret = compareFileMem(err, testErrors, testErrorsSize);
2214 if (ret != 0) {
2215 fprintf(stderr, "Error for %s failed\n", filename);
2216 printf("%s", testErrors);
2217 return(-1);
2218 }
2219 }
2220
2221 return(0);
2222}
2223
2224/**
2225 * streamParseTest:
2226 * @filename: the file to parse
2227 * @result: the file with expected result
2228 * @err: the file with error messages
2229 *
2230 * Parse a file using the reader API and check for errors.
2231 *
2232 * Returns 0 in case of success, an error code otherwise
2233 */
2234static int
2235streamParseTest(const char *filename, const char *result, const char *err,
2236 int options) {
2237 xmlTextReaderPtr reader;
2238 int ret;
2239
2240 reader = xmlReaderForFile(filename, NULL, options);
Daniel Veillarda7982ce2012-10-25 15:39:39 +08002241 ret = streamProcessTest(filename, result, err, reader, NULL, options);
William M. Brackca15a542005-07-06 20:41:33 +00002242 xmlFreeTextReader(reader);
2243 return(ret);
2244}
2245
2246/**
2247 * walkerParseTest:
2248 * @filename: the file to parse
2249 * @result: the file with expected result
2250 * @err: the file with error messages
2251 *
2252 * Parse a file using the walker, i.e. a reader built from a atree.
2253 *
2254 * Returns 0 in case of success, an error code otherwise
2255 */
2256static int
2257walkerParseTest(const char *filename, const char *result, const char *err,
2258 int options) {
2259 xmlDocPtr doc;
2260 xmlTextReaderPtr reader;
2261 int ret;
2262
2263 doc = xmlReadFile(filename, NULL, options);
2264 if (doc == NULL) {
2265 fprintf(stderr, "Failed to parse %s\n", filename);
2266 return(-1);
2267 }
2268 reader = xmlReaderWalker(doc);
Daniel Veillarda7982ce2012-10-25 15:39:39 +08002269 ret = streamProcessTest(filename, result, err, reader, NULL, options);
William M. Brackca15a542005-07-06 20:41:33 +00002270 xmlFreeTextReader(reader);
2271 xmlFreeDoc(doc);
2272 return(ret);
2273}
2274
2275/**
2276 * streamMemParseTest:
2277 * @filename: the file to parse
2278 * @result: the file with expected result
2279 * @err: the file with error messages
2280 *
2281 * Parse a file using the reader API from memory and check for errors.
2282 *
2283 * Returns 0 in case of success, an error code otherwise
2284 */
2285static int
2286streamMemParseTest(const char *filename, const char *result, const char *err,
2287 int options) {
2288 xmlTextReaderPtr reader;
2289 int ret;
2290 const char *base;
2291 int size;
2292
2293 /*
2294 * load and parse the memory
2295 */
2296 if (loadMem(filename, &base, &size) != 0) {
2297 fprintf(stderr, "Failed to load %s\n", filename);
2298 return(-1);
2299 }
2300 reader = xmlReaderForMemory(base, size, filename, NULL, options);
Daniel Veillarda7982ce2012-10-25 15:39:39 +08002301 ret = streamProcessTest(filename, result, err, reader, NULL, options);
William M. Brackca15a542005-07-06 20:41:33 +00002302 free((char *)base);
2303 xmlFreeTextReader(reader);
2304 return(ret);
2305}
2306#endif
2307
2308#ifdef LIBXML_XPATH_ENABLED
2309#ifdef LIBXML_DEBUG_ENABLED
2310/************************************************************************
2311 * *
2312 * XPath and XPointer based tests *
2313 * *
2314 ************************************************************************/
2315
Daniel Veillard24505b02005-07-28 23:49:35 +00002316static FILE *xpathOutput;
2317static xmlDocPtr xpathDocument;
William M. Brackca15a542005-07-06 20:41:33 +00002318
2319static void
Nick Wellnhofer1fc55ca2016-06-25 12:35:09 +02002320ignoreGenericError(void *ctx ATTRIBUTE_UNUSED,
2321 const char *msg ATTRIBUTE_UNUSED, ...) {
2322}
2323
2324static void
William M. Brackca15a542005-07-06 20:41:33 +00002325testXPath(const char *str, int xptr, int expr) {
Nick Wellnhofer1fc55ca2016-06-25 12:35:09 +02002326 xmlGenericErrorFunc handler = ignoreGenericError;
William M. Brackca15a542005-07-06 20:41:33 +00002327 xmlXPathObjectPtr res;
2328 xmlXPathContextPtr ctxt;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002329
Nick Wellnhofer1fc55ca2016-06-25 12:35:09 +02002330 /* Don't print generic errors to stderr. */
2331 initGenericErrorDefaultFunc(&handler);
2332
William M. Brackca15a542005-07-06 20:41:33 +00002333 nb_tests++;
2334#if defined(LIBXML_XPTR_ENABLED)
2335 if (xptr) {
2336 ctxt = xmlXPtrNewContext(xpathDocument, NULL, NULL);
2337 res = xmlXPtrEval(BAD_CAST str, ctxt);
2338 } else {
2339#endif
2340 ctxt = xmlXPathNewContext(xpathDocument);
2341 ctxt->node = xmlDocGetRootElement(xpathDocument);
2342 if (expr)
2343 res = xmlXPathEvalExpression(BAD_CAST str, ctxt);
2344 else {
2345 /* res = xmlXPathEval(BAD_CAST str, ctxt); */
2346 xmlXPathCompExprPtr comp;
2347
2348 comp = xmlXPathCompile(BAD_CAST str);
2349 if (comp != NULL) {
2350 res = xmlXPathCompiledEval(comp, ctxt);
2351 xmlXPathFreeCompExpr(comp);
2352 } else
2353 res = NULL;
2354 }
2355#if defined(LIBXML_XPTR_ENABLED)
2356 }
2357#endif
2358 xmlXPathDebugDumpObject(xpathOutput, res, 0);
2359 xmlXPathFreeObject(res);
2360 xmlXPathFreeContext(ctxt);
Nick Wellnhofer1fc55ca2016-06-25 12:35:09 +02002361
2362 /* Reset generic error handler. */
2363 initGenericErrorDefaultFunc(NULL);
William M. Brackca15a542005-07-06 20:41:33 +00002364}
2365
2366/**
2367 * xpathExprTest:
2368 * @filename: the file to parse
2369 * @result: the file with expected result
2370 * @err: the file with error messages
2371 *
2372 * Parse a file containing XPath standalone expressions and evaluate them
2373 *
2374 * Returns 0 in case of success, an error code otherwise
2375 */
2376static int
2377xpathCommonTest(const char *filename, const char *result,
2378 int xptr, int expr) {
2379 FILE *input;
2380 char expression[5000];
2381 int len, ret = 0;
2382 char *temp;
2383
2384 temp = resultFilename(filename, "", ".res");
2385 if (temp == NULL) {
2386 fprintf(stderr, "Out of memory\n");
2387 fatalError();
2388 }
2389 xpathOutput = fopen(temp, "wb");
2390 if (xpathOutput == NULL) {
2391 fprintf(stderr, "failed to open output file %s\n", temp);
2392 free(temp);
2393 return(-1);
2394 }
2395
2396 input = fopen(filename, "rb");
2397 if (input == NULL) {
2398 xmlGenericError(xmlGenericErrorContext,
2399 "Cannot open %s for reading\n", filename);
2400 free(temp);
2401 return(-1);
2402 }
2403 while (fgets(expression, 4500, input) != NULL) {
2404 len = strlen(expression);
2405 len--;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002406 while ((len >= 0) &&
William M. Brackca15a542005-07-06 20:41:33 +00002407 ((expression[len] == '\n') || (expression[len] == '\t') ||
2408 (expression[len] == '\r') || (expression[len] == ' '))) len--;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002409 expression[len + 1] = 0;
William M. Brackca15a542005-07-06 20:41:33 +00002410 if (len >= 0) {
2411 fprintf(xpathOutput,
2412 "\n========================\nExpression: %s\n",
2413 expression) ;
2414 testXPath(expression, xptr, expr);
2415 }
2416 }
2417
2418 fclose(input);
2419 fclose(xpathOutput);
2420 if (result != NULL) {
2421 ret = compareFiles(temp, result);
2422 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002423 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002424 }
2425 }
2426
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002427 if (temp != NULL) {
2428 unlink(temp);
2429 free(temp);
2430 }
William M. Brackca15a542005-07-06 20:41:33 +00002431 return(ret);
2432}
2433
2434/**
2435 * xpathExprTest:
2436 * @filename: the file to parse
2437 * @result: the file with expected result
2438 * @err: the file with error messages
2439 *
2440 * Parse a file containing XPath standalone expressions and evaluate them
2441 *
2442 * Returns 0 in case of success, an error code otherwise
2443 */
2444static int
2445xpathExprTest(const char *filename, const char *result,
2446 const char *err ATTRIBUTE_UNUSED,
2447 int options ATTRIBUTE_UNUSED) {
2448 return(xpathCommonTest(filename, result, 0, 1));
2449}
2450
2451/**
2452 * xpathDocTest:
2453 * @filename: the file to parse
2454 * @result: the file with expected result
2455 * @err: the file with error messages
2456 *
2457 * Parse a file containing XPath expressions and evaluate them against
2458 * a set of corresponding documents.
2459 *
2460 * Returns 0 in case of success, an error code otherwise
2461 */
2462static int
2463xpathDocTest(const char *filename,
2464 const char *resul ATTRIBUTE_UNUSED,
2465 const char *err ATTRIBUTE_UNUSED,
2466 int options) {
2467
2468 char pattern[500];
2469 char result[500];
2470 glob_t globbuf;
2471 size_t i;
2472 int ret = 0, res;
2473
2474 xpathDocument = xmlReadFile(filename, NULL,
2475 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2476 if (xpathDocument == NULL) {
2477 fprintf(stderr, "Failed to load %s\n", filename);
2478 return(-1);
2479 }
2480
2481 snprintf(pattern, 499, "./test/XPath/tests/%s*", baseFilename(filename));
2482 pattern[499] = 0;
2483 globbuf.gl_offs = 0;
2484 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2485 for (i = 0;i < globbuf.gl_pathc;i++) {
2486 snprintf(result, 499, "result/XPath/tests/%s",
2487 baseFilename(globbuf.gl_pathv[i]));
2488 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 0, 0);
2489 if (res != 0)
2490 ret = res;
2491 }
2492 globfree(&globbuf);
2493
2494 xmlFreeDoc(xpathDocument);
2495 return(ret);
2496}
2497
2498#ifdef LIBXML_XPTR_ENABLED
2499/**
2500 * xptrDocTest:
2501 * @filename: the file to parse
2502 * @result: the file with expected result
2503 * @err: the file with error messages
2504 *
2505 * Parse a file containing XPath expressions and evaluate them against
2506 * a set of corresponding documents.
2507 *
2508 * Returns 0 in case of success, an error code otherwise
2509 */
2510static int
2511xptrDocTest(const char *filename,
2512 const char *resul ATTRIBUTE_UNUSED,
2513 const char *err ATTRIBUTE_UNUSED,
2514 int options) {
2515
2516 char pattern[500];
2517 char result[500];
2518 glob_t globbuf;
2519 size_t i;
2520 int ret = 0, res;
2521
2522 xpathDocument = xmlReadFile(filename, NULL,
2523 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2524 if (xpathDocument == NULL) {
2525 fprintf(stderr, "Failed to load %s\n", filename);
2526 return(-1);
2527 }
2528
2529 snprintf(pattern, 499, "./test/XPath/xptr/%s*", baseFilename(filename));
2530 pattern[499] = 0;
2531 globbuf.gl_offs = 0;
2532 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2533 for (i = 0;i < globbuf.gl_pathc;i++) {
2534 snprintf(result, 499, "result/XPath/xptr/%s",
2535 baseFilename(globbuf.gl_pathv[i]));
2536 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 1, 0);
2537 if (res != 0)
2538 ret = res;
2539 }
2540 globfree(&globbuf);
2541
2542 xmlFreeDoc(xpathDocument);
2543 return(ret);
2544}
2545#endif /* LIBXML_XPTR_ENABLED */
2546
2547/**
2548 * xmlidDocTest:
2549 * @filename: the file to parse
2550 * @result: the file with expected result
2551 * @err: the file with error messages
2552 *
2553 * Parse a file containing xml:id and check for errors and verify
2554 * that XPath queries will work on them as expected.
2555 *
2556 * Returns 0 in case of success, an error code otherwise
2557 */
2558static int
2559xmlidDocTest(const char *filename,
2560 const char *result,
2561 const char *err,
2562 int options) {
2563
2564 int res = 0;
2565 int ret = 0;
2566 char *temp;
2567
2568 xpathDocument = xmlReadFile(filename, NULL,
2569 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2570 if (xpathDocument == NULL) {
2571 fprintf(stderr, "Failed to load %s\n", filename);
2572 return(-1);
2573 }
2574
2575 temp = resultFilename(filename, "", ".res");
2576 if (temp == NULL) {
2577 fprintf(stderr, "Out of memory\n");
2578 fatalError();
2579 }
2580 xpathOutput = fopen(temp, "wb");
2581 if (xpathOutput == NULL) {
2582 fprintf(stderr, "failed to open output file %s\n", temp);
2583 xmlFreeDoc(xpathDocument);
2584 free(temp);
2585 return(-1);
2586 }
2587
2588 testXPath("id('bar')", 0, 0);
2589
2590 fclose(xpathOutput);
2591 if (result != NULL) {
2592 ret = compareFiles(temp, result);
2593 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002594 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002595 res = 1;
2596 }
2597 }
2598
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002599 if (temp != NULL) {
2600 unlink(temp);
2601 free(temp);
2602 }
William M. Brackca15a542005-07-06 20:41:33 +00002603 xmlFreeDoc(xpathDocument);
2604
2605 if (err != NULL) {
2606 ret = compareFileMem(err, testErrors, testErrorsSize);
2607 if (ret != 0) {
2608 fprintf(stderr, "Error for %s failed\n", filename);
2609 res = 1;
2610 }
2611 }
2612 return(res);
2613}
2614
2615#endif /* LIBXML_DEBUG_ENABLED */
2616#endif /* XPATH */
2617/************************************************************************
2618 * *
2619 * URI based tests *
2620 * *
2621 ************************************************************************/
2622
2623static void
2624handleURI(const char *str, const char *base, FILE *o) {
2625 int ret;
2626 xmlURIPtr uri;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002627 xmlChar *res = NULL;
William M. Brackca15a542005-07-06 20:41:33 +00002628
2629 uri = xmlCreateURI();
2630
2631 if (base == NULL) {
2632 ret = xmlParseURIReference(uri, str);
2633 if (ret != 0)
2634 fprintf(o, "%s : error %d\n", str, ret);
2635 else {
2636 xmlNormalizeURIPath(uri->path);
2637 xmlPrintURI(o, uri);
2638 fprintf(o, "\n");
2639 }
2640 } else {
2641 res = xmlBuildURI((xmlChar *)str, (xmlChar *) base);
2642 if (res != NULL) {
2643 fprintf(o, "%s\n", (char *) res);
2644 }
2645 else
2646 fprintf(o, "::ERROR::\n");
2647 }
2648 if (res != NULL)
2649 xmlFree(res);
William M. Brackca15a542005-07-06 20:41:33 +00002650 xmlFreeURI(uri);
2651}
2652
2653/**
2654 * uriCommonTest:
2655 * @filename: the file to parse
2656 * @result: the file with expected result
2657 * @err: the file with error messages
2658 *
2659 * Parse a file containing URI and check for errors
2660 *
2661 * Returns 0 in case of success, an error code otherwise
2662 */
2663static int
2664uriCommonTest(const char *filename,
2665 const char *result,
2666 const char *err,
2667 const char *base) {
2668 char *temp;
2669 FILE *o, *f;
2670 char str[1024];
2671 int res = 0, i, ret;
2672
2673 temp = resultFilename(filename, "", ".res");
2674 if (temp == NULL) {
2675 fprintf(stderr, "Out of memory\n");
2676 fatalError();
2677 }
2678 o = fopen(temp, "wb");
2679 if (o == NULL) {
2680 fprintf(stderr, "failed to open output file %s\n", temp);
2681 free(temp);
2682 return(-1);
2683 }
2684 f = fopen(filename, "rb");
2685 if (f == NULL) {
2686 fprintf(stderr, "failed to open input file %s\n", filename);
2687 fclose(o);
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002688 if (temp != NULL) {
2689 unlink(temp);
2690 free(temp);
2691 }
William M. Brackca15a542005-07-06 20:41:33 +00002692 return(-1);
2693 }
2694
2695 while (1) {
2696 /*
2697 * read one line in string buffer.
2698 */
2699 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
2700 break;
2701
2702 /*
2703 * remove the ending spaces
2704 */
2705 i = strlen(str);
2706 while ((i > 0) &&
2707 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
2708 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
2709 i--;
2710 str[i] = 0;
2711 }
2712 nb_tests++;
2713 handleURI(str, base, o);
2714 }
2715
2716 fclose(f);
2717 fclose(o);
2718
2719 if (result != NULL) {
2720 ret = compareFiles(temp, result);
2721 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002722 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002723 res = 1;
2724 }
2725 }
2726 if (err != NULL) {
2727 ret = compareFileMem(err, testErrors, testErrorsSize);
2728 if (ret != 0) {
2729 fprintf(stderr, "Error for %s failed\n", filename);
2730 res = 1;
2731 }
2732 }
2733
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002734 if (temp != NULL) {
2735 unlink(temp);
2736 free(temp);
2737 }
William M. Brackca15a542005-07-06 20:41:33 +00002738 return(res);
2739}
2740
2741/**
2742 * uriParseTest:
2743 * @filename: the file to parse
2744 * @result: the file with expected result
2745 * @err: the file with error messages
2746 *
2747 * Parse a file containing URI and check for errors
2748 *
2749 * Returns 0 in case of success, an error code otherwise
2750 */
2751static int
2752uriParseTest(const char *filename,
2753 const char *result,
2754 const char *err,
2755 int options ATTRIBUTE_UNUSED) {
2756 return(uriCommonTest(filename, result, err, NULL));
2757}
2758
2759/**
2760 * uriBaseTest:
2761 * @filename: the file to parse
2762 * @result: the file with expected result
2763 * @err: the file with error messages
2764 *
2765 * Parse a file containing URI, compose them against a fixed base and
2766 * check for errors
2767 *
2768 * Returns 0 in case of success, an error code otherwise
2769 */
2770static int
2771uriBaseTest(const char *filename,
2772 const char *result,
2773 const char *err,
2774 int options ATTRIBUTE_UNUSED) {
2775 return(uriCommonTest(filename, result, err,
2776 "http://foo.com/path/to/index.html?orig#help"));
2777}
2778
Daniel Veillard336a8e12005-08-07 10:46:19 +00002779static int urip_success = 1;
2780static int urip_current = 0;
2781static const char *urip_testURLs[] = {
2782 "urip://example.com/a b.html",
2783 "urip://example.com/a%20b.html",
2784 "file:///path/to/a b.html",
2785 "file:///path/to/a%20b.html",
2786 "/path/to/a b.html",
2787 "/path/to/a%20b.html",
Daniel Veillardff7227f2012-08-20 20:58:24 +08002788 "urip://example.com/r" "\xe9" "sum" "\xe9" ".html",
Daniel Veillard336a8e12005-08-07 10:46:19 +00002789 "urip://example.com/test?a=1&b=2%263&c=4#foo",
2790 NULL
2791};
2792static const char *urip_rcvsURLs[] = {
2793 /* it is an URI the strings must be escaped */
2794 "urip://example.com/a%20b.html",
2795 /* check that % escaping is not broken */
2796 "urip://example.com/a%20b.html",
2797 /* it's an URI path the strings must be escaped */
2798 "file:///path/to/a%20b.html",
2799 /* check that % escaping is not broken */
2800 "file:///path/to/a%20b.html",
2801 /* this is not an URI, this is a path, so this should not be escaped */
2802 "/path/to/a b.html",
2803 /* check that paths with % are not broken */
2804 "/path/to/a%20b.html",
2805 /* out of context the encoding can't be guessed byte by byte conversion */
2806 "urip://example.com/r%E9sum%E9.html",
2807 /* verify we don't destroy URIs especially the query part */
2808 "urip://example.com/test?a=1&b=2%263&c=4#foo",
2809 NULL
2810};
2811static const char *urip_res = "<list/>";
2812static const char *urip_cur = NULL;
2813static int urip_rlen;
2814
2815/**
2816 * uripMatch:
2817 * @URI: an URI to test
2818 *
2819 * Check for an urip: query
2820 *
2821 * Returns 1 if yes and 0 if another Input module should be used
2822 */
2823static int
2824uripMatch(const char * URI) {
2825 if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog")))
2826 return(0);
2827 /* Verify we received the escaped URL */
2828 if (strcmp(urip_rcvsURLs[urip_current], URI))
2829 urip_success = 0;
2830 return(1);
2831}
2832
2833/**
2834 * uripOpen:
2835 * @URI: an URI to test
2836 *
2837 * Return a pointer to the urip: query handler, in this example simply
2838 * the urip_current pointer...
2839 *
2840 * Returns an Input context or NULL in case or error
2841 */
2842static void *
2843uripOpen(const char * URI) {
2844 if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog")))
2845 return(NULL);
2846 /* Verify we received the escaped URL */
2847 if (strcmp(urip_rcvsURLs[urip_current], URI))
2848 urip_success = 0;
2849 urip_cur = urip_res;
2850 urip_rlen = strlen(urip_res);
2851 return((void *) urip_cur);
2852}
2853
2854/**
2855 * uripClose:
2856 * @context: the read context
2857 *
2858 * Close the urip: query handler
2859 *
2860 * Returns 0 or -1 in case of error
2861 */
2862static int
2863uripClose(void * context) {
2864 if (context == NULL) return(-1);
2865 urip_cur = NULL;
2866 urip_rlen = 0;
2867 return(0);
2868}
2869
2870/**
2871 * uripRead:
2872 * @context: the read context
2873 * @buffer: where to store data
2874 * @len: number of bytes to read
2875 *
2876 * Implement an urip: query read.
2877 *
2878 * Returns the number of bytes read or -1 in case of error
2879 */
2880static int
2881uripRead(void * context, char * buffer, int len) {
2882 const char *ptr = (const char *) context;
2883
2884 if ((context == NULL) || (buffer == NULL) || (len < 0))
2885 return(-1);
2886
2887 if (len > urip_rlen) len = urip_rlen;
2888 memcpy(buffer, ptr, len);
2889 urip_rlen -= len;
2890 return(len);
2891}
2892
2893static int
2894urip_checkURL(const char *URL) {
2895 xmlDocPtr doc;
2896
2897 doc = xmlReadFile(URL, NULL, 0);
2898 if (doc == NULL)
2899 return(-1);
2900 xmlFreeDoc(doc);
2901 return(1);
2902}
2903
2904/**
2905 * uriPathTest:
2906 * @filename: ignored
2907 * @result: ignored
2908 * @err: ignored
2909 *
2910 * Run a set of tests to check how Path and URI are handled before
2911 * being passed to the I/O layer
2912 *
2913 * Returns 0 in case of success, an error code otherwise
2914 */
2915static int
2916uriPathTest(const char *filename ATTRIBUTE_UNUSED,
2917 const char *result ATTRIBUTE_UNUSED,
2918 const char *err ATTRIBUTE_UNUSED,
2919 int options ATTRIBUTE_UNUSED) {
2920 int parsed;
2921 int failures = 0;
2922
2923 /*
2924 * register the new I/O handlers
2925 */
2926 if (xmlRegisterInputCallbacks(uripMatch, uripOpen, uripRead, uripClose) < 0)
2927 {
2928 fprintf(stderr, "failed to register HTTP handler\n");
2929 return(-1);
2930 }
2931
2932 for (urip_current = 0;urip_testURLs[urip_current] != NULL;urip_current++) {
2933 urip_success = 1;
2934 parsed = urip_checkURL(urip_testURLs[urip_current]);
2935 if (urip_success != 1) {
2936 fprintf(stderr, "failed the URL passing test for %s",
2937 urip_testURLs[urip_current]);
2938 failures++;
2939 } else if (parsed != 1) {
2940 fprintf(stderr, "failed the parsing test for %s",
2941 urip_testURLs[urip_current]);
2942 failures++;
2943 }
2944 nb_tests++;
2945 }
2946
2947 xmlPopInputCallbacks();
2948 return(failures);
2949}
2950
William M. Brackca15a542005-07-06 20:41:33 +00002951#ifdef LIBXML_SCHEMAS_ENABLED
2952/************************************************************************
2953 * *
2954 * Schemas tests *
2955 * *
2956 ************************************************************************/
2957static int
2958schemasOneTest(const char *sch,
2959 const char *filename,
2960 const char *result,
2961 const char *err,
2962 int options,
2963 xmlSchemaPtr schemas) {
2964 xmlDocPtr doc;
2965 xmlSchemaValidCtxtPtr ctxt;
2966 int ret = 0;
Daniel Veillard381ff362006-06-18 17:31:31 +00002967 int validResult = 0;
William M. Brackca15a542005-07-06 20:41:33 +00002968 char *temp;
2969 FILE *schemasOutput;
2970
2971 doc = xmlReadFile(filename, NULL, options);
2972 if (doc == NULL) {
2973 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
2974 return(-1);
2975 }
2976
2977 temp = resultFilename(result, "", ".res");
2978 if (temp == NULL) {
2979 fprintf(stderr, "Out of memory\n");
2980 fatalError();
2981 }
2982 schemasOutput = fopen(temp, "wb");
2983 if (schemasOutput == NULL) {
2984 fprintf(stderr, "failed to open output file %s\n", temp);
2985 xmlFreeDoc(doc);
2986 free(temp);
2987 return(-1);
2988 }
2989
2990 ctxt = xmlSchemaNewValidCtxt(schemas);
2991 xmlSchemaSetValidErrors(ctxt,
2992 (xmlSchemaValidityErrorFunc) testErrorHandler,
2993 (xmlSchemaValidityWarningFunc) testErrorHandler,
2994 ctxt);
Daniel Veillard381ff362006-06-18 17:31:31 +00002995 validResult = xmlSchemaValidateDoc(ctxt, doc);
2996 if (validResult == 0) {
William M. Brackca15a542005-07-06 20:41:33 +00002997 fprintf(schemasOutput, "%s validates\n", filename);
Daniel Veillard381ff362006-06-18 17:31:31 +00002998 } else if (validResult > 0) {
William M. Brackca15a542005-07-06 20:41:33 +00002999 fprintf(schemasOutput, "%s fails to validate\n", filename);
3000 } else {
3001 fprintf(schemasOutput, "%s validation generated an internal error\n",
3002 filename);
3003 }
3004 fclose(schemasOutput);
3005 if (result) {
3006 if (compareFiles(temp, result)) {
3007 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
3008 ret = 1;
3009 }
3010 }
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003011 if (temp != NULL) {
3012 unlink(temp);
3013 free(temp);
3014 }
William M. Brackca15a542005-07-06 20:41:33 +00003015
Daniel Veillard381ff362006-06-18 17:31:31 +00003016 if ((validResult != 0) && (err != NULL)) {
William M. Brackca15a542005-07-06 20:41:33 +00003017 if (compareFileMem(err, testErrors, testErrorsSize)) {
3018 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
3019 ret = 1;
3020 }
3021 }
3022
William M. Brackca15a542005-07-06 20:41:33 +00003023 xmlSchemaFreeValidCtxt(ctxt);
3024 xmlFreeDoc(doc);
3025 return(ret);
3026}
3027/**
3028 * schemasTest:
3029 * @filename: the schemas file
3030 * @result: the file with expected result
3031 * @err: the file with error messages
3032 *
3033 * Parse a file containing URI, compose them against a fixed base and
3034 * check for errors
3035 *
3036 * Returns 0 in case of success, an error code otherwise
3037 */
3038static int
3039schemasTest(const char *filename,
3040 const char *resul ATTRIBUTE_UNUSED,
3041 const char *errr ATTRIBUTE_UNUSED,
3042 int options) {
3043 const char *base = baseFilename(filename);
3044 const char *base2;
3045 const char *instance;
3046 xmlSchemaParserCtxtPtr ctxt;
3047 xmlSchemaPtr schemas;
3048 int res = 0, len, ret;
3049 char pattern[500];
3050 char prefix[500];
3051 char result[500];
3052 char err[500];
3053 glob_t globbuf;
3054 size_t i;
3055 char count = 0;
3056
3057 /* first compile the schemas if possible */
3058 ctxt = xmlSchemaNewParserCtxt(filename);
3059 xmlSchemaSetParserErrors(ctxt,
3060 (xmlSchemaValidityErrorFunc) testErrorHandler,
3061 (xmlSchemaValidityWarningFunc) testErrorHandler,
3062 ctxt);
3063 schemas = xmlSchemaParse(ctxt);
3064 xmlSchemaFreeParserCtxt(ctxt);
3065
3066 /*
3067 * most of the mess is about the output filenames generated by the Makefile
3068 */
3069 len = strlen(base);
3070 if ((len > 499) || (len < 5)) {
3071 xmlSchemaFree(schemas);
3072 return(-1);
3073 }
3074 len -= 4; /* remove trailing .xsd */
3075 if (base[len - 2] == '_') {
3076 len -= 2; /* remove subtest number */
3077 }
3078 if (base[len - 2] == '_') {
3079 len -= 2; /* remove subtest number */
3080 }
3081 memcpy(prefix, base, len);
3082 prefix[len] = 0;
3083
3084 snprintf(pattern, 499, "./test/schemas/%s_?.xml", prefix);
3085 pattern[499] = 0;
3086
3087 if (base[len] == '_') {
3088 len += 2;
3089 memcpy(prefix, base, len);
3090 prefix[len] = 0;
3091 }
3092
3093 globbuf.gl_offs = 0;
3094 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3095 for (i = 0;i < globbuf.gl_pathc;i++) {
3096 testErrorsSize = 0;
3097 testErrors[0] = 0;
3098 instance = globbuf.gl_pathv[i];
3099 base2 = baseFilename(instance);
3100 len = strlen(base2);
3101 if ((len > 6) && (base2[len - 6] == '_')) {
3102 count = base2[len - 5];
3103 snprintf(result, 499, "result/schemas/%s_%c",
3104 prefix, count);
3105 result[499] = 0;
3106 snprintf(err, 499, "result/schemas/%s_%c.err",
3107 prefix, count);
3108 err[499] = 0;
3109 } else {
3110 fprintf(stderr, "don't know how to process %s\n", instance);
3111 continue;
3112 }
3113 if (schemas == NULL) {
3114 } else {
3115 nb_tests++;
3116 ret = schemasOneTest(filename, instance, result, err,
3117 options, schemas);
Daniel Veillard93e577f2005-11-15 08:50:04 +00003118 if (ret != 0)
3119 res = ret;
William M. Brackca15a542005-07-06 20:41:33 +00003120 }
3121 }
3122 globfree(&globbuf);
3123 xmlSchemaFree(schemas);
3124
3125 return(res);
3126}
3127
3128/************************************************************************
3129 * *
3130 * Schemas tests *
3131 * *
3132 ************************************************************************/
3133static int
3134rngOneTest(const char *sch,
3135 const char *filename,
3136 const char *result,
3137 const char *err,
3138 int options,
3139 xmlRelaxNGPtr schemas) {
3140 xmlDocPtr doc;
3141 xmlRelaxNGValidCtxtPtr ctxt;
3142 int ret = 0;
3143 char *temp;
3144 FILE *schemasOutput;
3145
3146 doc = xmlReadFile(filename, NULL, options);
3147 if (doc == NULL) {
3148 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
3149 return(-1);
3150 }
3151
3152 temp = resultFilename(result, "", ".res");
3153 if (temp == NULL) {
3154 fprintf(stderr, "Out of memory\n");
3155 fatalError();
3156 }
3157 schemasOutput = fopen(temp, "wb");
3158 if (schemasOutput == NULL) {
3159 fprintf(stderr, "failed to open output file %s\n", temp);
3160 xmlFreeDoc(doc);
3161 free(temp);
3162 return(-1);
3163 }
3164
3165 ctxt = xmlRelaxNGNewValidCtxt(schemas);
3166 xmlRelaxNGSetValidErrors(ctxt,
3167 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
3168 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
3169 ctxt);
3170 ret = xmlRelaxNGValidateDoc(ctxt, doc);
3171 if (ret == 0) {
3172 testErrorHandler(NULL, "%s validates\n", filename);
3173 } else if (ret > 0) {
3174 testErrorHandler(NULL, "%s fails to validate\n", filename);
3175 } else {
3176 testErrorHandler(NULL, "%s validation generated an internal error\n",
3177 filename);
3178 }
3179 fclose(schemasOutput);
Daniel Veillard594e5df2009-09-07 14:58:47 +02003180 ret = 0;
William M. Brackca15a542005-07-06 20:41:33 +00003181 if (result) {
3182 if (compareFiles(temp, result)) {
3183 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
3184 ret = 1;
3185 }
3186 }
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003187 if (temp != NULL) {
3188 unlink(temp);
3189 free(temp);
3190 }
William M. Brackca15a542005-07-06 20:41:33 +00003191
3192 if (err != NULL) {
3193 if (compareFileMem(err, testErrors, testErrorsSize)) {
3194 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
3195 ret = 1;
3196 printf("%s", testErrors);
3197 }
3198 }
3199
3200
3201 xmlRelaxNGFreeValidCtxt(ctxt);
3202 xmlFreeDoc(doc);
3203 return(ret);
3204}
3205/**
3206 * rngTest:
3207 * @filename: the schemas file
3208 * @result: the file with expected result
3209 * @err: the file with error messages
3210 *
3211 * Parse an RNG schemas and then apply it to the related .xml
3212 *
3213 * Returns 0 in case of success, an error code otherwise
3214 */
3215static int
3216rngTest(const char *filename,
3217 const char *resul ATTRIBUTE_UNUSED,
3218 const char *errr ATTRIBUTE_UNUSED,
3219 int options) {
3220 const char *base = baseFilename(filename);
3221 const char *base2;
3222 const char *instance;
3223 xmlRelaxNGParserCtxtPtr ctxt;
3224 xmlRelaxNGPtr schemas;
Rob Richardsc9667902010-01-22 08:24:25 -05003225 int res = 0, len, ret = 0;
William M. Brackca15a542005-07-06 20:41:33 +00003226 char pattern[500];
3227 char prefix[500];
3228 char result[500];
3229 char err[500];
3230 glob_t globbuf;
3231 size_t i;
3232 char count = 0;
3233
3234 /* first compile the schemas if possible */
3235 ctxt = xmlRelaxNGNewParserCtxt(filename);
3236 xmlRelaxNGSetParserErrors(ctxt,
3237 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
3238 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
3239 ctxt);
3240 schemas = xmlRelaxNGParse(ctxt);
3241 xmlRelaxNGFreeParserCtxt(ctxt);
3242
3243 /*
3244 * most of the mess is about the output filenames generated by the Makefile
3245 */
3246 len = strlen(base);
3247 if ((len > 499) || (len < 5)) {
3248 xmlRelaxNGFree(schemas);
3249 return(-1);
3250 }
3251 len -= 4; /* remove trailing .rng */
3252 memcpy(prefix, base, len);
3253 prefix[len] = 0;
3254
3255 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
3256 pattern[499] = 0;
3257
3258 globbuf.gl_offs = 0;
3259 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3260 for (i = 0;i < globbuf.gl_pathc;i++) {
3261 testErrorsSize = 0;
3262 testErrors[0] = 0;
3263 instance = globbuf.gl_pathv[i];
3264 base2 = baseFilename(instance);
3265 len = strlen(base2);
3266 if ((len > 6) && (base2[len - 6] == '_')) {
3267 count = base2[len - 5];
3268 snprintf(result, 499, "result/relaxng/%s_%c",
3269 prefix, count);
3270 result[499] = 0;
3271 snprintf(err, 499, "result/relaxng/%s_%c.err",
3272 prefix, count);
3273 err[499] = 0;
3274 } else {
3275 fprintf(stderr, "don't know how to process %s\n", instance);
3276 continue;
3277 }
3278 if (schemas == NULL) {
3279 } else {
3280 nb_tests++;
3281 ret = rngOneTest(filename, instance, result, err,
3282 options, schemas);
3283 if (res != 0)
3284 ret = res;
3285 }
3286 }
3287 globfree(&globbuf);
3288 xmlRelaxNGFree(schemas);
3289
Daniel Veillard594e5df2009-09-07 14:58:47 +02003290 return(ret);
William M. Brackca15a542005-07-06 20:41:33 +00003291}
3292
3293#ifdef LIBXML_READER_ENABLED
3294/**
3295 * rngStreamTest:
3296 * @filename: the schemas file
3297 * @result: the file with expected result
3298 * @err: the file with error messages
3299 *
Daniel Veillardaa6de472008-08-25 14:53:31 +00003300 * Parse a set of files with streaming, applying an RNG schemas
William M. Brackca15a542005-07-06 20:41:33 +00003301 *
3302 * Returns 0 in case of success, an error code otherwise
3303 */
3304static int
3305rngStreamTest(const char *filename,
3306 const char *resul ATTRIBUTE_UNUSED,
3307 const char *errr ATTRIBUTE_UNUSED,
3308 int options) {
3309 const char *base = baseFilename(filename);
3310 const char *base2;
3311 const char *instance;
3312 int res = 0, len, ret;
3313 char pattern[500];
3314 char prefix[500];
3315 char result[500];
3316 char err[500];
3317 glob_t globbuf;
3318 size_t i;
3319 char count = 0;
3320 xmlTextReaderPtr reader;
3321 int disable_err = 0;
3322
3323 /*
3324 * most of the mess is about the output filenames generated by the Makefile
3325 */
3326 len = strlen(base);
3327 if ((len > 499) || (len < 5)) {
3328 fprintf(stderr, "len(base) == %d !\n", len);
3329 return(-1);
3330 }
3331 len -= 4; /* remove trailing .rng */
3332 memcpy(prefix, base, len);
3333 prefix[len] = 0;
3334
3335 /*
3336 * strictly unifying the error messages is nearly impossible this
3337 * hack is also done in the Makefile
3338 */
3339 if ((!strcmp(prefix, "tutor10_1")) || (!strcmp(prefix, "tutor10_2")) ||
Daniel Veillardec18c962009-08-26 18:37:43 +02003340 (!strcmp(prefix, "tutor3_2")) || (!strcmp(prefix, "307377")) ||
3341 (!strcmp(prefix, "tutor8_2")))
William M. Brackca15a542005-07-06 20:41:33 +00003342 disable_err = 1;
3343
3344 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
3345 pattern[499] = 0;
3346
3347 globbuf.gl_offs = 0;
3348 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3349 for (i = 0;i < globbuf.gl_pathc;i++) {
3350 testErrorsSize = 0;
3351 testErrors[0] = 0;
3352 instance = globbuf.gl_pathv[i];
3353 base2 = baseFilename(instance);
3354 len = strlen(base2);
3355 if ((len > 6) && (base2[len - 6] == '_')) {
3356 count = base2[len - 5];
3357 snprintf(result, 499, "result/relaxng/%s_%c",
3358 prefix, count);
3359 result[499] = 0;
3360 snprintf(err, 499, "result/relaxng/%s_%c.err",
3361 prefix, count);
3362 err[499] = 0;
3363 } else {
3364 fprintf(stderr, "don't know how to process %s\n", instance);
3365 continue;
3366 }
3367 reader = xmlReaderForFile(instance, NULL, options);
3368 if (reader == NULL) {
3369 fprintf(stderr, "Failed to build reder for %s\n", instance);
3370 }
3371 if (disable_err == 1)
Daniel Veillarda7982ce2012-10-25 15:39:39 +08003372 ret = streamProcessTest(instance, result, NULL, reader, filename,
3373 options);
William M. Brackca15a542005-07-06 20:41:33 +00003374 else
Daniel Veillarda7982ce2012-10-25 15:39:39 +08003375 ret = streamProcessTest(instance, result, err, reader, filename,
3376 options);
William M. Brackca15a542005-07-06 20:41:33 +00003377 xmlFreeTextReader(reader);
3378 if (ret != 0) {
3379 fprintf(stderr, "instance %s failed\n", instance);
3380 res = ret;
3381 }
3382 }
3383 globfree(&globbuf);
3384
3385 return(res);
3386}
3387#endif /* READER */
3388
3389#endif
3390
3391#ifdef LIBXML_PATTERN_ENABLED
3392#ifdef LIBXML_READER_ENABLED
3393/************************************************************************
3394 * *
3395 * Patterns tests *
3396 * *
3397 ************************************************************************/
3398static void patternNode(FILE *out, xmlTextReaderPtr reader,
3399 const char *pattern, xmlPatternPtr patternc,
3400 xmlStreamCtxtPtr patstream) {
3401 xmlChar *path = NULL;
3402 int match = -1;
3403 int type, empty;
3404
3405 type = xmlTextReaderNodeType(reader);
3406 empty = xmlTextReaderIsEmptyElement(reader);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003407
William M. Brackca15a542005-07-06 20:41:33 +00003408 if (type == XML_READER_TYPE_ELEMENT) {
3409 /* do the check only on element start */
3410 match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader));
3411
3412 if (match) {
3413 path = xmlGetNodePath(xmlTextReaderCurrentNode(reader));
3414 fprintf(out, "Node %s matches pattern %s\n", path, pattern);
3415 }
3416 }
3417 if (patstream != NULL) {
3418 int ret;
3419
3420 if (type == XML_READER_TYPE_ELEMENT) {
3421 ret = xmlStreamPush(patstream,
3422 xmlTextReaderConstLocalName(reader),
3423 xmlTextReaderConstNamespaceUri(reader));
3424 if (ret < 0) {
3425 fprintf(out, "xmlStreamPush() failure\n");
3426 xmlFreeStreamCtxt(patstream);
3427 patstream = NULL;
3428 } else if (ret != match) {
3429 if (path == NULL) {
3430 path = xmlGetNodePath(
3431 xmlTextReaderCurrentNode(reader));
3432 }
3433 fprintf(out,
3434 "xmlPatternMatch and xmlStreamPush disagree\n");
3435 fprintf(out,
3436 " pattern %s node %s\n",
3437 pattern, path);
3438 }
William M. Brackca15a542005-07-06 20:41:33 +00003439
Daniel Veillardaa6de472008-08-25 14:53:31 +00003440
3441 }
William M. Brackca15a542005-07-06 20:41:33 +00003442 if ((type == XML_READER_TYPE_END_ELEMENT) ||
3443 ((type == XML_READER_TYPE_ELEMENT) && (empty))) {
3444 ret = xmlStreamPop(patstream);
3445 if (ret < 0) {
3446 fprintf(out, "xmlStreamPop() failure\n");
3447 xmlFreeStreamCtxt(patstream);
3448 patstream = NULL;
3449 }
3450 }
3451 }
3452 if (path != NULL)
3453 xmlFree(path);
3454}
3455
3456/**
3457 * patternTest:
3458 * @filename: the schemas file
3459 * @result: the file with expected result
3460 * @err: the file with error messages
3461 *
Daniel Veillardaa6de472008-08-25 14:53:31 +00003462 * Parse a set of files with streaming, applying an RNG schemas
William M. Brackca15a542005-07-06 20:41:33 +00003463 *
3464 * Returns 0 in case of success, an error code otherwise
3465 */
3466static int
3467patternTest(const char *filename,
3468 const char *resul ATTRIBUTE_UNUSED,
3469 const char *err ATTRIBUTE_UNUSED,
3470 int options) {
3471 xmlPatternPtr patternc = NULL;
3472 xmlStreamCtxtPtr patstream = NULL;
3473 FILE *o, *f;
3474 char str[1024];
3475 char xml[500];
3476 char result[500];
3477 int len, i;
3478 int ret = 0, res;
3479 char *temp;
3480 xmlTextReaderPtr reader;
3481 xmlDocPtr doc;
3482
3483 len = strlen(filename);
3484 len -= 4;
3485 memcpy(xml, filename, len);
3486 xml[len] = 0;
3487 snprintf(result, 499, "result/pattern/%s", baseFilename(xml));
3488 result[499] = 0;
3489 memcpy(xml + len, ".xml", 5);
3490
David Kilzer5c373822016-05-22 09:58:30 +08003491 if (!checkTestFile(xml) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00003492 fprintf(stderr, "Missing xml file %s\n", xml);
3493 return(-1);
3494 }
David Kilzer5c373822016-05-22 09:58:30 +08003495 if (!checkTestFile(result) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00003496 fprintf(stderr, "Missing result file %s\n", result);
3497 return(-1);
3498 }
3499 f = fopen(filename, "rb");
3500 if (f == NULL) {
3501 fprintf(stderr, "Failed to open %s\n", filename);
3502 return(-1);
3503 }
3504 temp = resultFilename(filename, "", ".res");
3505 if (temp == NULL) {
3506 fprintf(stderr, "Out of memory\n");
3507 fatalError();
3508 }
3509 o = fopen(temp, "wb");
3510 if (o == NULL) {
3511 fprintf(stderr, "failed to open output file %s\n", temp);
3512 fclose(f);
3513 free(temp);
3514 return(-1);
3515 }
3516 while (1) {
3517 /*
3518 * read one line in string buffer.
3519 */
3520 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
3521 break;
3522
3523 /*
3524 * remove the ending spaces
3525 */
3526 i = strlen(str);
3527 while ((i > 0) &&
3528 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
3529 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
3530 i--;
3531 str[i] = 0;
3532 }
3533 doc = xmlReadFile(xml, NULL, options);
3534 if (doc == NULL) {
3535 fprintf(stderr, "Failed to parse %s\n", xml);
3536 ret = 1;
3537 } else {
3538 xmlNodePtr root;
3539 const xmlChar *namespaces[22];
3540 int j;
3541 xmlNsPtr ns;
3542
3543 root = xmlDocGetRootElement(doc);
3544 for (ns = root->nsDef, j = 0;ns != NULL && j < 20;ns=ns->next) {
3545 namespaces[j++] = ns->href;
3546 namespaces[j++] = ns->prefix;
3547 }
3548 namespaces[j++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003549 namespaces[j] = NULL;
William M. Brackca15a542005-07-06 20:41:33 +00003550
3551 patternc = xmlPatterncompile((const xmlChar *) str, doc->dict,
3552 0, &namespaces[0]);
3553 if (patternc == NULL) {
3554 testErrorHandler(NULL,
3555 "Pattern %s failed to compile\n", str);
3556 xmlFreeDoc(doc);
3557 ret = 1;
3558 continue;
3559 }
3560 patstream = xmlPatternGetStreamCtxt(patternc);
3561 if (patstream != NULL) {
3562 ret = xmlStreamPush(patstream, NULL, NULL);
3563 if (ret < 0) {
3564 fprintf(stderr, "xmlStreamPush() failure\n");
3565 xmlFreeStreamCtxt(patstream);
3566 patstream = NULL;
3567 }
3568 }
3569 nb_tests++;
3570
3571 reader = xmlReaderWalker(doc);
3572 res = xmlTextReaderRead(reader);
3573 while (res == 1) {
3574 patternNode(o, reader, str, patternc, patstream);
3575 res = xmlTextReaderRead(reader);
3576 }
3577 if (res != 0) {
3578 fprintf(o, "%s : failed to parse\n", filename);
3579 }
3580 xmlFreeTextReader(reader);
3581 xmlFreeDoc(doc);
3582 xmlFreeStreamCtxt(patstream);
3583 patstream = NULL;
3584 xmlFreePattern(patternc);
3585
3586 }
3587 }
3588
3589 fclose(f);
3590 fclose(o);
3591
3592 ret = compareFiles(temp, result);
3593 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08003594 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00003595 ret = 1;
3596 }
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003597 if (temp != NULL) {
3598 unlink(temp);
3599 free(temp);
3600 }
William M. Brackca15a542005-07-06 20:41:33 +00003601 return(ret);
3602}
3603#endif /* READER */
3604#endif /* PATTERN */
3605#ifdef LIBXML_C14N_ENABLED
3606/************************************************************************
3607 * *
3608 * Canonicalization tests *
3609 * *
3610 ************************************************************************/
3611static xmlXPathObjectPtr
3612load_xpath_expr (xmlDocPtr parent_doc, const char* filename) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00003613 xmlXPathObjectPtr xpath;
William M. Brackca15a542005-07-06 20:41:33 +00003614 xmlDocPtr doc;
3615 xmlChar *expr;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003616 xmlXPathContextPtr ctx;
William M. Brackca15a542005-07-06 20:41:33 +00003617 xmlNodePtr node;
3618 xmlNsPtr ns;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003619
William M. Brackca15a542005-07-06 20:41:33 +00003620 /*
3621 * load XPath expr as a file
3622 */
3623 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3624 xmlSubstituteEntitiesDefault(1);
3625
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003626 doc = xmlReadFile(filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
William M. Brackca15a542005-07-06 20:41:33 +00003627 if (doc == NULL) {
3628 fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
3629 return(NULL);
3630 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003631
William M. Brackca15a542005-07-06 20:41:33 +00003632 /*
3633 * Check the document is of the right kind
Daniel Veillardaa6de472008-08-25 14:53:31 +00003634 */
William M. Brackca15a542005-07-06 20:41:33 +00003635 if(xmlDocGetRootElement(doc) == NULL) {
3636 fprintf(stderr,"Error: empty document for file \"%s\"\n", filename);
3637 xmlFreeDoc(doc);
3638 return(NULL);
3639 }
3640
3641 node = doc->children;
3642 while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) {
3643 node = node->next;
3644 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003645
3646 if(node == NULL) {
William M. Brackca15a542005-07-06 20:41:33 +00003647 fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename);
3648 xmlFreeDoc(doc);
3649 return(NULL);
3650 }
3651
3652 expr = xmlNodeGetContent(node);
3653 if(expr == NULL) {
3654 fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename);
3655 xmlFreeDoc(doc);
3656 return(NULL);
3657 }
3658
3659 ctx = xmlXPathNewContext(parent_doc);
3660 if(ctx == NULL) {
3661 fprintf(stderr,"Error: unable to create new context\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003662 xmlFree(expr);
3663 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003664 return(NULL);
3665 }
3666
3667 /*
3668 * Register namespaces
3669 */
3670 ns = node->nsDef;
3671 while(ns != NULL) {
3672 if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) {
3673 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 +00003674 xmlFree(expr);
3675 xmlXPathFreeContext(ctx);
3676 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003677 return(NULL);
3678 }
3679 ns = ns->next;
3680 }
3681
Daniel Veillardaa6de472008-08-25 14:53:31 +00003682 /*
William M. Brackca15a542005-07-06 20:41:33 +00003683 * Evaluate xpath
3684 */
3685 xpath = xmlXPathEvalExpression(expr, ctx);
3686 if(xpath == NULL) {
3687 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003688xmlFree(expr);
3689 xmlXPathFreeContext(ctx);
3690 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003691 return(NULL);
3692 }
3693
3694 /* print_xpath_nodes(xpath->nodesetval); */
3695
Daniel Veillardaa6de472008-08-25 14:53:31 +00003696 xmlFree(expr);
3697 xmlXPathFreeContext(ctx);
3698 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003699 return(xpath);
3700}
3701
3702/*
3703 * Macro used to grow the current buffer.
3704 */
3705#define xxx_growBufferReentrant() { \
3706 buffer_size *= 2; \
3707 buffer = (xmlChar **) \
Daniel Veillardaa6de472008-08-25 14:53:31 +00003708 xmlRealloc(buffer, buffer_size * sizeof(xmlChar*)); \
William M. Brackca15a542005-07-06 20:41:33 +00003709 if (buffer == NULL) { \
3710 perror("realloc failed"); \
3711 return(NULL); \
3712 } \
3713}
3714
3715static xmlChar **
3716parse_list(xmlChar *str) {
3717 xmlChar **buffer;
3718 xmlChar **out = NULL;
3719 int buffer_size = 0;
3720 int len;
3721
3722 if(str == NULL) {
3723 return(NULL);
3724 }
3725
3726 len = xmlStrlen(str);
3727 if((str[0] == '\'') && (str[len - 1] == '\'')) {
3728 str[len - 1] = '\0';
3729 str++;
William M. Brackca15a542005-07-06 20:41:33 +00003730 }
3731 /*
3732 * allocate an translation buffer.
3733 */
3734 buffer_size = 1000;
3735 buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*));
3736 if (buffer == NULL) {
3737 perror("malloc failed");
3738 return(NULL);
3739 }
3740 out = buffer;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003741
William M. Brackca15a542005-07-06 20:41:33 +00003742 while(*str != '\0') {
3743 if (out - buffer > buffer_size - 10) {
3744 int indx = out - buffer;
3745
3746 xxx_growBufferReentrant();
3747 out = &buffer[indx];
3748 }
3749 (*out++) = str;
3750 while(*str != ',' && *str != '\0') ++str;
3751 if(*str == ',') *(str++) = '\0';
3752 }
3753 (*out) = NULL;
3754 return buffer;
3755}
3756
Daniel Veillardaa6de472008-08-25 14:53:31 +00003757static int
Aleksey Sanin83868242009-07-09 10:26:22 +02003758c14nRunTest(const char* xml_filename, int with_comments, int mode,
William M. Brackca15a542005-07-06 20:41:33 +00003759 const char* xpath_filename, const char *ns_filename,
3760 const char* result_file) {
3761 xmlDocPtr doc;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003762 xmlXPathObjectPtr xpath = NULL;
William M. Brackca15a542005-07-06 20:41:33 +00003763 xmlChar *result = NULL;
3764 int ret;
3765 xmlChar **inclusive_namespaces = NULL;
3766 const char *nslist = NULL;
3767 int nssize;
3768
3769
3770 /*
3771 * build an XML tree from a the file; we need to add default
3772 * attributes and resolve all character and entities references
3773 */
3774 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3775 xmlSubstituteEntitiesDefault(1);
3776
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003777 doc = xmlReadFile(xml_filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
William M. Brackca15a542005-07-06 20:41:33 +00003778 if (doc == NULL) {
3779 fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename);
3780 return(-1);
3781 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003782
William M. Brackca15a542005-07-06 20:41:33 +00003783 /*
3784 * Check the document is of the right kind
Daniel Veillardaa6de472008-08-25 14:53:31 +00003785 */
William M. Brackca15a542005-07-06 20:41:33 +00003786 if(xmlDocGetRootElement(doc) == NULL) {
3787 fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename);
3788 xmlFreeDoc(doc);
3789 return(-1);
3790 }
3791
Daniel Veillardaa6de472008-08-25 14:53:31 +00003792 /*
3793 * load xpath file if specified
William M. Brackca15a542005-07-06 20:41:33 +00003794 */
3795 if(xpath_filename) {
3796 xpath = load_xpath_expr(doc, xpath_filename);
3797 if(xpath == NULL) {
3798 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003799 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003800 return(-1);
3801 }
3802 }
3803
3804 if (ns_filename != NULL) {
3805 if (loadMem(ns_filename, &nslist, &nssize)) {
3806 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3807 if(xpath != NULL) xmlXPathFreeObject(xpath);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003808 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003809 return(-1);
3810 }
3811 inclusive_namespaces = parse_list((xmlChar *) nslist);
3812 }
3813
3814 /*
3815 * Canonical form
Daniel Veillardaa6de472008-08-25 14:53:31 +00003816 */
William M. Brackca15a542005-07-06 20:41:33 +00003817 /* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */
Daniel Veillardaa6de472008-08-25 14:53:31 +00003818 ret = xmlC14NDocDumpMemory(doc,
3819 (xpath) ? xpath->nodesetval : NULL,
Aleksey Sanin83868242009-07-09 10:26:22 +02003820 mode, inclusive_namespaces,
William M. Brackca15a542005-07-06 20:41:33 +00003821 with_comments, &result);
3822 if (ret >= 0) {
3823 if(result != NULL) {
3824 if (compareFileMem(result_file, (const char *) result, ret)) {
3825 fprintf(stderr, "Result mismatch for %s\n", xml_filename);
Aleksey Sanin83868242009-07-09 10:26:22 +02003826 fprintf(stderr, "RESULT:\n%s\n", (const char*)result);
William M. Brackca15a542005-07-06 20:41:33 +00003827 ret = -1;
3828 }
3829 }
3830 } else {
3831 fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret);
3832 ret = -1;
3833 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003834
William M. Brackca15a542005-07-06 20:41:33 +00003835 /*
3836 * Cleanup
Daniel Veillardaa6de472008-08-25 14:53:31 +00003837 */
William M. Brackca15a542005-07-06 20:41:33 +00003838 if (result != NULL) xmlFree(result);
3839 if(xpath != NULL) xmlXPathFreeObject(xpath);
3840 if (inclusive_namespaces != NULL) xmlFree(inclusive_namespaces);
3841 if (nslist != NULL) free((char *) nslist);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003842 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003843
3844 return(ret);
3845}
3846
3847static int
Aleksey Sanin83868242009-07-09 10:26:22 +02003848c14nCommonTest(const char *filename, int with_comments, int mode,
William M. Brackca15a542005-07-06 20:41:33 +00003849 const char *subdir) {
3850 char buf[500];
3851 char prefix[500];
3852 const char *base;
3853 int len;
3854 char *result = NULL;
3855 char *xpath = NULL;
3856 char *ns = NULL;
3857 int ret = 0;
3858
3859 base = baseFilename(filename);
3860 len = strlen(base);
3861 len -= 4;
3862 memcpy(prefix, base, len);
3863 prefix[len] = 0;
3864
3865 snprintf(buf, 499, "result/c14n/%s/%s", subdir,prefix);
David Kilzer5c373822016-05-22 09:58:30 +08003866 if (!checkTestFile(buf) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00003867 fprintf(stderr, "Missing result file %s", buf);
3868 return(-1);
3869 }
3870 result = strdup(buf);
3871 snprintf(buf, 499, "test/c14n/%s/%s.xpath", subdir,prefix);
3872 if (checkTestFile(buf)) {
3873 xpath = strdup(buf);
3874 }
3875 snprintf(buf, 499, "test/c14n/%s/%s.ns", subdir,prefix);
3876 if (checkTestFile(buf)) {
3877 ns = strdup(buf);
3878 }
3879
3880 nb_tests++;
Aleksey Sanin83868242009-07-09 10:26:22 +02003881 if (c14nRunTest(filename, with_comments, mode,
William M. Brackca15a542005-07-06 20:41:33 +00003882 xpath, ns, result) < 0)
3883 ret = 1;
3884
3885 if (result != NULL) free(result);
3886 if (xpath != NULL) free(xpath);
3887 if (ns != NULL) free(ns);
3888 return(ret);
3889}
3890
3891static int
3892c14nWithCommentTest(const char *filename,
3893 const char *resul ATTRIBUTE_UNUSED,
3894 const char *err ATTRIBUTE_UNUSED,
3895 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003896 return(c14nCommonTest(filename, 1, XML_C14N_1_0, "with-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003897}
3898static int
3899c14nWithoutCommentTest(const char *filename,
3900 const char *resul ATTRIBUTE_UNUSED,
3901 const char *err ATTRIBUTE_UNUSED,
3902 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003903 return(c14nCommonTest(filename, 0, XML_C14N_1_0, "without-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003904}
3905static int
3906c14nExcWithoutCommentTest(const char *filename,
3907 const char *resul ATTRIBUTE_UNUSED,
3908 const char *err ATTRIBUTE_UNUSED,
3909 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003910 return(c14nCommonTest(filename, 0, XML_C14N_EXCLUSIVE_1_0, "exc-without-comments"));
3911}
3912static int
3913c14n11WithoutCommentTest(const char *filename,
3914 const char *resul ATTRIBUTE_UNUSED,
3915 const char *err ATTRIBUTE_UNUSED,
3916 int options ATTRIBUTE_UNUSED) {
3917 return(c14nCommonTest(filename, 0, XML_C14N_1_1, "1-1-without-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003918}
3919#endif
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003920#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) && defined (LIBXML_SAX1_ENABLED)
William M. Brackca15a542005-07-06 20:41:33 +00003921/************************************************************************
3922 * *
3923 * Catalog and threads test *
3924 * *
3925 ************************************************************************/
3926
3927/*
3928 * mostly a cut and paste from testThreads.c
3929 */
3930#define MAX_ARGC 20
3931
3932static const char *catalog = "test/threads/complex.xml";
3933static const char *testfiles[] = {
3934 "test/threads/abc.xml",
3935 "test/threads/acb.xml",
3936 "test/threads/bac.xml",
3937 "test/threads/bca.xml",
3938 "test/threads/cab.xml",
3939 "test/threads/cba.xml",
3940 "test/threads/invalid.xml",
3941};
3942
Daniel Veillard24505b02005-07-28 23:49:35 +00003943static const char *Okay = "OK";
3944static const char *Failed = "Failed";
William M. Brackca15a542005-07-06 20:41:33 +00003945
3946#ifndef xmlDoValidityCheckingDefaultValue
3947#error xmlDoValidityCheckingDefaultValue is not a macro
3948#endif
3949#ifndef xmlGenericErrorContext
3950#error xmlGenericErrorContext is not a macro
3951#endif
3952
3953static void *
3954thread_specific_data(void *private_data)
3955{
3956 xmlDocPtr myDoc;
3957 const char *filename = (const char *) private_data;
3958 int okay = 1;
3959
3960 if (!strcmp(filename, "test/threads/invalid.xml")) {
3961 xmlDoValidityCheckingDefaultValue = 0;
3962 xmlGenericErrorContext = stdout;
3963 } else {
3964 xmlDoValidityCheckingDefaultValue = 1;
3965 xmlGenericErrorContext = stderr;
3966 }
3967 myDoc = xmlParseFile(filename);
3968 if (myDoc) {
3969 xmlFreeDoc(myDoc);
3970 } else {
3971 printf("parse failed\n");
3972 okay = 0;
3973 }
3974 if (!strcmp(filename, "test/threads/invalid.xml")) {
3975 if (xmlDoValidityCheckingDefaultValue != 0) {
3976 printf("ValidityCheckingDefaultValue override failed\n");
3977 okay = 0;
3978 }
3979 if (xmlGenericErrorContext != stdout) {
3980 printf("xmlGenericErrorContext override failed\n");
3981 okay = 0;
3982 }
3983 } else {
3984 if (xmlDoValidityCheckingDefaultValue != 1) {
3985 printf("ValidityCheckingDefaultValue override failed\n");
3986 okay = 0;
3987 }
3988 if (xmlGenericErrorContext != stderr) {
3989 printf("xmlGenericErrorContext override failed\n");
3990 okay = 0;
3991 }
3992 }
3993 if (okay == 0)
3994 return ((void *) Failed);
3995 return ((void *) Okay);
3996}
3997
Daniel Richard G495a73d2012-08-07 10:14:56 +08003998#if defined WIN32
William M. Brackca15a542005-07-06 20:41:33 +00003999#include <windows.h>
4000#include <string.h>
4001
4002#define TEST_REPEAT_COUNT 500
4003
4004static HANDLE tid[MAX_ARGC];
4005
4006static DWORD WINAPI
4007win32_thread_specific_data(void *private_data)
4008{
4009 return((DWORD) thread_specific_data(private_data));
4010}
4011
4012static int
4013testThread(void)
4014{
4015 unsigned int i, repeat;
4016 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
4017 DWORD results[MAX_ARGC];
4018 BOOL ret;
4019 int res = 0;
4020
4021 xmlInitParser();
4022 for (repeat = 0; repeat < TEST_REPEAT_COUNT; repeat++) {
4023 xmlLoadCatalog(catalog);
4024 nb_tests++;
4025
4026 for (i = 0; i < num_threads; i++) {
4027 results[i] = 0;
4028 tid[i] = (HANDLE) - 1;
4029 }
4030
4031 for (i = 0; i < num_threads; i++) {
4032 DWORD useless;
4033
4034 tid[i] = CreateThread(NULL, 0,
Daniel Veillardaa6de472008-08-25 14:53:31 +00004035 win32_thread_specific_data,
William M. Brackca15a542005-07-06 20:41:33 +00004036 (void *) testfiles[i], 0,
4037 &useless);
4038 if (tid[i] == NULL) {
4039 fprintf(stderr, "CreateThread failed\n");
4040 return(1);
4041 }
4042 }
4043
4044 if (WaitForMultipleObjects(num_threads, tid, TRUE, INFINITE) ==
4045 WAIT_FAILED) {
4046 fprintf(stderr, "WaitForMultipleObjects failed\n");
4047 return(1);
4048 }
4049
4050 for (i = 0; i < num_threads; i++) {
4051 ret = GetExitCodeThread(tid[i], &results[i]);
4052 if (ret == 0) {
4053 fprintf(stderr, "GetExitCodeThread failed\n");
4054 return(1);
4055 }
4056 CloseHandle(tid[i]);
4057 }
4058
4059 xmlCatalogCleanup();
4060 for (i = 0; i < num_threads; i++) {
4061 if (results[i] != (DWORD) Okay) {
4062 fprintf(stderr, "Thread %d handling %s failed\n",
4063 i, testfiles[i]);
4064 res = 1;
4065 }
4066 }
4067 }
4068
4069 return (res);
4070}
4071
4072#elif defined __BEOS__
4073#include <OS.h>
4074
4075static thread_id tid[MAX_ARGC];
4076
4077static int
4078testThread(void)
4079{
4080 unsigned int i, repeat;
4081 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
4082 void *results[MAX_ARGC];
4083 status_t ret;
4084 int res = 0;
4085
4086 xmlInitParser();
4087 for (repeat = 0; repeat < 500; repeat++) {
4088 xmlLoadCatalog(catalog);
4089 for (i = 0; i < num_threads; i++) {
4090 results[i] = NULL;
4091 tid[i] = (thread_id) - 1;
4092 }
4093 for (i = 0; i < num_threads; i++) {
4094 tid[i] =
4095 spawn_thread(thread_specific_data, "xmlTestThread",
4096 B_NORMAL_PRIORITY, (void *) testfiles[i]);
4097 if (tid[i] < B_OK) {
4098 fprintf(stderr, "beos_thread_create failed\n");
4099 return (1);
4100 }
4101 printf("beos_thread_create %d -> %d\n", i, tid[i]);
4102 }
4103 for (i = 0; i < num_threads; i++) {
4104 ret = wait_for_thread(tid[i], &results[i]);
4105 printf("beos_thread_wait %d -> %d\n", i, ret);
4106 if (ret != B_OK) {
4107 fprintf(stderr, "beos_thread_wait failed\n");
4108 return (1);
4109 }
4110 }
4111
4112 xmlCatalogCleanup();
4113 ret = B_OK;
4114 for (i = 0; i < num_threads; i++)
4115 if (results[i] != (void *) Okay) {
4116 printf("Thread %d handling %s failed\n", i, testfiles[i]);
4117 ret = B_ERROR;
4118 }
4119 }
4120 if (ret != B_OK)
4121 return(1);
4122 return (0);
4123}
Daniel Richard G495a73d2012-08-07 10:14:56 +08004124
4125#elif defined HAVE_PTHREAD_H
4126#include <pthread.h>
4127
4128static pthread_t tid[MAX_ARGC];
4129
4130static int
4131testThread(void)
4132{
4133 unsigned int i, repeat;
4134 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
4135 void *results[MAX_ARGC];
4136 int ret;
4137 int res = 0;
4138
4139 xmlInitParser();
4140
4141 for (repeat = 0; repeat < 500; repeat++) {
4142 xmlLoadCatalog(catalog);
4143 nb_tests++;
4144
4145 for (i = 0; i < num_threads; i++) {
4146 results[i] = NULL;
4147 tid[i] = (pthread_t) - 1;
4148 }
4149
4150 for (i = 0; i < num_threads; i++) {
4151 ret = pthread_create(&tid[i], 0, thread_specific_data,
4152 (void *) testfiles[i]);
4153 if (ret != 0) {
4154 fprintf(stderr, "pthread_create failed\n");
4155 return (1);
4156 }
4157 }
4158 for (i = 0; i < num_threads; i++) {
4159 ret = pthread_join(tid[i], &results[i]);
4160 if (ret != 0) {
4161 fprintf(stderr, "pthread_join failed\n");
4162 return (1);
4163 }
4164 }
4165
4166 xmlCatalogCleanup();
4167 for (i = 0; i < num_threads; i++)
4168 if (results[i] != (void *) Okay) {
4169 fprintf(stderr, "Thread %d handling %s failed\n",
4170 i, testfiles[i]);
4171 res = 1;
4172 }
4173 }
4174 return (res);
4175}
4176
William M. Brackca15a542005-07-06 20:41:33 +00004177#else
4178static int
4179testThread(void)
4180{
4181 fprintf(stderr,
4182 "Specific platform thread support not detected\n");
4183 return (-1);
4184}
4185#endif
Daniel Veillardaa6de472008-08-25 14:53:31 +00004186static int
William M. Brackca15a542005-07-06 20:41:33 +00004187threadsTest(const char *filename ATTRIBUTE_UNUSED,
4188 const char *resul ATTRIBUTE_UNUSED,
4189 const char *err ATTRIBUTE_UNUSED,
4190 int options ATTRIBUTE_UNUSED) {
4191 return(testThread());
4192}
4193#endif
4194/************************************************************************
4195 * *
4196 * Tests Descriptions *
4197 * *
4198 ************************************************************************/
4199
4200static
4201testDesc testDescriptions[] = {
4202 { "XML regression tests" ,
4203 oldParseTest, "./test/*", "result/", "", NULL,
4204 0 },
4205 { "XML regression tests on memory" ,
4206 memParseTest, "./test/*", "result/", "", NULL,
4207 0 },
4208 { "XML entity subst regression tests" ,
4209 noentParseTest, "./test/*", "result/noent/", "", NULL,
4210 XML_PARSE_NOENT },
4211 { "XML Namespaces regression tests",
4212 errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err",
4213 0 },
4214 { "Error cases regression tests",
4215 errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err",
4216 0 },
4217#ifdef LIBXML_READER_ENABLED
4218 { "Error cases stream regression tests",
4219 streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str",
4220 0 },
4221 { "Reader regression tests",
4222 streamParseTest, "./test/*", "result/", ".rdr", NULL,
4223 0 },
4224 { "Reader entities substitution regression tests",
4225 streamParseTest, "./test/*", "result/", ".rde", NULL,
4226 XML_PARSE_NOENT },
4227 { "Reader on memory regression tests",
4228 streamMemParseTest, "./test/*", "result/", ".rdr", NULL,
4229 0 },
4230 { "Walker regression tests",
4231 walkerParseTest, "./test/*", "result/", ".rdr", NULL,
4232 0 },
4233#endif
4234#ifdef LIBXML_SAX1_ENABLED
4235 { "SAX1 callbacks regression tests" ,
4236 saxParseTest, "./test/*", "result/", ".sax", NULL,
4237 XML_PARSE_SAX1 },
4238 { "SAX2 callbacks regression tests" ,
4239 saxParseTest, "./test/*", "result/", ".sax2", NULL,
4240 0 },
4241#endif
4242#ifdef LIBXML_PUSH_ENABLED
4243 { "XML push regression tests" ,
4244 pushParseTest, "./test/*", "result/", "", NULL,
4245 0 },
4246#endif
4247#ifdef LIBXML_HTML_ENABLED
4248 { "HTML regression tests" ,
4249 errParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4250 XML_PARSE_HTML },
4251#ifdef LIBXML_PUSH_ENABLED
4252 { "Push HTML regression tests" ,
4253 pushParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4254 XML_PARSE_HTML },
4255#endif
4256#ifdef LIBXML_SAX1_ENABLED
4257 { "HTML SAX regression tests" ,
4258 saxParseTest, "./test/HTML/*", "result/HTML/", ".sax", NULL,
4259 XML_PARSE_HTML },
4260#endif
4261#endif
4262#ifdef LIBXML_VALID_ENABLED
4263 { "Valid documents regression tests" ,
4264 errParseTest, "./test/VCM/*", NULL, NULL, NULL,
4265 XML_PARSE_DTDVALID },
4266 { "Validity checking regression tests" ,
4267 errParseTest, "./test/VC/*", "result/VC/", NULL, "",
4268 XML_PARSE_DTDVALID },
Daniel Veillarda7982ce2012-10-25 15:39:39 +08004269#ifdef LIBXML_READER_ENABLED
4270 { "Streaming validity checking regression tests" ,
4271 streamParseTest, "./test/valid/*.xml", "result/valid/", NULL, ".err.rdr",
4272 XML_PARSE_DTDVALID },
4273 { "Streaming validity error checking regression tests" ,
4274 streamParseTest, "./test/VC/*", "result/VC/", NULL, ".rdr",
4275 XML_PARSE_DTDVALID },
4276#endif
William M. Brackca15a542005-07-06 20:41:33 +00004277 { "General documents valid regression tests" ,
4278 errParseTest, "./test/valid/*", "result/valid/", "", ".err",
4279 XML_PARSE_DTDVALID },
4280#endif
4281#ifdef LIBXML_XINCLUDE_ENABLED
4282 { "XInclude regression tests" ,
4283 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4284 /* Ignore errors at this point ".err", */
4285 XML_PARSE_XINCLUDE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004286#ifdef LIBXML_READER_ENABLED
William M. Brackca15a542005-07-06 20:41:33 +00004287 { "XInclude xmlReader regression tests",
4288 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4289 /* Ignore errors at this point ".err", */
4290 NULL, XML_PARSE_XINCLUDE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004291#endif
William M. Brackca15a542005-07-06 20:41:33 +00004292 { "XInclude regression tests stripping include nodes" ,
4293 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4294 /* Ignore errors at this point ".err", */
4295 XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004296#ifdef LIBXML_READER_ENABLED
William M. Brackca15a542005-07-06 20:41:33 +00004297 { "XInclude xmlReader regression tests stripping include nodes",
4298 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4299 /* Ignore errors at this point ".err", */
4300 NULL, XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
4301#endif
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004302#endif
William M. Brackca15a542005-07-06 20:41:33 +00004303#ifdef LIBXML_XPATH_ENABLED
4304#ifdef LIBXML_DEBUG_ENABLED
4305 { "XPath expressions regression tests" ,
4306 xpathExprTest, "./test/XPath/expr/*", "result/XPath/expr/", "", NULL,
4307 0 },
4308 { "XPath document queries regression tests" ,
4309 xpathDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4310 0 },
4311#ifdef LIBXML_XPTR_ENABLED
4312 { "XPointer document queries regression tests" ,
4313 xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4314 0 },
4315#endif
4316 { "xml:id regression tests" ,
4317 xmlidDocTest, "./test/xmlid/*", "result/xmlid/", "", ".err",
4318 0 },
4319#endif
4320#endif
4321 { "URI parsing tests" ,
4322 uriParseTest, "./test/URI/*.uri", "result/URI/", "", NULL,
4323 0 },
4324 { "URI base composition tests" ,
4325 uriBaseTest, "./test/URI/*.data", "result/URI/", "", NULL,
4326 0 },
Daniel Veillard336a8e12005-08-07 10:46:19 +00004327 { "Path URI conversion tests" ,
4328 uriPathTest, NULL, NULL, NULL, NULL,
4329 0 },
William M. Brackca15a542005-07-06 20:41:33 +00004330#ifdef LIBXML_SCHEMAS_ENABLED
4331 { "Schemas regression tests" ,
4332 schemasTest, "./test/schemas/*_*.xsd", NULL, NULL, NULL,
4333 0 },
4334 { "Relax-NG regression tests" ,
4335 rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4336 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4337#ifdef LIBXML_READER_ENABLED
4338 { "Relax-NG streaming regression tests" ,
4339 rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4340 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4341#endif
4342#endif
4343#ifdef LIBXML_PATTERN_ENABLED
4344#ifdef LIBXML_READER_ENABLED
4345 { "Pattern regression tests" ,
4346 patternTest, "./test/pattern/*.pat", "result/pattern/", NULL, NULL,
4347 0 },
4348#endif
4349#endif
4350#ifdef LIBXML_C14N_ENABLED
4351 { "C14N with comments regression tests" ,
4352 c14nWithCommentTest, "./test/c14n/with-comments/*.xml", NULL, NULL, NULL,
4353 0 },
4354 { "C14N without comments regression tests" ,
4355 c14nWithoutCommentTest, "./test/c14n/without-comments/*.xml", NULL, NULL, NULL,
4356 0 },
4357 { "C14N exclusive without comments regression tests" ,
4358 c14nExcWithoutCommentTest, "./test/c14n/exc-without-comments/*.xml", NULL, NULL, NULL,
4359 0 },
Aleksey Sanin83868242009-07-09 10:26:22 +02004360 { "C14N 1.1 without comments regression tests" ,
4361 c14n11WithoutCommentTest, "./test/c14n/1-1-without-comments/*.xml", NULL, NULL, NULL,
4362 0 },
William M. Brackca15a542005-07-06 20:41:33 +00004363#endif
Daniel Veillardbca3ad22005-08-23 22:14:02 +00004364#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) && defined(LIBXML_SAX1_ENABLED)
William M. Brackca15a542005-07-06 20:41:33 +00004365 { "Catalog and Threads regression tests" ,
4366 threadsTest, NULL, NULL, NULL, NULL,
4367 0 },
4368#endif
4369 {NULL, NULL, NULL, NULL, NULL, NULL, 0}
4370};
4371
4372/************************************************************************
4373 * *
4374 * The main code driving the tests *
4375 * *
4376 ************************************************************************/
4377
4378static int
4379launchTests(testDescPtr tst) {
4380 int res = 0, err = 0;
4381 size_t i;
4382 char *result;
4383 char *error;
4384 int mem;
4385
4386 if (tst == NULL) return(-1);
4387 if (tst->in != NULL) {
4388 glob_t globbuf;
4389
4390 globbuf.gl_offs = 0;
4391 glob(tst->in, GLOB_DOOFFS, NULL, &globbuf);
4392 for (i = 0;i < globbuf.gl_pathc;i++) {
4393 if (!checkTestFile(globbuf.gl_pathv[i]))
4394 continue;
4395 if (tst->suffix != NULL) {
4396 result = resultFilename(globbuf.gl_pathv[i], tst->out,
4397 tst->suffix);
4398 if (result == NULL) {
4399 fprintf(stderr, "Out of memory !\n");
4400 fatalError();
4401 }
4402 } else {
4403 result = NULL;
4404 }
4405 if (tst->err != NULL) {
4406 error = resultFilename(globbuf.gl_pathv[i], tst->out,
4407 tst->err);
4408 if (error == NULL) {
4409 fprintf(stderr, "Out of memory !\n");
4410 fatalError();
4411 }
4412 } else {
4413 error = NULL;
4414 }
David Kilzer5c373822016-05-22 09:58:30 +08004415 if ((result) &&(!checkTestFile(result)) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00004416 fprintf(stderr, "Missing result file %s\n", result);
David Kilzer5c373822016-05-22 09:58:30 +08004417 } else if ((error) &&(!checkTestFile(error)) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00004418 fprintf(stderr, "Missing error file %s\n", error);
4419 } else {
4420 mem = xmlMemUsed();
4421 extraMemoryFromResolver = 0;
4422 testErrorsSize = 0;
4423 testErrors[0] = 0;
4424 res = tst->func(globbuf.gl_pathv[i], result, error,
Daniel Veillard8874b942005-08-25 13:19:21 +00004425 tst->options | XML_PARSE_COMPACT);
William M. Brackca15a542005-07-06 20:41:33 +00004426 xmlResetLastError();
4427 if (res != 0) {
4428 fprintf(stderr, "File %s generated an error\n",
4429 globbuf.gl_pathv[i]);
4430 nb_errors++;
4431 err++;
4432 }
4433 else if (xmlMemUsed() != mem) {
4434 if ((xmlMemUsed() != mem) &&
4435 (extraMemoryFromResolver == 0)) {
4436 fprintf(stderr, "File %s leaked %d bytes\n",
4437 globbuf.gl_pathv[i], xmlMemUsed() - mem);
4438 nb_leaks++;
4439 err++;
4440 }
4441 }
4442 testErrorsSize = 0;
4443 }
4444 if (result)
4445 free(result);
4446 if (error)
4447 free(error);
4448 }
4449 globfree(&globbuf);
4450 } else {
4451 testErrorsSize = 0;
4452 testErrors[0] = 0;
4453 extraMemoryFromResolver = 0;
4454 res = tst->func(NULL, NULL, NULL, tst->options);
4455 if (res != 0) {
4456 nb_errors++;
4457 err++;
4458 }
4459 }
4460 return(err);
4461}
4462
Daniel Veillarddb68b742005-07-30 13:18:24 +00004463static int verbose = 0;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004464static int tests_quiet = 0;
Daniel Veillarddb68b742005-07-30 13:18:24 +00004465
4466static int
4467runtest(int i) {
4468 int ret = 0, res;
4469 int old_errors, old_tests, old_leaks;
4470
4471 old_errors = nb_errors;
4472 old_tests = nb_tests;
4473 old_leaks = nb_leaks;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004474 if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
Daniel Veillarddb68b742005-07-30 13:18:24 +00004475 printf("## %s\n", testDescriptions[i].desc);
4476 res = launchTests(&testDescriptions[i]);
4477 if (res != 0)
4478 ret++;
4479 if (verbose) {
4480 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
4481 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
4482 else
4483 printf("Ran %d tests, %d errors, %d leaks\n",
4484 nb_tests - old_tests,
4485 nb_errors - old_errors,
4486 nb_leaks - old_leaks);
4487 }
4488 return(ret);
4489}
4490
William M. Brackca15a542005-07-06 20:41:33 +00004491int
4492main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
Daniel Veillarddb68b742005-07-30 13:18:24 +00004493 int i, a, ret = 0;
4494 int subset = 0;
William M. Brackca15a542005-07-06 20:41:33 +00004495
4496 initializeLibxml2();
4497
Daniel Veillarddb68b742005-07-30 13:18:24 +00004498 for (a = 1; a < argc;a++) {
4499 if (!strcmp(argv[a], "-v"))
4500 verbose = 1;
David Kilzer5c373822016-05-22 09:58:30 +08004501 else if (!strcmp(argv[a], "-u"))
4502 update_results = 1;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004503 else if (!strcmp(argv[a], "-quiet"))
4504 tests_quiet = 1;
Daniel Veillarddb68b742005-07-30 13:18:24 +00004505 else {
4506 for (i = 0; testDescriptions[i].func != NULL; i++) {
4507 if (strstr(testDescriptions[i].desc, argv[a])) {
4508 ret += runtest(i);
4509 subset++;
4510 }
4511 }
4512 }
4513 }
4514 if (subset == 0) {
4515 for (i = 0; testDescriptions[i].func != NULL; i++) {
4516 ret += runtest(i);
William M. Brackca15a542005-07-06 20:41:33 +00004517 }
4518 }
4519 if ((nb_errors == 0) && (nb_leaks == 0)) {
4520 ret = 0;
4521 printf("Total %d tests, no errors\n",
4522 nb_tests);
4523 } else {
4524 ret = 1;
4525 printf("Total %d tests, %d errors, %d leaks\n",
4526 nb_tests, nb_errors, nb_leaks);
4527 }
4528 xmlCleanupParser();
4529 xmlMemoryDump();
4530
4531 return(ret);
4532}
4533
4534#else /* ! LIBXML_OUTPUT_ENABLED */
4535int
4536main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
4537 fprintf(stderr, "runtest requires output to be enabled in libxml2\n");
4538 return(1);
4539}
4540#endif