blob: 03816a8f5ef66d0abf7a30e9958410355da4f502 [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>
Nick Wellnhoferdbaab1f2017-06-16 21:38:57 +020026#include <libxml/parserInternals.h>
William M. Brackca15a542005-07-06 20:41:33 +000027#include <libxml/tree.h>
28#include <libxml/uri.h>
29
30#ifdef LIBXML_OUTPUT_ENABLED
31#ifdef LIBXML_READER_ENABLED
32#include <libxml/xmlreader.h>
33#endif
34
35#ifdef LIBXML_XINCLUDE_ENABLED
36#include <libxml/xinclude.h>
37#endif
38
39#ifdef LIBXML_XPATH_ENABLED
40#include <libxml/xpath.h>
41#include <libxml/xpathInternals.h>
42#ifdef LIBXML_XPTR_ENABLED
43#include <libxml/xpointer.h>
44#endif
45#endif
46
47#ifdef LIBXML_SCHEMAS_ENABLED
48#include <libxml/relaxng.h>
49#include <libxml/xmlschemas.h>
50#include <libxml/xmlschemastypes.h>
51#endif
52
53#ifdef LIBXML_PATTERN_ENABLED
54#include <libxml/pattern.h>
55#endif
56
57#ifdef LIBXML_C14N_ENABLED
58#include <libxml/c14n.h>
59#endif
60
61#ifdef LIBXML_HTML_ENABLED
62#include <libxml/HTMLparser.h>
63#include <libxml/HTMLtree.h>
64
65/*
66 * pseudo flag for the unification of HTML and XML tests
67 */
68#define XML_PARSE_HTML 1 << 24
69#endif
70
71#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
72#include <libxml/globals.h>
73#include <libxml/threads.h>
74#include <libxml/parser.h>
75#include <libxml/catalog.h>
76#include <string.h>
77#endif
78
79/*
80 * O_BINARY is just for Windows compatibility - if it isn't defined
81 * on this system, avoid any compilation error
82 */
83#ifdef O_BINARY
84#define RD_FLAGS O_RDONLY | O_BINARY
David Kilzer5c373822016-05-22 09:58:30 +080085#define WR_FLAGS O_WRONLY | O_CREAT | O_TRUNC | O_BINARY
William M. Brackca15a542005-07-06 20:41:33 +000086#else
David Kilzer5c373822016-05-22 09:58:30 +080087#define RD_FLAGS O_RDONLY
88#define WR_FLAGS O_WRONLY | O_CREAT | O_TRUNC
William M. Brackca15a542005-07-06 20:41:33 +000089#endif
90
91typedef int (*functest) (const char *filename, const char *result,
92 const char *error, int options);
93
94typedef struct testDesc testDesc;
95typedef testDesc *testDescPtr;
96struct testDesc {
97 const char *desc; /* descripton of the test */
98 functest func; /* function implementing the test */
99 const char *in; /* glob to path for input files */
100 const char *out; /* output directory */
101 const char *suffix;/* suffix for output files */
102 const char *err; /* suffix for error output files */
103 int options; /* parser options for the test */
104};
105
David Kilzer5c373822016-05-22 09:58:30 +0800106static int update_results = 0;
William M. Brackca15a542005-07-06 20:41:33 +0000107static int checkTestFile(const char *filename);
108
109#if defined(_WIN32) && !defined(__CYGWIN__)
110
111#include <windows.h>
112#include <io.h>
113
114typedef struct
115{
116 size_t gl_pathc; /* Count of paths matched so far */
117 char **gl_pathv; /* List of matched pathnames. */
118 size_t gl_offs; /* Slots to reserve in 'gl_pathv'. */
119} glob_t;
120
121#define GLOB_DOOFFS 0
122static int glob(const char *pattern, int flags,
123 int errfunc(const char *epath, int eerrno),
124 glob_t *pglob) {
125 glob_t *ret;
126 WIN32_FIND_DATA FindFileData;
127 HANDLE hFind;
128 unsigned int nb_paths = 0;
129 char directory[500];
130 int len;
131
132 if ((pattern == NULL) || (pglob == NULL)) return(-1);
Daniel Veillardaa6de472008-08-25 14:53:31 +0000133
William M. Brackca15a542005-07-06 20:41:33 +0000134 strncpy(directory, pattern, 499);
135 for (len = strlen(directory);len >= 0;len--) {
136 if (directory[len] == '/') {
137 len++;
138 directory[len] = 0;
139 break;
140 }
141 }
142 if (len <= 0)
143 len = 0;
144
Daniel Veillardaa6de472008-08-25 14:53:31 +0000145
William M. Brackca15a542005-07-06 20:41:33 +0000146 ret = pglob;
147 memset(ret, 0, sizeof(glob_t));
Daniel Veillardaa6de472008-08-25 14:53:31 +0000148
William M. Brackca15a542005-07-06 20:41:33 +0000149 hFind = FindFirstFileA(pattern, &FindFileData);
Daniel Veillardaa6de472008-08-25 14:53:31 +0000150 if (hFind == INVALID_HANDLE_VALUE)
William M. Brackca15a542005-07-06 20:41:33 +0000151 return(0);
152 nb_paths = 20;
153 ret->gl_pathv = (char **) malloc(nb_paths * sizeof(char *));
154 if (ret->gl_pathv == NULL) {
155 FindClose(hFind);
156 return(-1);
157 }
158 strncpy(directory + len, FindFileData.cFileName, 499 - len);
159 ret->gl_pathv[ret->gl_pathc] = strdup(directory);
160 if (ret->gl_pathv[ret->gl_pathc] == NULL)
161 goto done;
162 ret->gl_pathc++;
163 while(FindNextFileA(hFind, &FindFileData)) {
164 if (FindFileData.cFileName[0] == '.')
165 continue;
166 if (ret->gl_pathc + 2 > nb_paths) {
167 char **tmp = realloc(ret->gl_pathv, nb_paths * 2 * sizeof(char *));
168 if (tmp == NULL)
169 break;
170 ret->gl_pathv = tmp;
171 nb_paths *= 2;
172 }
173 strncpy(directory + len, FindFileData.cFileName, 499 - len);
174 ret->gl_pathv[ret->gl_pathc] = strdup(directory);
175 if (ret->gl_pathv[ret->gl_pathc] == NULL)
176 break;
177 ret->gl_pathc++;
178 }
179 ret->gl_pathv[ret->gl_pathc] = NULL;
180
181done:
182 FindClose(hFind);
183 return(0);
184}
Daniel Veillardaa6de472008-08-25 14:53:31 +0000185
William M. Brackca15a542005-07-06 20:41:33 +0000186
187
188static void globfree(glob_t *pglob) {
189 unsigned int i;
190 if (pglob == NULL)
191 return;
Daniel Veillardaa6de472008-08-25 14:53:31 +0000192
William M. Brackca15a542005-07-06 20:41:33 +0000193 for (i = 0;i < pglob->gl_pathc;i++) {
194 if (pglob->gl_pathv[i] != NULL)
195 free(pglob->gl_pathv[i]);
196 }
197}
Daniel Veillard22030ef2012-05-23 15:52:45 +0800198
William M. Brackca15a542005-07-06 20:41:33 +0000199#else
200#include <glob.h>
201#endif
202
203/************************************************************************
204 * *
205 * Libxml2 specific routines *
206 * *
207 ************************************************************************/
208
209static int nb_tests = 0;
210static int nb_errors = 0;
211static int nb_leaks = 0;
William M. Brackca15a542005-07-06 20:41:33 +0000212static int extraMemoryFromResolver = 0;
213
214static int
215fatalError(void) {
216 fprintf(stderr, "Exitting tests on fatal error\n");
217 exit(1);
218}
219
220/*
221 * We need to trap calls to the resolver to not account memory for the catalog
222 * which is shared to the current running test. We also don't want to have
223 * network downloads modifying tests.
224 */
Daniel Veillardaa6de472008-08-25 14:53:31 +0000225static xmlParserInputPtr
William M. Brackca15a542005-07-06 20:41:33 +0000226testExternalEntityLoader(const char *URL, const char *ID,
227 xmlParserCtxtPtr ctxt) {
228 xmlParserInputPtr ret;
229
230 if (checkTestFile(URL)) {
231 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
232 } else {
233 int memused = xmlMemUsed();
234 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
235 extraMemoryFromResolver += xmlMemUsed() - memused;
236 }
Daniel Veillardaa6de472008-08-25 14:53:31 +0000237
William M. Brackca15a542005-07-06 20:41:33 +0000238 return(ret);
239}
240
241/*
242 * Trapping the error messages at the generic level to grab the equivalent of
243 * stderr messages on CLI tools.
244 */
245static char testErrors[32769];
246static int testErrorsSize = 0;
247
Daniel Veillardffa3c742005-07-21 13:24:09 +0000248static void XMLCDECL
William M. Brackca15a542005-07-06 20:41:33 +0000249testErrorHandler(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
250 va_list args;
251 int res;
252
253 if (testErrorsSize >= 32768)
254 return;
255 va_start(args, msg);
256 res = vsnprintf(&testErrors[testErrorsSize],
257 32768 - testErrorsSize,
258 msg, args);
259 va_end(args);
260 if (testErrorsSize + res >= 32768) {
261 /* buffer is full */
262 testErrorsSize = 32768;
263 testErrors[testErrorsSize] = 0;
264 } else {
265 testErrorsSize += res;
266 }
267 testErrors[testErrorsSize] = 0;
268}
269
Daniel Veillardffa3c742005-07-21 13:24:09 +0000270static void XMLCDECL
William M. Brackca15a542005-07-06 20:41:33 +0000271channel(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
272 va_list args;
273 int res;
274
275 if (testErrorsSize >= 32768)
276 return;
277 va_start(args, msg);
278 res = vsnprintf(&testErrors[testErrorsSize],
279 32768 - testErrorsSize,
280 msg, args);
281 va_end(args);
282 if (testErrorsSize + res >= 32768) {
283 /* buffer is full */
284 testErrorsSize = 32768;
285 testErrors[testErrorsSize] = 0;
286 } else {
287 testErrorsSize += res;
288 }
289 testErrors[testErrorsSize] = 0;
290}
291
292/**
293 * xmlParserPrintFileContext:
294 * @input: an xmlParserInputPtr input
Daniel Veillardaa6de472008-08-25 14:53:31 +0000295 *
William M. Brackca15a542005-07-06 20:41:33 +0000296 * Displays current context within the input content for error tracking
297 */
298
299static void
Daniel Veillardaa6de472008-08-25 14:53:31 +0000300xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
William M. Brackca15a542005-07-06 20:41:33 +0000301 xmlGenericErrorFunc chanl, void *data ) {
302 const xmlChar *cur, *base;
303 unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */
304 xmlChar content[81]; /* space for 80 chars + line terminator */
305 xmlChar *ctnt;
306
307 if (input == NULL) return;
308 cur = input->cur;
309 base = input->base;
310 /* skip backwards over any end-of-lines */
311 while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
312 cur--;
313 }
314 n = 0;
315 /* search backwards for beginning-of-line (to max buff size) */
Daniel Veillardaa6de472008-08-25 14:53:31 +0000316 while ((n++ < (sizeof(content)-1)) && (cur > base) &&
317 (*(cur) != '\n') && (*(cur) != '\r'))
William M. Brackca15a542005-07-06 20:41:33 +0000318 cur--;
319 if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
320 /* calculate the error position in terms of the current position */
321 col = input->cur - cur;
322 /* search forward for end-of-line (to max buff size) */
323 n = 0;
324 ctnt = content;
325 /* copy selected text to our buffer */
Daniel Veillardaa6de472008-08-25 14:53:31 +0000326 while ((*cur != 0) && (*(cur) != '\n') &&
327 (*(cur) != '\r') && (n < sizeof(content)-1)) {
William M. Brackca15a542005-07-06 20:41:33 +0000328 *ctnt++ = *cur++;
329 n++;
330 }
331 *ctnt = 0;
332 /* print out the selected text */
333 chanl(data ,"%s\n", content);
334 /* create blank line with problem pointer */
335 n = 0;
336 ctnt = content;
337 /* (leave buffer space for pointer + line terminator) */
338 while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
339 if (*(ctnt) != '\t')
340 *(ctnt) = ' ';
341 ctnt++;
342 }
343 *ctnt++ = '^';
344 *ctnt = 0;
345 chanl(data ,"%s\n", content);
346}
347
348static void
349testStructuredErrorHandler(void *ctx ATTRIBUTE_UNUSED, xmlErrorPtr err) {
350 char *file = NULL;
351 int line = 0;
352 int code = -1;
353 int domain;
354 void *data = NULL;
355 const char *str;
356 const xmlChar *name = NULL;
357 xmlNodePtr node;
358 xmlErrorLevel level;
359 xmlParserInputPtr input = NULL;
360 xmlParserInputPtr cur = NULL;
361 xmlParserCtxtPtr ctxt = NULL;
362
363 if (err == NULL)
364 return;
365
366 file = err->file;
367 line = err->line;
368 code = err->code;
369 domain = err->domain;
370 level = err->level;
371 node = err->node;
372 if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
373 (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
374 (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
375 ctxt = err->ctxt;
376 }
377 str = err->message;
378
379 if (code == XML_ERR_OK)
380 return;
381
382 if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
383 name = node->name;
384
385 /*
386 * Maintain the compatibility with the legacy error handling
387 */
388 if (ctxt != NULL) {
389 input = ctxt->input;
390 if ((input != NULL) && (input->filename == NULL) &&
391 (ctxt->inputNr > 1)) {
392 cur = input;
393 input = ctxt->inputTab[ctxt->inputNr - 2];
394 }
395 if (input != NULL) {
396 if (input->filename)
397 channel(data, "%s:%d: ", input->filename, input->line);
398 else if ((line != 0) && (domain == XML_FROM_PARSER))
399 channel(data, "Entity: line %d: ", input->line);
400 }
401 } else {
402 if (file != NULL)
403 channel(data, "%s:%d: ", file, line);
404 else if ((line != 0) && (domain == XML_FROM_PARSER))
405 channel(data, "Entity: line %d: ", line);
406 }
407 if (name != NULL) {
408 channel(data, "element %s: ", name);
409 }
410 if (code == XML_ERR_OK)
411 return;
412 switch (domain) {
413 case XML_FROM_PARSER:
414 channel(data, "parser ");
415 break;
416 case XML_FROM_NAMESPACE:
417 channel(data, "namespace ");
418 break;
419 case XML_FROM_DTD:
420 case XML_FROM_VALID:
421 channel(data, "validity ");
422 break;
423 case XML_FROM_HTML:
424 channel(data, "HTML parser ");
425 break;
426 case XML_FROM_MEMORY:
427 channel(data, "memory ");
428 break;
429 case XML_FROM_OUTPUT:
430 channel(data, "output ");
431 break;
432 case XML_FROM_IO:
433 channel(data, "I/O ");
434 break;
435 case XML_FROM_XINCLUDE:
436 channel(data, "XInclude ");
437 break;
438 case XML_FROM_XPATH:
439 channel(data, "XPath ");
440 break;
441 case XML_FROM_XPOINTER:
442 channel(data, "parser ");
443 break;
444 case XML_FROM_REGEXP:
445 channel(data, "regexp ");
446 break;
447 case XML_FROM_MODULE:
448 channel(data, "module ");
449 break;
450 case XML_FROM_SCHEMASV:
451 channel(data, "Schemas validity ");
452 break;
453 case XML_FROM_SCHEMASP:
454 channel(data, "Schemas parser ");
455 break;
456 case XML_FROM_RELAXNGP:
457 channel(data, "Relax-NG parser ");
458 break;
459 case XML_FROM_RELAXNGV:
460 channel(data, "Relax-NG validity ");
461 break;
462 case XML_FROM_CATALOG:
463 channel(data, "Catalog ");
464 break;
465 case XML_FROM_C14N:
466 channel(data, "C14N ");
467 break;
468 case XML_FROM_XSLT:
469 channel(data, "XSLT ");
470 break;
471 default:
472 break;
473 }
474 if (code == XML_ERR_OK)
475 return;
476 switch (level) {
477 case XML_ERR_NONE:
478 channel(data, ": ");
479 break;
480 case XML_ERR_WARNING:
481 channel(data, "warning : ");
482 break;
483 case XML_ERR_ERROR:
484 channel(data, "error : ");
485 break;
486 case XML_ERR_FATAL:
487 channel(data, "error : ");
488 break;
489 }
490 if (code == XML_ERR_OK)
491 return;
492 if (str != NULL) {
493 int len;
494 len = xmlStrlen((const xmlChar *)str);
495 if ((len > 0) && (str[len - 1] != '\n'))
496 channel(data, "%s\n", str);
497 else
498 channel(data, "%s", str);
499 } else {
500 channel(data, "%s\n", "out of memory error");
501 }
502 if (code == XML_ERR_OK)
503 return;
504
505 if (ctxt != NULL) {
506 xmlParserPrintFileContextInternal(input, channel, data);
507 if (cur != NULL) {
508 if (cur->filename)
509 channel(data, "%s:%d: \n", cur->filename, cur->line);
510 else if ((line != 0) && (domain == XML_FROM_PARSER))
511 channel(data, "Entity: line %d: \n", cur->line);
512 xmlParserPrintFileContextInternal(cur, channel, data);
513 }
514 }
515 if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
516 (err->int1 < 100) &&
517 (err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
518 xmlChar buf[150];
519 int i;
520
521 channel(data, "%s\n", err->str1);
522 for (i=0;i < err->int1;i++)
523 buf[i] = ' ';
524 buf[i++] = '^';
525 buf[i] = 0;
526 channel(data, "%s\n", buf);
527 }
528}
529
530static void
531initializeLibxml2(void) {
532 xmlGetWarningsDefaultValue = 0;
533 xmlPedanticParserDefault(0);
534
535 xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
536 xmlInitParser();
537 xmlSetExternalEntityLoader(testExternalEntityLoader);
538 xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
539#ifdef LIBXML_SCHEMAS_ENABLED
540 xmlSchemaInitTypes();
541 xmlRelaxNGInitTypes();
542#endif
William M. Brackca15a542005-07-06 20:41:33 +0000543}
544
545
546/************************************************************************
547 * *
548 * File name and path utilities *
549 * *
550 ************************************************************************/
551
552static const char *baseFilename(const char *filename) {
553 const char *cur;
554 if (filename == NULL)
555 return(NULL);
556 cur = &filename[strlen(filename)];
557 while ((cur > filename) && (*cur != '/'))
558 cur--;
559 if (*cur == '/')
560 return(cur + 1);
561 return(cur);
562}
563
564static char *resultFilename(const char *filename, const char *out,
565 const char *suffix) {
566 const char *base;
567 char res[500];
Daniel Veillard381ff362006-06-18 17:31:31 +0000568 char suffixbuff[500];
William M. Brackca15a542005-07-06 20:41:33 +0000569
570/*************
571 if ((filename[0] == 't') && (filename[1] == 'e') &&
572 (filename[2] == 's') && (filename[3] == 't') &&
573 (filename[4] == '/'))
574 filename = &filename[5];
575 *************/
Daniel Veillardaa6de472008-08-25 14:53:31 +0000576
William M. Brackca15a542005-07-06 20:41:33 +0000577 base = baseFilename(filename);
578 if (suffix == NULL)
579 suffix = ".tmp";
580 if (out == NULL)
581 out = "";
Daniel Veillard381ff362006-06-18 17:31:31 +0000582
583 strncpy(suffixbuff,suffix,499);
584#ifdef VMS
585 if(strstr(base,".") && suffixbuff[0]=='.')
586 suffixbuff[0]='_';
587#endif
588
589 snprintf(res, 499, "%s%s%s", out, base, suffixbuff);
William M. Brackca15a542005-07-06 20:41:33 +0000590 res[499] = 0;
591 return(strdup(res));
592}
593
594static int checkTestFile(const char *filename) {
595 struct stat buf;
596
597 if (stat(filename, &buf) == -1)
598 return(0);
599
600#if defined(_WIN32) && !defined(__CYGWIN__)
601 if (!(buf.st_mode & _S_IFREG))
602 return(0);
603#else
604 if (!S_ISREG(buf.st_mode))
605 return(0);
606#endif
607
608 return(1);
609}
610
David Kilzer5c373822016-05-22 09:58:30 +0800611static int compareFiles(const char *r1 /* temp */, const char *r2 /* result */) {
William M. Brackca15a542005-07-06 20:41:33 +0000612 int res1, res2;
613 int fd1, fd2;
614 char bytes1[4096];
615 char bytes2[4096];
616
David Kilzer5c373822016-05-22 09:58:30 +0800617 if (update_results) {
618 fd1 = open(r1, RD_FLAGS);
619 if (fd1 < 0)
620 return(-1);
621 fd2 = open(r2, WR_FLAGS, 0644);
622 if (fd2 < 0) {
623 close(fd1);
624 return(-1);
625 }
626 do {
627 res1 = read(fd1, bytes1, 4096);
628 if (res1 <= 0)
629 break;
630 res2 = write(fd2, bytes1, res1);
631 if (res2 <= 0 || res2 != res1)
632 break;
633 } while (1);
634 close(fd2);
635 close(fd1);
636 return(res1 != 0);
637 }
638
William M. Brackca15a542005-07-06 20:41:33 +0000639 fd1 = open(r1, RD_FLAGS);
640 if (fd1 < 0)
641 return(-1);
642 fd2 = open(r2, RD_FLAGS);
643 if (fd2 < 0) {
644 close(fd1);
645 return(-1);
646 }
647 while (1) {
648 res1 = read(fd1, bytes1, 4096);
649 res2 = read(fd2, bytes2, 4096);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000650 if ((res1 != res2) || (res1 < 0)) {
William M. Brackca15a542005-07-06 20:41:33 +0000651 close(fd1);
652 close(fd2);
653 return(1);
654 }
655 if (res1 == 0)
656 break;
657 if (memcmp(bytes1, bytes2, res1) != 0) {
658 close(fd1);
659 close(fd2);
660 return(1);
661 }
662 }
663 close(fd1);
664 close(fd2);
665 return(0);
666}
667
668static int compareFileMem(const char *filename, const char *mem, int size) {
669 int res;
670 int fd;
671 char bytes[4096];
672 int idx = 0;
673 struct stat info;
674
David Kilzer5c373822016-05-22 09:58:30 +0800675 if (update_results) {
676 fd = open(filename, WR_FLAGS, 0644);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800677 if (fd < 0) {
678 fprintf(stderr, "failed to open %s for writing", filename);
David Kilzer5c373822016-05-22 09:58:30 +0800679 return(-1);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800680 }
David Kilzer5c373822016-05-22 09:58:30 +0800681 res = write(fd, mem, size);
682 close(fd);
683 return(res != size);
684 }
685
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800686 if (stat(filename, &info) < 0) {
687 fprintf(stderr, "failed to stat %s\n", filename);
William M. Brackca15a542005-07-06 20:41:33 +0000688 return(-1);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800689 }
690 if (info.st_size != size) {
691 fprintf(stderr, "file %s is %ld bytes, result is %d bytes\n",
Nick Wellnhoferc2545cb2016-08-22 11:44:18 +0200692 filename, (long) info.st_size, size);
William M. Brackca15a542005-07-06 20:41:33 +0000693 return(-1);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800694 }
William M. Brackca15a542005-07-06 20:41:33 +0000695 fd = open(filename, RD_FLAGS);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800696 if (fd < 0) {
697 fprintf(stderr, "failed to open %s for reading", filename);
William M. Brackca15a542005-07-06 20:41:33 +0000698 return(-1);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800699 }
William M. Brackca15a542005-07-06 20:41:33 +0000700 while (idx < size) {
701 res = read(fd, bytes, 4096);
702 if (res <= 0)
703 break;
Daniel Veillardaa6de472008-08-25 14:53:31 +0000704 if (res + idx > size)
William M. Brackca15a542005-07-06 20:41:33 +0000705 break;
706 if (memcmp(bytes, &mem[idx], res) != 0) {
707 int ix;
708 for (ix=0; ix<res; ix++)
709 if (bytes[ix] != mem[idx+ix])
710 break;
711 fprintf(stderr,"Compare error at position %d\n", idx+ix);
712 close(fd);
713 return(1);
714 }
715 idx += res;
716 }
717 close(fd);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800718 if (idx != size) {
719 fprintf(stderr,"Compare error index %d, size %d\n", idx, size);
720 }
William M. Brackca15a542005-07-06 20:41:33 +0000721 return(idx != size);
722}
723
724static int loadMem(const char *filename, const char **mem, int *size) {
725 int fd, res;
726 struct stat info;
727 char *base;
728 int siz = 0;
Daniel Veillardaa6de472008-08-25 14:53:31 +0000729 if (stat(filename, &info) < 0)
William M. Brackca15a542005-07-06 20:41:33 +0000730 return(-1);
731 base = malloc(info.st_size + 1);
732 if (base == NULL)
733 return(-1);
734 if ((fd = open(filename, RD_FLAGS)) < 0) {
735 free(base);
736 return(-1);
737 }
738 while ((res = read(fd, &base[siz], info.st_size - siz)) > 0) {
739 siz += res;
740 }
741 close(fd);
742#if !defined(_WIN32)
743 if (siz != info.st_size) {
744 free(base);
745 return(-1);
746 }
747#endif
748 base[siz] = 0;
749 *mem = base;
750 *size = siz;
751 return(0);
752}
753
754static int unloadMem(const char *mem) {
755 free((char *)mem);
756 return(0);
757}
758
759/************************************************************************
760 * *
761 * Tests implementations *
762 * *
763 ************************************************************************/
764
765/************************************************************************
766 * *
767 * Parse to SAX based tests *
768 * *
769 ************************************************************************/
770
Daniel Veillard24505b02005-07-28 23:49:35 +0000771static FILE *SAXdebug = NULL;
William M. Brackca15a542005-07-06 20:41:33 +0000772
773/*
774 * empty SAX block
775 */
Daniel Veillard24505b02005-07-28 23:49:35 +0000776static xmlSAXHandler emptySAXHandlerStruct = {
William M. Brackca15a542005-07-06 20:41:33 +0000777 NULL, /* internalSubset */
778 NULL, /* isStandalone */
779 NULL, /* hasInternalSubset */
780 NULL, /* hasExternalSubset */
781 NULL, /* resolveEntity */
782 NULL, /* getEntity */
783 NULL, /* entityDecl */
784 NULL, /* notationDecl */
785 NULL, /* attributeDecl */
786 NULL, /* elementDecl */
787 NULL, /* unparsedEntityDecl */
788 NULL, /* setDocumentLocator */
789 NULL, /* startDocument */
790 NULL, /* endDocument */
791 NULL, /* startElement */
792 NULL, /* endElement */
793 NULL, /* reference */
794 NULL, /* characters */
795 NULL, /* ignorableWhitespace */
796 NULL, /* processingInstruction */
797 NULL, /* comment */
798 NULL, /* xmlParserWarning */
799 NULL, /* xmlParserError */
800 NULL, /* xmlParserError */
801 NULL, /* getParameterEntity */
802 NULL, /* cdataBlock; */
803 NULL, /* externalSubset; */
804 1,
805 NULL,
806 NULL, /* startElementNs */
807 NULL, /* endElementNs */
808 NULL /* xmlStructuredErrorFunc */
809};
810
811static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct;
Daniel Veillard24505b02005-07-28 23:49:35 +0000812static int callbacks = 0;
813static int quiet = 0;
William M. Brackca15a542005-07-06 20:41:33 +0000814
815/**
816 * isStandaloneDebug:
817 * @ctxt: An XML parser context
818 *
819 * Is this document tagged standalone ?
820 *
821 * Returns 1 if true
822 */
823static int
824isStandaloneDebug(void *ctx ATTRIBUTE_UNUSED)
825{
826 callbacks++;
827 if (quiet)
828 return(0);
829 fprintf(SAXdebug, "SAX.isStandalone()\n");
830 return(0);
831}
832
833/**
834 * hasInternalSubsetDebug:
835 * @ctxt: An XML parser context
836 *
837 * Does this document has an internal subset
838 *
839 * Returns 1 if true
840 */
841static int
842hasInternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
843{
844 callbacks++;
845 if (quiet)
846 return(0);
847 fprintf(SAXdebug, "SAX.hasInternalSubset()\n");
848 return(0);
849}
850
851/**
852 * hasExternalSubsetDebug:
853 * @ctxt: An XML parser context
854 *
855 * Does this document has an external subset
856 *
857 * Returns 1 if true
858 */
859static int
860hasExternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
861{
862 callbacks++;
863 if (quiet)
864 return(0);
865 fprintf(SAXdebug, "SAX.hasExternalSubset()\n");
866 return(0);
867}
868
869/**
870 * internalSubsetDebug:
871 * @ctxt: An XML parser context
872 *
873 * Does this document has an internal subset
874 */
875static void
876internalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
877 const xmlChar *ExternalID, const xmlChar *SystemID)
878{
879 callbacks++;
880 if (quiet)
881 return;
882 fprintf(SAXdebug, "SAX.internalSubset(%s,", name);
883 if (ExternalID == NULL)
884 fprintf(SAXdebug, " ,");
885 else
886 fprintf(SAXdebug, " %s,", ExternalID);
887 if (SystemID == NULL)
888 fprintf(SAXdebug, " )\n");
889 else
890 fprintf(SAXdebug, " %s)\n", SystemID);
891}
892
893/**
894 * externalSubsetDebug:
895 * @ctxt: An XML parser context
896 *
897 * Does this document has an external subset
898 */
899static void
900externalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
901 const xmlChar *ExternalID, const xmlChar *SystemID)
902{
903 callbacks++;
904 if (quiet)
905 return;
906 fprintf(SAXdebug, "SAX.externalSubset(%s,", name);
907 if (ExternalID == NULL)
908 fprintf(SAXdebug, " ,");
909 else
910 fprintf(SAXdebug, " %s,", ExternalID);
911 if (SystemID == NULL)
912 fprintf(SAXdebug, " )\n");
913 else
914 fprintf(SAXdebug, " %s)\n", SystemID);
915}
916
917/**
918 * resolveEntityDebug:
919 * @ctxt: An XML parser context
920 * @publicId: The public ID of the entity
921 * @systemId: The system ID of the entity
922 *
923 * Special entity resolver, better left to the parser, it has
924 * more context than the application layer.
925 * The default behaviour is to NOT resolve the entities, in that case
926 * the ENTITY_REF nodes are built in the structure (and the parameter
927 * values).
928 *
929 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
930 */
931static xmlParserInputPtr
932resolveEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *publicId, const xmlChar *systemId)
933{
934 callbacks++;
935 if (quiet)
936 return(NULL);
937 /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
938
Daniel Veillardaa6de472008-08-25 14:53:31 +0000939
William M. Brackca15a542005-07-06 20:41:33 +0000940 fprintf(SAXdebug, "SAX.resolveEntity(");
941 if (publicId != NULL)
942 fprintf(SAXdebug, "%s", (char *)publicId);
943 else
944 fprintf(SAXdebug, " ");
945 if (systemId != NULL)
946 fprintf(SAXdebug, ", %s)\n", (char *)systemId);
947 else
948 fprintf(SAXdebug, ", )\n");
949/*********
950 if (systemId != NULL) {
951 return(xmlNewInputFromFile(ctxt, (char *) systemId));
952 }
953 *********/
954 return(NULL);
955}
956
957/**
958 * getEntityDebug:
959 * @ctxt: An XML parser context
960 * @name: The entity name
961 *
962 * Get an entity by name
963 *
964 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
965 */
966static xmlEntityPtr
967getEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
968{
969 callbacks++;
970 if (quiet)
971 return(NULL);
972 fprintf(SAXdebug, "SAX.getEntity(%s)\n", name);
973 return(NULL);
974}
975
976/**
977 * getParameterEntityDebug:
978 * @ctxt: An XML parser context
979 * @name: The entity name
980 *
981 * Get a parameter entity by name
982 *
983 * Returns the xmlParserInputPtr
984 */
985static xmlEntityPtr
986getParameterEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
987{
988 callbacks++;
989 if (quiet)
990 return(NULL);
991 fprintf(SAXdebug, "SAX.getParameterEntity(%s)\n", name);
992 return(NULL);
993}
994
995
996/**
997 * entityDeclDebug:
998 * @ctxt: An XML parser context
Daniel Veillardaa6de472008-08-25 14:53:31 +0000999 * @name: the entity name
1000 * @type: the entity type
William M. Brackca15a542005-07-06 20:41:33 +00001001 * @publicId: The public ID of the entity
1002 * @systemId: The system ID of the entity
1003 * @content: the entity value (without processing).
1004 *
1005 * An entity definition has been parsed
1006 */
1007static void
1008entityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
1009 const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
1010{
1011const xmlChar *nullstr = BAD_CAST "(null)";
1012 /* not all libraries handle printing null pointers nicely */
1013 if (publicId == NULL)
1014 publicId = nullstr;
1015 if (systemId == NULL)
1016 systemId = nullstr;
1017 if (content == NULL)
1018 content = (xmlChar *)nullstr;
1019 callbacks++;
1020 if (quiet)
1021 return;
1022 fprintf(SAXdebug, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
1023 name, type, publicId, systemId, content);
1024}
1025
1026/**
1027 * attributeDeclDebug:
1028 * @ctxt: An XML parser context
Daniel Veillardaa6de472008-08-25 14:53:31 +00001029 * @name: the attribute name
1030 * @type: the attribute type
William M. Brackca15a542005-07-06 20:41:33 +00001031 *
1032 * An attribute definition has been parsed
1033 */
1034static void
1035attributeDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar * elem,
1036 const xmlChar * name, int type, int def,
1037 const xmlChar * defaultValue, xmlEnumerationPtr tree)
1038{
1039 callbacks++;
1040 if (quiet)
1041 return;
1042 if (defaultValue == NULL)
1043 fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, NULL, ...)\n",
1044 elem, name, type, def);
1045 else
1046 fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
1047 elem, name, type, def, defaultValue);
1048 xmlFreeEnumeration(tree);
1049}
1050
1051/**
1052 * elementDeclDebug:
1053 * @ctxt: An XML parser context
Daniel Veillardaa6de472008-08-25 14:53:31 +00001054 * @name: the element name
1055 * @type: the element type
William M. Brackca15a542005-07-06 20:41:33 +00001056 * @content: the element value (without processing).
1057 *
1058 * An element definition has been parsed
1059 */
1060static void
1061elementDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
1062 xmlElementContentPtr content ATTRIBUTE_UNUSED)
1063{
1064 callbacks++;
1065 if (quiet)
1066 return;
1067 fprintf(SAXdebug, "SAX.elementDecl(%s, %d, ...)\n",
1068 name, type);
1069}
1070
1071/**
1072 * notationDeclDebug:
1073 * @ctxt: An XML parser context
1074 * @name: The name of the notation
1075 * @publicId: The public ID of the entity
1076 * @systemId: The system ID of the entity
1077 *
1078 * What to do when a notation declaration has been parsed.
1079 */
1080static void
1081notationDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
1082 const xmlChar *publicId, const xmlChar *systemId)
1083{
1084 callbacks++;
1085 if (quiet)
1086 return;
1087 fprintf(SAXdebug, "SAX.notationDecl(%s, %s, %s)\n",
1088 (char *) name, (char *) publicId, (char *) systemId);
1089}
1090
1091/**
1092 * unparsedEntityDeclDebug:
1093 * @ctxt: An XML parser context
1094 * @name: The name of the entity
1095 * @publicId: The public ID of the entity
1096 * @systemId: The system ID of the entity
1097 * @notationName: the name of the notation
1098 *
1099 * What to do when an unparsed entity declaration is parsed
1100 */
1101static void
1102unparsedEntityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
1103 const xmlChar *publicId, const xmlChar *systemId,
1104 const xmlChar *notationName)
1105{
1106const xmlChar *nullstr = BAD_CAST "(null)";
1107
1108 if (publicId == NULL)
1109 publicId = nullstr;
1110 if (systemId == NULL)
1111 systemId = nullstr;
1112 if (notationName == NULL)
1113 notationName = nullstr;
1114 callbacks++;
1115 if (quiet)
1116 return;
1117 fprintf(SAXdebug, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
1118 (char *) name, (char *) publicId, (char *) systemId,
1119 (char *) notationName);
1120}
1121
1122/**
1123 * setDocumentLocatorDebug:
1124 * @ctxt: An XML parser context
1125 * @loc: A SAX Locator
1126 *
1127 * Receive the document locator at startup, actually xmlDefaultSAXLocator
1128 * Everything is available on the context, so this is useless in our case.
1129 */
1130static void
1131setDocumentLocatorDebug(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
1132{
1133 callbacks++;
1134 if (quiet)
1135 return;
1136 fprintf(SAXdebug, "SAX.setDocumentLocator()\n");
1137}
1138
1139/**
1140 * startDocumentDebug:
1141 * @ctxt: An XML parser context
1142 *
1143 * called when the document start being processed.
1144 */
1145static void
1146startDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
1147{
1148 callbacks++;
1149 if (quiet)
1150 return;
1151 fprintf(SAXdebug, "SAX.startDocument()\n");
1152}
1153
1154/**
1155 * endDocumentDebug:
1156 * @ctxt: An XML parser context
1157 *
1158 * called when the document end has been detected.
1159 */
1160static void
1161endDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
1162{
1163 callbacks++;
1164 if (quiet)
1165 return;
1166 fprintf(SAXdebug, "SAX.endDocument()\n");
1167}
1168
1169/**
1170 * startElementDebug:
1171 * @ctxt: An XML parser context
1172 * @name: The element name
1173 *
1174 * called when an opening tag has been processed.
1175 */
1176static void
1177startElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
1178{
1179 int i;
1180
1181 callbacks++;
1182 if (quiet)
1183 return;
1184 fprintf(SAXdebug, "SAX.startElement(%s", (char *) name);
1185 if (atts != NULL) {
1186 for (i = 0;(atts[i] != NULL);i++) {
1187 fprintf(SAXdebug, ", %s='", atts[i++]);
1188 if (atts[i] != NULL)
1189 fprintf(SAXdebug, "%s'", atts[i]);
1190 }
1191 }
1192 fprintf(SAXdebug, ")\n");
1193}
1194
1195/**
1196 * endElementDebug:
1197 * @ctxt: An XML parser context
1198 * @name: The element name
1199 *
1200 * called when the end of an element has been detected.
1201 */
1202static void
1203endElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
1204{
1205 callbacks++;
1206 if (quiet)
1207 return;
1208 fprintf(SAXdebug, "SAX.endElement(%s)\n", (char *) name);
1209}
1210
1211/**
1212 * charactersDebug:
1213 * @ctxt: An XML parser context
1214 * @ch: a xmlChar string
1215 * @len: the number of xmlChar
1216 *
1217 * receiving some chars from the parser.
1218 * Question: how much at a time ???
1219 */
1220static void
1221charactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1222{
1223 char output[40];
1224 int i;
1225
1226 callbacks++;
1227 if (quiet)
1228 return;
1229 for (i = 0;(i<len) && (i < 30);i++)
1230 output[i] = ch[i];
1231 output[i] = 0;
1232
1233 fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len);
1234}
1235
1236/**
1237 * referenceDebug:
1238 * @ctxt: An XML parser context
1239 * @name: The entity name
1240 *
Daniel Veillardaa6de472008-08-25 14:53:31 +00001241 * called when an entity reference is detected.
William M. Brackca15a542005-07-06 20:41:33 +00001242 */
1243static void
1244referenceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
1245{
1246 callbacks++;
1247 if (quiet)
1248 return;
1249 fprintf(SAXdebug, "SAX.reference(%s)\n", name);
1250}
1251
1252/**
1253 * ignorableWhitespaceDebug:
1254 * @ctxt: An XML parser context
1255 * @ch: a xmlChar string
1256 * @start: the first char in the string
1257 * @len: the number of xmlChar
1258 *
1259 * receiving some ignorable whitespaces from the parser.
1260 * Question: how much at a time ???
1261 */
1262static void
1263ignorableWhitespaceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1264{
1265 char output[40];
1266 int i;
1267
1268 callbacks++;
1269 if (quiet)
1270 return;
1271 for (i = 0;(i<len) && (i < 30);i++)
1272 output[i] = ch[i];
1273 output[i] = 0;
1274 fprintf(SAXdebug, "SAX.ignorableWhitespace(%s, %d)\n", output, len);
1275}
1276
1277/**
1278 * processingInstructionDebug:
1279 * @ctxt: An XML parser context
1280 * @target: the target name
1281 * @data: the PI data's
1282 * @len: the number of xmlChar
1283 *
1284 * A processing instruction has been parsed.
1285 */
1286static void
1287processingInstructionDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *target,
1288 const xmlChar *data)
1289{
1290 callbacks++;
1291 if (quiet)
1292 return;
1293 if (data != NULL)
1294 fprintf(SAXdebug, "SAX.processingInstruction(%s, %s)\n",
1295 (char *) target, (char *) data);
1296 else
1297 fprintf(SAXdebug, "SAX.processingInstruction(%s, NULL)\n",
1298 (char *) target);
1299}
1300
1301/**
1302 * cdataBlockDebug:
1303 * @ctx: the user data (XML parser context)
1304 * @value: The pcdata content
1305 * @len: the block length
1306 *
1307 * called when a pcdata block has been parsed
1308 */
1309static void
1310cdataBlockDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value, int len)
1311{
1312 callbacks++;
1313 if (quiet)
1314 return;
1315 fprintf(SAXdebug, "SAX.pcdata(%.20s, %d)\n",
1316 (char *) value, len);
1317}
1318
1319/**
1320 * commentDebug:
1321 * @ctxt: An XML parser context
1322 * @value: the comment content
1323 *
1324 * A comment has been parsed.
1325 */
1326static void
1327commentDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value)
1328{
1329 callbacks++;
1330 if (quiet)
1331 return;
1332 fprintf(SAXdebug, "SAX.comment(%s)\n", value);
1333}
1334
1335/**
1336 * warningDebug:
1337 * @ctxt: An XML parser context
1338 * @msg: the message to display/transmit
1339 * @...: extra parameters for the message display
1340 *
1341 * Display and format a warning messages, gives file, line, position and
1342 * extra parameters.
1343 */
Daniel Veillardffa3c742005-07-21 13:24:09 +00001344static void XMLCDECL
William M. Brackca15a542005-07-06 20:41:33 +00001345warningDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1346{
1347 va_list args;
1348
1349 callbacks++;
1350 if (quiet)
1351 return;
1352 va_start(args, msg);
1353 fprintf(SAXdebug, "SAX.warning: ");
1354 vfprintf(SAXdebug, msg, args);
1355 va_end(args);
1356}
1357
1358/**
1359 * errorDebug:
1360 * @ctxt: An XML parser context
1361 * @msg: the message to display/transmit
1362 * @...: extra parameters for the message display
1363 *
1364 * Display and format a error messages, gives file, line, position and
1365 * extra parameters.
1366 */
Daniel Veillardffa3c742005-07-21 13:24:09 +00001367static void XMLCDECL
William M. Brackca15a542005-07-06 20:41:33 +00001368errorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1369{
1370 va_list args;
1371
1372 callbacks++;
1373 if (quiet)
1374 return;
1375 va_start(args, msg);
1376 fprintf(SAXdebug, "SAX.error: ");
1377 vfprintf(SAXdebug, msg, args);
1378 va_end(args);
1379}
1380
1381/**
1382 * fatalErrorDebug:
1383 * @ctxt: An XML parser context
1384 * @msg: the message to display/transmit
1385 * @...: extra parameters for the message display
1386 *
1387 * Display and format a fatalError messages, gives file, line, position and
1388 * extra parameters.
1389 */
Daniel Veillardffa3c742005-07-21 13:24:09 +00001390static void XMLCDECL
William M. Brackca15a542005-07-06 20:41:33 +00001391fatalErrorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1392{
1393 va_list args;
1394
1395 callbacks++;
1396 if (quiet)
1397 return;
1398 va_start(args, msg);
1399 fprintf(SAXdebug, "SAX.fatalError: ");
1400 vfprintf(SAXdebug, msg, args);
1401 va_end(args);
1402}
1403
Daniel Veillard24505b02005-07-28 23:49:35 +00001404static xmlSAXHandler debugSAXHandlerStruct = {
William M. Brackca15a542005-07-06 20:41:33 +00001405 internalSubsetDebug,
1406 isStandaloneDebug,
1407 hasInternalSubsetDebug,
1408 hasExternalSubsetDebug,
1409 resolveEntityDebug,
1410 getEntityDebug,
1411 entityDeclDebug,
1412 notationDeclDebug,
1413 attributeDeclDebug,
1414 elementDeclDebug,
1415 unparsedEntityDeclDebug,
1416 setDocumentLocatorDebug,
1417 startDocumentDebug,
1418 endDocumentDebug,
1419 startElementDebug,
1420 endElementDebug,
1421 referenceDebug,
1422 charactersDebug,
1423 ignorableWhitespaceDebug,
1424 processingInstructionDebug,
1425 commentDebug,
1426 warningDebug,
1427 errorDebug,
1428 fatalErrorDebug,
1429 getParameterEntityDebug,
1430 cdataBlockDebug,
1431 externalSubsetDebug,
1432 1,
1433 NULL,
1434 NULL,
1435 NULL,
1436 NULL
1437};
1438
Daniel Veillard24505b02005-07-28 23:49:35 +00001439static xmlSAXHandlerPtr debugSAXHandler = &debugSAXHandlerStruct;
William M. Brackca15a542005-07-06 20:41:33 +00001440
1441/*
1442 * SAX2 specific callbacks
1443 */
1444/**
1445 * startElementNsDebug:
1446 * @ctxt: An XML parser context
1447 * @name: The element name
1448 *
1449 * called when an opening tag has been processed.
1450 */
1451static void
1452startElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
1453 const xmlChar *localname,
1454 const xmlChar *prefix,
1455 const xmlChar *URI,
1456 int nb_namespaces,
1457 const xmlChar **namespaces,
1458 int nb_attributes,
1459 int nb_defaulted,
1460 const xmlChar **attributes)
1461{
1462 int i;
1463
1464 callbacks++;
1465 if (quiet)
1466 return;
1467 fprintf(SAXdebug, "SAX.startElementNs(%s", (char *) localname);
1468 if (prefix == NULL)
1469 fprintf(SAXdebug, ", NULL");
1470 else
1471 fprintf(SAXdebug, ", %s", (char *) prefix);
1472 if (URI == NULL)
1473 fprintf(SAXdebug, ", NULL");
1474 else
1475 fprintf(SAXdebug, ", '%s'", (char *) URI);
1476 fprintf(SAXdebug, ", %d", nb_namespaces);
Daniel Veillardaa6de472008-08-25 14:53:31 +00001477
William M. Brackca15a542005-07-06 20:41:33 +00001478 if (namespaces != NULL) {
1479 for (i = 0;i < nb_namespaces * 2;i++) {
1480 fprintf(SAXdebug, ", xmlns");
1481 if (namespaces[i] != NULL)
1482 fprintf(SAXdebug, ":%s", namespaces[i]);
1483 i++;
1484 fprintf(SAXdebug, "='%s'", namespaces[i]);
1485 }
1486 }
1487 fprintf(SAXdebug, ", %d, %d", nb_attributes, nb_defaulted);
1488 if (attributes != NULL) {
1489 for (i = 0;i < nb_attributes * 5;i += 5) {
1490 if (attributes[i + 1] != NULL)
1491 fprintf(SAXdebug, ", %s:%s='", attributes[i + 1], attributes[i]);
1492 else
1493 fprintf(SAXdebug, ", %s='", attributes[i]);
1494 fprintf(SAXdebug, "%.4s...', %d", attributes[i + 3],
1495 (int)(attributes[i + 4] - attributes[i + 3]));
1496 }
1497 }
1498 fprintf(SAXdebug, ")\n");
1499}
1500
1501/**
1502 * endElementDebug:
1503 * @ctxt: An XML parser context
1504 * @name: The element name
1505 *
1506 * called when the end of an element has been detected.
1507 */
1508static void
1509endElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
1510 const xmlChar *localname,
1511 const xmlChar *prefix,
1512 const xmlChar *URI)
1513{
1514 callbacks++;
1515 if (quiet)
1516 return;
1517 fprintf(SAXdebug, "SAX.endElementNs(%s", (char *) localname);
1518 if (prefix == NULL)
1519 fprintf(SAXdebug, ", NULL");
1520 else
1521 fprintf(SAXdebug, ", %s", (char *) prefix);
1522 if (URI == NULL)
1523 fprintf(SAXdebug, ", NULL)\n");
1524 else
1525 fprintf(SAXdebug, ", '%s')\n", (char *) URI);
1526}
1527
Daniel Veillard24505b02005-07-28 23:49:35 +00001528static xmlSAXHandler debugSAX2HandlerStruct = {
William M. Brackca15a542005-07-06 20:41:33 +00001529 internalSubsetDebug,
1530 isStandaloneDebug,
1531 hasInternalSubsetDebug,
1532 hasExternalSubsetDebug,
1533 resolveEntityDebug,
1534 getEntityDebug,
1535 entityDeclDebug,
1536 notationDeclDebug,
1537 attributeDeclDebug,
1538 elementDeclDebug,
1539 unparsedEntityDeclDebug,
1540 setDocumentLocatorDebug,
1541 startDocumentDebug,
1542 endDocumentDebug,
1543 NULL,
1544 NULL,
1545 referenceDebug,
1546 charactersDebug,
1547 ignorableWhitespaceDebug,
1548 processingInstructionDebug,
1549 commentDebug,
1550 warningDebug,
1551 errorDebug,
1552 fatalErrorDebug,
1553 getParameterEntityDebug,
1554 cdataBlockDebug,
1555 externalSubsetDebug,
1556 XML_SAX2_MAGIC,
1557 NULL,
1558 startElementNsDebug,
1559 endElementNsDebug,
1560 NULL
1561};
1562
Daniel Veillard24505b02005-07-28 23:49:35 +00001563static xmlSAXHandlerPtr debugSAX2Handler = &debugSAX2HandlerStruct;
William M. Brackca15a542005-07-06 20:41:33 +00001564
1565#ifdef LIBXML_HTML_ENABLED
1566/**
1567 * htmlstartElementDebug:
1568 * @ctxt: An XML parser context
1569 * @name: The element name
1570 *
1571 * called when an opening tag has been processed.
1572 */
1573static void
1574htmlstartElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
1575{
1576 int i;
1577
1578 fprintf(SAXdebug, "SAX.startElement(%s", (char *) name);
1579 if (atts != NULL) {
1580 for (i = 0;(atts[i] != NULL);i++) {
1581 fprintf(SAXdebug, ", %s", atts[i++]);
1582 if (atts[i] != NULL) {
1583 unsigned char output[40];
1584 const unsigned char *att = atts[i];
1585 int outlen, attlen;
1586 fprintf(SAXdebug, "='");
1587 while ((attlen = strlen((char*)att)) > 0) {
1588 outlen = sizeof output - 1;
1589 htmlEncodeEntities(output, &outlen, att, &attlen, '\'');
1590 output[outlen] = 0;
1591 fprintf(SAXdebug, "%s", (char *) output);
1592 att += attlen;
1593 }
1594 fprintf(SAXdebug, "'");
1595 }
1596 }
1597 }
1598 fprintf(SAXdebug, ")\n");
1599}
1600
1601/**
1602 * htmlcharactersDebug:
1603 * @ctxt: An XML parser context
1604 * @ch: a xmlChar string
1605 * @len: the number of xmlChar
1606 *
1607 * receiving some chars from the parser.
1608 * Question: how much at a time ???
1609 */
1610static void
1611htmlcharactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1612{
1613 unsigned char output[40];
1614 int inlen = len, outlen = 30;
1615
1616 htmlEncodeEntities(output, &outlen, ch, &inlen, 0);
1617 output[outlen] = 0;
1618
1619 fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len);
1620}
1621
1622/**
1623 * htmlcdataDebug:
1624 * @ctxt: An XML parser context
1625 * @ch: a xmlChar string
1626 * @len: the number of xmlChar
1627 *
1628 * receiving some cdata chars from the parser.
1629 * Question: how much at a time ???
1630 */
1631static void
1632htmlcdataDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1633{
1634 unsigned char output[40];
1635 int inlen = len, outlen = 30;
1636
1637 htmlEncodeEntities(output, &outlen, ch, &inlen, 0);
1638 output[outlen] = 0;
1639
1640 fprintf(SAXdebug, "SAX.cdata(%s, %d)\n", output, len);
1641}
1642
Daniel Veillard24505b02005-07-28 23:49:35 +00001643static xmlSAXHandler debugHTMLSAXHandlerStruct = {
William M. Brackca15a542005-07-06 20:41:33 +00001644 internalSubsetDebug,
1645 isStandaloneDebug,
1646 hasInternalSubsetDebug,
1647 hasExternalSubsetDebug,
1648 resolveEntityDebug,
1649 getEntityDebug,
1650 entityDeclDebug,
1651 notationDeclDebug,
1652 attributeDeclDebug,
1653 elementDeclDebug,
1654 unparsedEntityDeclDebug,
1655 setDocumentLocatorDebug,
1656 startDocumentDebug,
1657 endDocumentDebug,
1658 htmlstartElementDebug,
1659 endElementDebug,
1660 referenceDebug,
1661 htmlcharactersDebug,
1662 ignorableWhitespaceDebug,
1663 processingInstructionDebug,
1664 commentDebug,
1665 warningDebug,
1666 errorDebug,
1667 fatalErrorDebug,
1668 getParameterEntityDebug,
1669 htmlcdataDebug,
1670 externalSubsetDebug,
1671 1,
1672 NULL,
1673 NULL,
1674 NULL,
1675 NULL
1676};
1677
Daniel Veillard24505b02005-07-28 23:49:35 +00001678static xmlSAXHandlerPtr debugHTMLSAXHandler = &debugHTMLSAXHandlerStruct;
William M. Brackca15a542005-07-06 20:41:33 +00001679#endif /* LIBXML_HTML_ENABLED */
1680
William M. Brackca15a542005-07-06 20:41:33 +00001681/**
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
Nick Wellnhoferdbaab1f2017-06-16 21:38:57 +02001721 {
1722 xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename);
1723 memcpy(ctxt->sax, emptySAXHandler, sizeof(xmlSAXHandler));
1724 xmlCtxtUseOptions(ctxt, options);
1725 xmlParseDocument(ctxt);
1726 ret = ctxt->wellFormed ? 0 : ctxt->errNo;
1727 xmlFreeDoc(ctxt->myDoc);
1728 xmlFreeParserCtxt(ctxt);
1729 }
William M. Brackca15a542005-07-06 20:41:33 +00001730 if (ret == XML_WAR_UNDECLARED_ENTITY) {
1731 fprintf(SAXdebug, "xmlSAXUserParseFile returned error %d\n", ret);
1732 ret = 0;
1733 }
1734 if (ret != 0) {
1735 fprintf(stderr, "Failed to parse %s\n", filename);
Philip Withnall5777ae72014-06-20 21:15:16 +01001736 ret = 1;
1737 goto done;
William M. Brackca15a542005-07-06 20:41:33 +00001738 }
1739#ifdef LIBXML_HTML_ENABLED
1740 if (options & XML_PARSE_HTML) {
1741 htmlSAXParseFile(filename, NULL, debugHTMLSAXHandler, NULL);
1742 ret = 0;
1743 } else
1744#endif
Nick Wellnhoferdbaab1f2017-06-16 21:38:57 +02001745 {
1746 xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename);
1747 if (options & XML_PARSE_SAX1) {
1748 memcpy(ctxt->sax, debugSAXHandler, sizeof(xmlSAXHandler));
1749 options -= XML_PARSE_SAX1;
1750 } else {
1751 memcpy(ctxt->sax, debugSAX2Handler, sizeof(xmlSAXHandler));
1752 }
1753 xmlCtxtUseOptions(ctxt, options);
1754 xmlParseDocument(ctxt);
1755 ret = ctxt->wellFormed ? 0 : ctxt->errNo;
1756 xmlFreeDoc(ctxt->myDoc);
1757 xmlFreeParserCtxt(ctxt);
William M. Brackca15a542005-07-06 20:41:33 +00001758 }
1759 if (ret == XML_WAR_UNDECLARED_ENTITY) {
1760 fprintf(SAXdebug, "xmlSAXUserParseFile returned error %d\n", ret);
1761 ret = 0;
1762 }
1763 fclose(SAXdebug);
1764 if (compareFiles(temp, result)) {
1765 fprintf(stderr, "Got a difference for %s\n", filename);
1766 ret = 1;
Daniel Veillard13cee4e2009-09-05 14:52:55 +02001767 }
Philip Withnall5777ae72014-06-20 21:15:16 +01001768
1769done:
Daniel Veillard13cee4e2009-09-05 14:52:55 +02001770 if (temp != NULL) {
1771 unlink(temp);
1772 free(temp);
1773 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00001774
William M. Brackca15a542005-07-06 20:41:33 +00001775 /* switch back to structured error handling */
1776 xmlSetGenericErrorFunc(NULL, NULL);
1777 xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
1778
1779 return(ret);
1780}
William M. Brackca15a542005-07-06 20:41:33 +00001781
1782/************************************************************************
1783 * *
1784 * Parse to tree based tests *
1785 * *
1786 ************************************************************************/
1787/**
1788 * oldParseTest:
1789 * @filename: the file to parse
1790 * @result: the file with expected result
1791 * @err: the file with error messages: unused
1792 *
1793 * Parse a file using the old xmlParseFile API, then serialize back
1794 * reparse the result and serialize again, then check for deviation
1795 * in serialization.
1796 *
1797 * Returns 0 in case of success, an error code otherwise
1798 */
1799static int
1800oldParseTest(const char *filename, const char *result,
1801 const char *err ATTRIBUTE_UNUSED,
1802 int options ATTRIBUTE_UNUSED) {
1803 xmlDocPtr doc;
1804 char *temp;
1805 int res = 0;
1806
1807 nb_tests++;
1808 /*
1809 * base of the test, parse with the old API
1810 */
1811#ifdef LIBXML_SAX1_ENABLED
1812 doc = xmlParseFile(filename);
1813#else
1814 doc = xmlReadFile(filename, NULL, 0);
1815#endif
1816 if (doc == NULL)
1817 return(1);
1818 temp = resultFilename(filename, "", ".res");
1819 if (temp == NULL) {
1820 fprintf(stderr, "out of memory\n");
1821 fatalError();
1822 }
1823 xmlSaveFile(temp, doc);
1824 if (compareFiles(temp, result)) {
1825 res = 1;
1826 }
1827 xmlFreeDoc(doc);
1828
1829 /*
1830 * Parse the saved result to make sure the round trip is okay
1831 */
1832#ifdef LIBXML_SAX1_ENABLED
1833 doc = xmlParseFile(temp);
1834#else
1835 doc = xmlReadFile(temp, NULL, 0);
1836#endif
1837 if (doc == NULL)
1838 return(1);
1839 xmlSaveFile(temp, doc);
1840 if (compareFiles(temp, result)) {
1841 res = 1;
1842 }
1843 xmlFreeDoc(doc);
1844
Daniel Veillard13cee4e2009-09-05 14:52:55 +02001845 if (temp != NULL) {
1846 unlink(temp);
1847 free(temp);
1848 }
William M. Brackca15a542005-07-06 20:41:33 +00001849 return(res);
1850}
1851
1852#ifdef LIBXML_PUSH_ENABLED
1853/**
1854 * pushParseTest:
1855 * @filename: the file to parse
1856 * @result: the file with expected result
1857 * @err: the file with error messages: unused
1858 *
1859 * Parse a file using the Push API, then serialize back
1860 * to check for content.
1861 *
1862 * Returns 0 in case of success, an error code otherwise
1863 */
1864static int
1865pushParseTest(const char *filename, const char *result,
1866 const char *err ATTRIBUTE_UNUSED,
1867 int options) {
1868 xmlParserCtxtPtr ctxt;
1869 xmlDocPtr doc;
1870 const char *base;
1871 int size, res;
1872 int cur = 0;
David Kilzer85c112a2017-06-12 18:26:11 +02001873 int chunkSize = 4;
William M. Brackca15a542005-07-06 20:41:33 +00001874
1875 nb_tests++;
1876 /*
1877 * load the document in memory and work from there.
1878 */
1879 if (loadMem(filename, &base, &size) != 0) {
1880 fprintf(stderr, "Failed to load %s\n", filename);
1881 return(-1);
1882 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00001883
David Kilzer85c112a2017-06-12 18:26:11 +02001884 if (chunkSize > size)
1885 chunkSize = size;
1886
William M. Brackca15a542005-07-06 20:41:33 +00001887#ifdef LIBXML_HTML_ENABLED
1888 if (options & XML_PARSE_HTML)
David Kilzer85c112a2017-06-12 18:26:11 +02001889 ctxt = htmlCreatePushParserCtxt(NULL, NULL, base + cur, chunkSize, filename,
William M. Brackca15a542005-07-06 20:41:33 +00001890 XML_CHAR_ENCODING_NONE);
1891 else
1892#endif
David Kilzer85c112a2017-06-12 18:26:11 +02001893 ctxt = xmlCreatePushParserCtxt(NULL, NULL, base + cur, chunkSize, filename);
William M. Brackca15a542005-07-06 20:41:33 +00001894 xmlCtxtUseOptions(ctxt, options);
David Kilzer85c112a2017-06-12 18:26:11 +02001895 cur += chunkSize;
1896 chunkSize = 1024;
Pranjal Jumdea820dbe2016-03-01 11:34:04 -08001897 do {
David Kilzer85c112a2017-06-12 18:26:11 +02001898 if (cur + chunkSize >= size) {
William M. Brackca15a542005-07-06 20:41:33 +00001899#ifdef LIBXML_HTML_ENABLED
1900 if (options & XML_PARSE_HTML)
1901 htmlParseChunk(ctxt, base + cur, size - cur, 1);
1902 else
1903#endif
1904 xmlParseChunk(ctxt, base + cur, size - cur, 1);
1905 break;
1906 } else {
1907#ifdef LIBXML_HTML_ENABLED
1908 if (options & XML_PARSE_HTML)
David Kilzer85c112a2017-06-12 18:26:11 +02001909 htmlParseChunk(ctxt, base + cur, chunkSize, 0);
William M. Brackca15a542005-07-06 20:41:33 +00001910 else
1911#endif
David Kilzer85c112a2017-06-12 18:26:11 +02001912 xmlParseChunk(ctxt, base + cur, chunkSize, 0);
1913 cur += chunkSize;
William M. Brackca15a542005-07-06 20:41:33 +00001914 }
Pranjal Jumdea820dbe2016-03-01 11:34:04 -08001915 } while (cur < size);
William M. Brackca15a542005-07-06 20:41:33 +00001916 doc = ctxt->myDoc;
1917#ifdef LIBXML_HTML_ENABLED
1918 if (options & XML_PARSE_HTML)
1919 res = 1;
1920 else
1921#endif
1922 res = ctxt->wellFormed;
1923 xmlFreeParserCtxt(ctxt);
1924 free((char *)base);
1925 if (!res) {
1926 xmlFreeDoc(doc);
1927 fprintf(stderr, "Failed to parse %s\n", filename);
1928 return(-1);
1929 }
1930#ifdef LIBXML_HTML_ENABLED
1931 if (options & XML_PARSE_HTML)
1932 htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1933 else
1934#endif
1935 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1936 xmlFreeDoc(doc);
1937 res = compareFileMem(result, base, size);
1938 if ((base == NULL) || (res != 0)) {
1939 if (base != NULL)
1940 xmlFree((char *)base);
Daniel Veillard9f2416c2016-05-22 11:14:45 +08001941 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00001942 return(-1);
1943 }
1944 xmlFree((char *)base);
1945 if (err != NULL) {
1946 res = compareFileMem(err, testErrors, testErrorsSize);
1947 if (res != 0) {
1948 fprintf(stderr, "Error for %s failed\n", filename);
1949 return(-1);
1950 }
1951 }
1952 return(0);
1953}
1954#endif
1955
1956/**
1957 * memParseTest:
1958 * @filename: the file to parse
1959 * @result: the file with expected result
1960 * @err: the file with error messages: unused
1961 *
1962 * Parse a file using the old xmlReadMemory API, then serialize back
1963 * reparse the result and serialize again, then check for deviation
1964 * in serialization.
1965 *
1966 * Returns 0 in case of success, an error code otherwise
1967 */
1968static int
1969memParseTest(const char *filename, const char *result,
1970 const char *err ATTRIBUTE_UNUSED,
1971 int options ATTRIBUTE_UNUSED) {
1972 xmlDocPtr doc;
1973 const char *base;
1974 int size, res;
1975
1976 nb_tests++;
1977 /*
1978 * load and parse the memory
1979 */
1980 if (loadMem(filename, &base, &size) != 0) {
1981 fprintf(stderr, "Failed to load %s\n", filename);
1982 return(-1);
1983 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00001984
William M. Brackca15a542005-07-06 20:41:33 +00001985 doc = xmlReadMemory(base, size, filename, NULL, 0);
1986 unloadMem(base);
1987 if (doc == NULL) {
1988 return(1);
1989 }
1990 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1991 xmlFreeDoc(doc);
1992 res = compareFileMem(result, base, size);
1993 if ((base == NULL) || (res != 0)) {
1994 if (base != NULL)
1995 xmlFree((char *)base);
Daniel Veillard9f2416c2016-05-22 11:14:45 +08001996 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00001997 return(-1);
1998 }
1999 xmlFree((char *)base);
2000 return(0);
2001}
2002
2003/**
2004 * noentParseTest:
2005 * @filename: the file to parse
2006 * @result: the file with expected result
2007 * @err: the file with error messages: unused
2008 *
2009 * Parse a file with entity resolution, then serialize back
2010 * reparse the result and serialize again, then check for deviation
2011 * in serialization.
2012 *
2013 * Returns 0 in case of success, an error code otherwise
2014 */
2015static int
2016noentParseTest(const char *filename, const char *result,
2017 const char *err ATTRIBUTE_UNUSED,
2018 int options) {
2019 xmlDocPtr doc;
2020 char *temp;
2021 int res = 0;
2022
2023 nb_tests++;
2024 /*
2025 * base of the test, parse with the old API
2026 */
2027 doc = xmlReadFile(filename, NULL, options);
2028 if (doc == NULL)
2029 return(1);
2030 temp = resultFilename(filename, "", ".res");
2031 if (temp == NULL) {
2032 fprintf(stderr, "Out of memory\n");
2033 fatalError();
2034 }
2035 xmlSaveFile(temp, doc);
2036 if (compareFiles(temp, result)) {
2037 res = 1;
2038 }
2039 xmlFreeDoc(doc);
2040
2041 /*
2042 * Parse the saved result to make sure the round trip is okay
2043 */
2044 doc = xmlReadFile(filename, NULL, options);
2045 if (doc == NULL)
2046 return(1);
2047 xmlSaveFile(temp, doc);
2048 if (compareFiles(temp, result)) {
2049 res = 1;
2050 }
2051 xmlFreeDoc(doc);
2052
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002053 if (temp != NULL) {
2054 unlink(temp);
2055 free(temp);
2056 }
William M. Brackca15a542005-07-06 20:41:33 +00002057 return(res);
2058}
2059
2060/**
2061 * errParseTest:
2062 * @filename: the file to parse
2063 * @result: the file with expected result
2064 * @err: the file with error messages
2065 *
2066 * Parse a file using the xmlReadFile API and check for errors.
2067 *
2068 * Returns 0 in case of success, an error code otherwise
2069 */
2070static int
2071errParseTest(const char *filename, const char *result, const char *err,
2072 int options) {
2073 xmlDocPtr doc;
2074 const char *base = NULL;
2075 int size, res = 0;
2076
2077 nb_tests++;
2078#ifdef LIBXML_HTML_ENABLED
2079 if (options & XML_PARSE_HTML) {
2080 doc = htmlReadFile(filename, NULL, options);
2081 } else
2082#endif
2083#ifdef LIBXML_XINCLUDE_ENABLED
2084 if (options & XML_PARSE_XINCLUDE) {
2085 doc = xmlReadFile(filename, NULL, options);
2086 xmlXIncludeProcessFlags(doc, options);
2087 } else
2088#endif
2089 {
2090 xmlGetWarningsDefaultValue = 1;
2091 doc = xmlReadFile(filename, NULL, options);
2092 }
2093 xmlGetWarningsDefaultValue = 0;
2094 if (result) {
2095 if (doc == NULL) {
2096 base = "";
2097 size = 0;
2098 } else {
2099#ifdef LIBXML_HTML_ENABLED
2100 if (options & XML_PARSE_HTML) {
2101 htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2102 } else
2103#endif
2104 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2105 }
2106 res = compareFileMem(result, base, size);
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002107 if (res != 0) {
2108 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
2109 return(-1);
2110 }
William M. Brackca15a542005-07-06 20:41:33 +00002111 }
2112 if (doc != NULL) {
2113 if (base != NULL)
2114 xmlFree((char *)base);
2115 xmlFreeDoc(doc);
2116 }
William M. Brackca15a542005-07-06 20:41:33 +00002117 if (err != NULL) {
2118 res = compareFileMem(err, testErrors, testErrorsSize);
2119 if (res != 0) {
2120 fprintf(stderr, "Error for %s failed\n", filename);
2121 return(-1);
2122 }
2123 } else if (options & XML_PARSE_DTDVALID) {
2124 if (testErrorsSize != 0)
2125 fprintf(stderr, "Validation for %s failed\n", filename);
2126 }
2127
2128 return(0);
2129}
2130
2131#ifdef LIBXML_READER_ENABLED
2132/************************************************************************
2133 * *
2134 * Reader based tests *
2135 * *
2136 ************************************************************************/
2137
2138static void processNode(FILE *out, xmlTextReaderPtr reader) {
2139 const xmlChar *name, *value;
2140 int type, empty;
2141
2142 type = xmlTextReaderNodeType(reader);
2143 empty = xmlTextReaderIsEmptyElement(reader);
2144
2145 name = xmlTextReaderConstName(reader);
2146 if (name == NULL)
2147 name = BAD_CAST "--";
2148
2149 value = xmlTextReaderConstValue(reader);
2150
Daniel Veillardaa6de472008-08-25 14:53:31 +00002151
2152 fprintf(out, "%d %d %s %d %d",
William M. Brackca15a542005-07-06 20:41:33 +00002153 xmlTextReaderDepth(reader),
2154 type,
2155 name,
2156 empty,
2157 xmlTextReaderHasValue(reader));
2158 if (value == NULL)
2159 fprintf(out, "\n");
2160 else {
2161 fprintf(out, " %s\n", value);
2162 }
2163}
2164static int
2165streamProcessTest(const char *filename, const char *result, const char *err,
Daniel Veillarda7982ce2012-10-25 15:39:39 +08002166 xmlTextReaderPtr reader, const char *rng, int options) {
William M. Brackca15a542005-07-06 20:41:33 +00002167 int ret;
2168 char *temp = NULL;
2169 FILE *t = NULL;
2170
2171 if (reader == NULL)
2172 return(-1);
2173
2174 nb_tests++;
2175 if (result != NULL) {
2176 temp = resultFilename(filename, "", ".res");
2177 if (temp == NULL) {
2178 fprintf(stderr, "Out of memory\n");
2179 fatalError();
2180 }
2181 t = fopen(temp, "wb");
2182 if (t == NULL) {
2183 fprintf(stderr, "Can't open temp file %s\n", temp);
2184 free(temp);
2185 return(-1);
2186 }
2187 }
2188#ifdef LIBXML_SCHEMAS_ENABLED
2189 if (rng != NULL) {
2190 ret = xmlTextReaderRelaxNGValidate(reader, rng);
2191 if (ret < 0) {
2192 testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n",
2193 rng);
2194 fclose(t);
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002195 if (temp != NULL) {
2196 unlink(temp);
2197 free(temp);
2198 }
William M. Brackca15a542005-07-06 20:41:33 +00002199 return(0);
2200 }
2201 }
2202#endif
2203 xmlGetWarningsDefaultValue = 1;
2204 ret = xmlTextReaderRead(reader);
2205 while (ret == 1) {
2206 if ((t != NULL) && (rng == NULL))
2207 processNode(t, reader);
2208 ret = xmlTextReaderRead(reader);
2209 }
2210 if (ret != 0) {
2211 testErrorHandler(NULL, "%s : failed to parse\n", filename);
2212 }
2213 if (rng != NULL) {
2214 if (xmlTextReaderIsValid(reader) != 1) {
2215 testErrorHandler(NULL, "%s fails to validate\n", filename);
2216 } else {
2217 testErrorHandler(NULL, "%s validates\n", filename);
2218 }
2219 }
2220 xmlGetWarningsDefaultValue = 0;
2221 if (t != NULL) {
2222 fclose(t);
2223 ret = compareFiles(temp, result);
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002224 if (temp != NULL) {
2225 unlink(temp);
2226 free(temp);
2227 }
William M. Brackca15a542005-07-06 20:41:33 +00002228 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002229 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002230 return(-1);
2231 }
2232 }
2233 if (err != NULL) {
2234 ret = compareFileMem(err, testErrors, testErrorsSize);
2235 if (ret != 0) {
2236 fprintf(stderr, "Error for %s failed\n", filename);
2237 printf("%s", testErrors);
2238 return(-1);
2239 }
2240 }
2241
2242 return(0);
2243}
2244
2245/**
2246 * streamParseTest:
2247 * @filename: the file to parse
2248 * @result: the file with expected result
2249 * @err: the file with error messages
2250 *
2251 * Parse a file using the reader API and check for errors.
2252 *
2253 * Returns 0 in case of success, an error code otherwise
2254 */
2255static int
2256streamParseTest(const char *filename, const char *result, const char *err,
2257 int options) {
2258 xmlTextReaderPtr reader;
2259 int ret;
2260
2261 reader = xmlReaderForFile(filename, NULL, options);
Daniel Veillarda7982ce2012-10-25 15:39:39 +08002262 ret = streamProcessTest(filename, result, err, reader, NULL, options);
William M. Brackca15a542005-07-06 20:41:33 +00002263 xmlFreeTextReader(reader);
2264 return(ret);
2265}
2266
2267/**
2268 * walkerParseTest:
2269 * @filename: the file to parse
2270 * @result: the file with expected result
2271 * @err: the file with error messages
2272 *
2273 * Parse a file using the walker, i.e. a reader built from a atree.
2274 *
2275 * Returns 0 in case of success, an error code otherwise
2276 */
2277static int
2278walkerParseTest(const char *filename, const char *result, const char *err,
2279 int options) {
2280 xmlDocPtr doc;
2281 xmlTextReaderPtr reader;
2282 int ret;
2283
2284 doc = xmlReadFile(filename, NULL, options);
2285 if (doc == NULL) {
2286 fprintf(stderr, "Failed to parse %s\n", filename);
2287 return(-1);
2288 }
2289 reader = xmlReaderWalker(doc);
Daniel Veillarda7982ce2012-10-25 15:39:39 +08002290 ret = streamProcessTest(filename, result, err, reader, NULL, options);
William M. Brackca15a542005-07-06 20:41:33 +00002291 xmlFreeTextReader(reader);
2292 xmlFreeDoc(doc);
2293 return(ret);
2294}
2295
2296/**
2297 * streamMemParseTest:
2298 * @filename: the file to parse
2299 * @result: the file with expected result
2300 * @err: the file with error messages
2301 *
2302 * Parse a file using the reader API from memory and check for errors.
2303 *
2304 * Returns 0 in case of success, an error code otherwise
2305 */
2306static int
2307streamMemParseTest(const char *filename, const char *result, const char *err,
2308 int options) {
2309 xmlTextReaderPtr reader;
2310 int ret;
2311 const char *base;
2312 int size;
2313
2314 /*
2315 * load and parse the memory
2316 */
2317 if (loadMem(filename, &base, &size) != 0) {
2318 fprintf(stderr, "Failed to load %s\n", filename);
2319 return(-1);
2320 }
2321 reader = xmlReaderForMemory(base, size, filename, NULL, options);
Daniel Veillarda7982ce2012-10-25 15:39:39 +08002322 ret = streamProcessTest(filename, result, err, reader, NULL, options);
William M. Brackca15a542005-07-06 20:41:33 +00002323 free((char *)base);
2324 xmlFreeTextReader(reader);
2325 return(ret);
2326}
2327#endif
2328
2329#ifdef LIBXML_XPATH_ENABLED
2330#ifdef LIBXML_DEBUG_ENABLED
2331/************************************************************************
2332 * *
2333 * XPath and XPointer based tests *
2334 * *
2335 ************************************************************************/
2336
Daniel Veillard24505b02005-07-28 23:49:35 +00002337static FILE *xpathOutput;
2338static xmlDocPtr xpathDocument;
William M. Brackca15a542005-07-06 20:41:33 +00002339
2340static void
Nick Wellnhofer1fc55ca2016-06-25 12:35:09 +02002341ignoreGenericError(void *ctx ATTRIBUTE_UNUSED,
2342 const char *msg ATTRIBUTE_UNUSED, ...) {
2343}
2344
2345static void
William M. Brackca15a542005-07-06 20:41:33 +00002346testXPath(const char *str, int xptr, int expr) {
Nick Wellnhofer1fc55ca2016-06-25 12:35:09 +02002347 xmlGenericErrorFunc handler = ignoreGenericError;
William M. Brackca15a542005-07-06 20:41:33 +00002348 xmlXPathObjectPtr res;
2349 xmlXPathContextPtr ctxt;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002350
Nick Wellnhofer1fc55ca2016-06-25 12:35:09 +02002351 /* Don't print generic errors to stderr. */
2352 initGenericErrorDefaultFunc(&handler);
2353
William M. Brackca15a542005-07-06 20:41:33 +00002354 nb_tests++;
2355#if defined(LIBXML_XPTR_ENABLED)
2356 if (xptr) {
2357 ctxt = xmlXPtrNewContext(xpathDocument, NULL, NULL);
2358 res = xmlXPtrEval(BAD_CAST str, ctxt);
2359 } else {
2360#endif
2361 ctxt = xmlXPathNewContext(xpathDocument);
2362 ctxt->node = xmlDocGetRootElement(xpathDocument);
2363 if (expr)
2364 res = xmlXPathEvalExpression(BAD_CAST str, ctxt);
2365 else {
2366 /* res = xmlXPathEval(BAD_CAST str, ctxt); */
2367 xmlXPathCompExprPtr comp;
2368
2369 comp = xmlXPathCompile(BAD_CAST str);
2370 if (comp != NULL) {
2371 res = xmlXPathCompiledEval(comp, ctxt);
2372 xmlXPathFreeCompExpr(comp);
2373 } else
2374 res = NULL;
2375 }
2376#if defined(LIBXML_XPTR_ENABLED)
2377 }
2378#endif
2379 xmlXPathDebugDumpObject(xpathOutput, res, 0);
2380 xmlXPathFreeObject(res);
2381 xmlXPathFreeContext(ctxt);
Nick Wellnhofer1fc55ca2016-06-25 12:35:09 +02002382
2383 /* Reset generic error handler. */
2384 initGenericErrorDefaultFunc(NULL);
William M. Brackca15a542005-07-06 20:41:33 +00002385}
2386
2387/**
2388 * xpathExprTest:
2389 * @filename: the file to parse
2390 * @result: the file with expected result
2391 * @err: the file with error messages
2392 *
2393 * Parse a file containing XPath standalone expressions and evaluate them
2394 *
2395 * Returns 0 in case of success, an error code otherwise
2396 */
2397static int
2398xpathCommonTest(const char *filename, const char *result,
2399 int xptr, int expr) {
2400 FILE *input;
2401 char expression[5000];
2402 int len, ret = 0;
2403 char *temp;
2404
2405 temp = resultFilename(filename, "", ".res");
2406 if (temp == NULL) {
2407 fprintf(stderr, "Out of memory\n");
2408 fatalError();
2409 }
2410 xpathOutput = fopen(temp, "wb");
2411 if (xpathOutput == NULL) {
2412 fprintf(stderr, "failed to open output file %s\n", temp);
2413 free(temp);
2414 return(-1);
2415 }
2416
2417 input = fopen(filename, "rb");
2418 if (input == NULL) {
2419 xmlGenericError(xmlGenericErrorContext,
2420 "Cannot open %s for reading\n", filename);
2421 free(temp);
2422 return(-1);
2423 }
2424 while (fgets(expression, 4500, input) != NULL) {
2425 len = strlen(expression);
2426 len--;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002427 while ((len >= 0) &&
William M. Brackca15a542005-07-06 20:41:33 +00002428 ((expression[len] == '\n') || (expression[len] == '\t') ||
2429 (expression[len] == '\r') || (expression[len] == ' '))) len--;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002430 expression[len + 1] = 0;
William M. Brackca15a542005-07-06 20:41:33 +00002431 if (len >= 0) {
2432 fprintf(xpathOutput,
2433 "\n========================\nExpression: %s\n",
2434 expression) ;
2435 testXPath(expression, xptr, expr);
2436 }
2437 }
2438
2439 fclose(input);
2440 fclose(xpathOutput);
2441 if (result != NULL) {
2442 ret = compareFiles(temp, result);
2443 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002444 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002445 }
2446 }
2447
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002448 if (temp != NULL) {
2449 unlink(temp);
2450 free(temp);
2451 }
William M. Brackca15a542005-07-06 20:41:33 +00002452 return(ret);
2453}
2454
2455/**
2456 * xpathExprTest:
2457 * @filename: the file to parse
2458 * @result: the file with expected result
2459 * @err: the file with error messages
2460 *
2461 * Parse a file containing XPath standalone expressions and evaluate them
2462 *
2463 * Returns 0 in case of success, an error code otherwise
2464 */
2465static int
2466xpathExprTest(const char *filename, const char *result,
2467 const char *err ATTRIBUTE_UNUSED,
2468 int options ATTRIBUTE_UNUSED) {
2469 return(xpathCommonTest(filename, result, 0, 1));
2470}
2471
2472/**
2473 * xpathDocTest:
2474 * @filename: the file to parse
2475 * @result: the file with expected result
2476 * @err: the file with error messages
2477 *
2478 * Parse a file containing XPath expressions and evaluate them against
2479 * a set of corresponding documents.
2480 *
2481 * Returns 0 in case of success, an error code otherwise
2482 */
2483static int
2484xpathDocTest(const char *filename,
2485 const char *resul ATTRIBUTE_UNUSED,
2486 const char *err ATTRIBUTE_UNUSED,
2487 int options) {
2488
2489 char pattern[500];
2490 char result[500];
2491 glob_t globbuf;
2492 size_t i;
2493 int ret = 0, res;
2494
2495 xpathDocument = xmlReadFile(filename, NULL,
2496 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2497 if (xpathDocument == NULL) {
2498 fprintf(stderr, "Failed to load %s\n", filename);
2499 return(-1);
2500 }
2501
2502 snprintf(pattern, 499, "./test/XPath/tests/%s*", baseFilename(filename));
2503 pattern[499] = 0;
2504 globbuf.gl_offs = 0;
2505 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2506 for (i = 0;i < globbuf.gl_pathc;i++) {
2507 snprintf(result, 499, "result/XPath/tests/%s",
2508 baseFilename(globbuf.gl_pathv[i]));
2509 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 0, 0);
2510 if (res != 0)
2511 ret = res;
2512 }
2513 globfree(&globbuf);
2514
2515 xmlFreeDoc(xpathDocument);
2516 return(ret);
2517}
2518
2519#ifdef LIBXML_XPTR_ENABLED
2520/**
2521 * xptrDocTest:
2522 * @filename: the file to parse
2523 * @result: the file with expected result
2524 * @err: the file with error messages
2525 *
2526 * Parse a file containing XPath expressions and evaluate them against
2527 * a set of corresponding documents.
2528 *
2529 * Returns 0 in case of success, an error code otherwise
2530 */
2531static int
2532xptrDocTest(const char *filename,
2533 const char *resul ATTRIBUTE_UNUSED,
2534 const char *err ATTRIBUTE_UNUSED,
2535 int options) {
2536
2537 char pattern[500];
2538 char result[500];
2539 glob_t globbuf;
2540 size_t i;
2541 int ret = 0, res;
2542
2543 xpathDocument = xmlReadFile(filename, NULL,
2544 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2545 if (xpathDocument == NULL) {
2546 fprintf(stderr, "Failed to load %s\n", filename);
2547 return(-1);
2548 }
2549
2550 snprintf(pattern, 499, "./test/XPath/xptr/%s*", baseFilename(filename));
2551 pattern[499] = 0;
2552 globbuf.gl_offs = 0;
2553 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2554 for (i = 0;i < globbuf.gl_pathc;i++) {
2555 snprintf(result, 499, "result/XPath/xptr/%s",
2556 baseFilename(globbuf.gl_pathv[i]));
2557 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 1, 0);
2558 if (res != 0)
2559 ret = res;
2560 }
2561 globfree(&globbuf);
2562
2563 xmlFreeDoc(xpathDocument);
2564 return(ret);
2565}
2566#endif /* LIBXML_XPTR_ENABLED */
2567
2568/**
2569 * xmlidDocTest:
2570 * @filename: the file to parse
2571 * @result: the file with expected result
2572 * @err: the file with error messages
2573 *
2574 * Parse a file containing xml:id and check for errors and verify
2575 * that XPath queries will work on them as expected.
2576 *
2577 * Returns 0 in case of success, an error code otherwise
2578 */
2579static int
2580xmlidDocTest(const char *filename,
2581 const char *result,
2582 const char *err,
2583 int options) {
2584
2585 int res = 0;
2586 int ret = 0;
2587 char *temp;
2588
2589 xpathDocument = xmlReadFile(filename, NULL,
2590 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2591 if (xpathDocument == NULL) {
2592 fprintf(stderr, "Failed to load %s\n", filename);
2593 return(-1);
2594 }
2595
2596 temp = resultFilename(filename, "", ".res");
2597 if (temp == NULL) {
2598 fprintf(stderr, "Out of memory\n");
2599 fatalError();
2600 }
2601 xpathOutput = fopen(temp, "wb");
2602 if (xpathOutput == NULL) {
2603 fprintf(stderr, "failed to open output file %s\n", temp);
2604 xmlFreeDoc(xpathDocument);
2605 free(temp);
2606 return(-1);
2607 }
2608
2609 testXPath("id('bar')", 0, 0);
2610
2611 fclose(xpathOutput);
2612 if (result != NULL) {
2613 ret = compareFiles(temp, result);
2614 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002615 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002616 res = 1;
2617 }
2618 }
2619
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002620 if (temp != NULL) {
2621 unlink(temp);
2622 free(temp);
2623 }
William M. Brackca15a542005-07-06 20:41:33 +00002624 xmlFreeDoc(xpathDocument);
2625
2626 if (err != NULL) {
2627 ret = compareFileMem(err, testErrors, testErrorsSize);
2628 if (ret != 0) {
2629 fprintf(stderr, "Error for %s failed\n", filename);
2630 res = 1;
2631 }
2632 }
2633 return(res);
2634}
2635
2636#endif /* LIBXML_DEBUG_ENABLED */
2637#endif /* XPATH */
2638/************************************************************************
2639 * *
2640 * URI based tests *
2641 * *
2642 ************************************************************************/
2643
2644static void
2645handleURI(const char *str, const char *base, FILE *o) {
2646 int ret;
2647 xmlURIPtr uri;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002648 xmlChar *res = NULL;
William M. Brackca15a542005-07-06 20:41:33 +00002649
2650 uri = xmlCreateURI();
2651
2652 if (base == NULL) {
2653 ret = xmlParseURIReference(uri, str);
2654 if (ret != 0)
2655 fprintf(o, "%s : error %d\n", str, ret);
2656 else {
2657 xmlNormalizeURIPath(uri->path);
2658 xmlPrintURI(o, uri);
2659 fprintf(o, "\n");
2660 }
2661 } else {
2662 res = xmlBuildURI((xmlChar *)str, (xmlChar *) base);
2663 if (res != NULL) {
2664 fprintf(o, "%s\n", (char *) res);
2665 }
2666 else
2667 fprintf(o, "::ERROR::\n");
2668 }
2669 if (res != NULL)
2670 xmlFree(res);
William M. Brackca15a542005-07-06 20:41:33 +00002671 xmlFreeURI(uri);
2672}
2673
2674/**
2675 * uriCommonTest:
2676 * @filename: the file to parse
2677 * @result: the file with expected result
2678 * @err: the file with error messages
2679 *
2680 * Parse a file containing URI and check for errors
2681 *
2682 * Returns 0 in case of success, an error code otherwise
2683 */
2684static int
2685uriCommonTest(const char *filename,
2686 const char *result,
2687 const char *err,
2688 const char *base) {
2689 char *temp;
2690 FILE *o, *f;
2691 char str[1024];
2692 int res = 0, i, ret;
2693
2694 temp = resultFilename(filename, "", ".res");
2695 if (temp == NULL) {
2696 fprintf(stderr, "Out of memory\n");
2697 fatalError();
2698 }
2699 o = fopen(temp, "wb");
2700 if (o == NULL) {
2701 fprintf(stderr, "failed to open output file %s\n", temp);
2702 free(temp);
2703 return(-1);
2704 }
2705 f = fopen(filename, "rb");
2706 if (f == NULL) {
2707 fprintf(stderr, "failed to open input file %s\n", filename);
2708 fclose(o);
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002709 if (temp != NULL) {
2710 unlink(temp);
2711 free(temp);
2712 }
William M. Brackca15a542005-07-06 20:41:33 +00002713 return(-1);
2714 }
2715
2716 while (1) {
2717 /*
2718 * read one line in string buffer.
2719 */
2720 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
2721 break;
2722
2723 /*
2724 * remove the ending spaces
2725 */
2726 i = strlen(str);
2727 while ((i > 0) &&
2728 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
2729 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
2730 i--;
2731 str[i] = 0;
2732 }
2733 nb_tests++;
2734 handleURI(str, base, o);
2735 }
2736
2737 fclose(f);
2738 fclose(o);
2739
2740 if (result != NULL) {
2741 ret = compareFiles(temp, result);
2742 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002743 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002744 res = 1;
2745 }
2746 }
2747 if (err != NULL) {
2748 ret = compareFileMem(err, testErrors, testErrorsSize);
2749 if (ret != 0) {
2750 fprintf(stderr, "Error for %s failed\n", filename);
2751 res = 1;
2752 }
2753 }
2754
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002755 if (temp != NULL) {
2756 unlink(temp);
2757 free(temp);
2758 }
William M. Brackca15a542005-07-06 20:41:33 +00002759 return(res);
2760}
2761
2762/**
2763 * uriParseTest:
2764 * @filename: the file to parse
2765 * @result: the file with expected result
2766 * @err: the file with error messages
2767 *
2768 * Parse a file containing URI and check for errors
2769 *
2770 * Returns 0 in case of success, an error code otherwise
2771 */
2772static int
2773uriParseTest(const char *filename,
2774 const char *result,
2775 const char *err,
2776 int options ATTRIBUTE_UNUSED) {
2777 return(uriCommonTest(filename, result, err, NULL));
2778}
2779
2780/**
2781 * uriBaseTest:
2782 * @filename: the file to parse
2783 * @result: the file with expected result
2784 * @err: the file with error messages
2785 *
2786 * Parse a file containing URI, compose them against a fixed base and
2787 * check for errors
2788 *
2789 * Returns 0 in case of success, an error code otherwise
2790 */
2791static int
2792uriBaseTest(const char *filename,
2793 const char *result,
2794 const char *err,
2795 int options ATTRIBUTE_UNUSED) {
2796 return(uriCommonTest(filename, result, err,
2797 "http://foo.com/path/to/index.html?orig#help"));
2798}
2799
Daniel Veillard336a8e12005-08-07 10:46:19 +00002800static int urip_success = 1;
2801static int urip_current = 0;
2802static const char *urip_testURLs[] = {
2803 "urip://example.com/a b.html",
2804 "urip://example.com/a%20b.html",
2805 "file:///path/to/a b.html",
2806 "file:///path/to/a%20b.html",
2807 "/path/to/a b.html",
2808 "/path/to/a%20b.html",
Daniel Veillardff7227f2012-08-20 20:58:24 +08002809 "urip://example.com/r" "\xe9" "sum" "\xe9" ".html",
Daniel Veillard336a8e12005-08-07 10:46:19 +00002810 "urip://example.com/test?a=1&b=2%263&c=4#foo",
2811 NULL
2812};
2813static const char *urip_rcvsURLs[] = {
2814 /* it is an URI the strings must be escaped */
2815 "urip://example.com/a%20b.html",
2816 /* check that % escaping is not broken */
2817 "urip://example.com/a%20b.html",
2818 /* it's an URI path the strings must be escaped */
2819 "file:///path/to/a%20b.html",
2820 /* check that % escaping is not broken */
2821 "file:///path/to/a%20b.html",
2822 /* this is not an URI, this is a path, so this should not be escaped */
2823 "/path/to/a b.html",
2824 /* check that paths with % are not broken */
2825 "/path/to/a%20b.html",
2826 /* out of context the encoding can't be guessed byte by byte conversion */
2827 "urip://example.com/r%E9sum%E9.html",
2828 /* verify we don't destroy URIs especially the query part */
2829 "urip://example.com/test?a=1&b=2%263&c=4#foo",
2830 NULL
2831};
2832static const char *urip_res = "<list/>";
2833static const char *urip_cur = NULL;
2834static int urip_rlen;
2835
2836/**
2837 * uripMatch:
2838 * @URI: an URI to test
2839 *
2840 * Check for an urip: query
2841 *
2842 * Returns 1 if yes and 0 if another Input module should be used
2843 */
2844static int
2845uripMatch(const char * URI) {
2846 if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog")))
2847 return(0);
2848 /* Verify we received the escaped URL */
2849 if (strcmp(urip_rcvsURLs[urip_current], URI))
2850 urip_success = 0;
2851 return(1);
2852}
2853
2854/**
2855 * uripOpen:
2856 * @URI: an URI to test
2857 *
2858 * Return a pointer to the urip: query handler, in this example simply
2859 * the urip_current pointer...
2860 *
2861 * Returns an Input context or NULL in case or error
2862 */
2863static void *
2864uripOpen(const char * URI) {
2865 if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog")))
2866 return(NULL);
2867 /* Verify we received the escaped URL */
2868 if (strcmp(urip_rcvsURLs[urip_current], URI))
2869 urip_success = 0;
2870 urip_cur = urip_res;
2871 urip_rlen = strlen(urip_res);
2872 return((void *) urip_cur);
2873}
2874
2875/**
2876 * uripClose:
2877 * @context: the read context
2878 *
2879 * Close the urip: query handler
2880 *
2881 * Returns 0 or -1 in case of error
2882 */
2883static int
2884uripClose(void * context) {
2885 if (context == NULL) return(-1);
2886 urip_cur = NULL;
2887 urip_rlen = 0;
2888 return(0);
2889}
2890
2891/**
2892 * uripRead:
2893 * @context: the read context
2894 * @buffer: where to store data
2895 * @len: number of bytes to read
2896 *
2897 * Implement an urip: query read.
2898 *
2899 * Returns the number of bytes read or -1 in case of error
2900 */
2901static int
2902uripRead(void * context, char * buffer, int len) {
2903 const char *ptr = (const char *) context;
2904
2905 if ((context == NULL) || (buffer == NULL) || (len < 0))
2906 return(-1);
2907
2908 if (len > urip_rlen) len = urip_rlen;
2909 memcpy(buffer, ptr, len);
2910 urip_rlen -= len;
2911 return(len);
2912}
2913
2914static int
2915urip_checkURL(const char *URL) {
2916 xmlDocPtr doc;
2917
2918 doc = xmlReadFile(URL, NULL, 0);
2919 if (doc == NULL)
2920 return(-1);
2921 xmlFreeDoc(doc);
2922 return(1);
2923}
2924
2925/**
2926 * uriPathTest:
2927 * @filename: ignored
2928 * @result: ignored
2929 * @err: ignored
2930 *
2931 * Run a set of tests to check how Path and URI are handled before
2932 * being passed to the I/O layer
2933 *
2934 * Returns 0 in case of success, an error code otherwise
2935 */
2936static int
2937uriPathTest(const char *filename ATTRIBUTE_UNUSED,
2938 const char *result ATTRIBUTE_UNUSED,
2939 const char *err ATTRIBUTE_UNUSED,
2940 int options ATTRIBUTE_UNUSED) {
2941 int parsed;
2942 int failures = 0;
2943
2944 /*
2945 * register the new I/O handlers
2946 */
2947 if (xmlRegisterInputCallbacks(uripMatch, uripOpen, uripRead, uripClose) < 0)
2948 {
2949 fprintf(stderr, "failed to register HTTP handler\n");
2950 return(-1);
2951 }
2952
2953 for (urip_current = 0;urip_testURLs[urip_current] != NULL;urip_current++) {
2954 urip_success = 1;
2955 parsed = urip_checkURL(urip_testURLs[urip_current]);
2956 if (urip_success != 1) {
2957 fprintf(stderr, "failed the URL passing test for %s",
2958 urip_testURLs[urip_current]);
2959 failures++;
2960 } else if (parsed != 1) {
2961 fprintf(stderr, "failed the parsing test for %s",
2962 urip_testURLs[urip_current]);
2963 failures++;
2964 }
2965 nb_tests++;
2966 }
2967
2968 xmlPopInputCallbacks();
2969 return(failures);
2970}
2971
William M. Brackca15a542005-07-06 20:41:33 +00002972#ifdef LIBXML_SCHEMAS_ENABLED
2973/************************************************************************
2974 * *
2975 * Schemas tests *
2976 * *
2977 ************************************************************************/
2978static int
2979schemasOneTest(const char *sch,
2980 const char *filename,
2981 const char *result,
2982 const char *err,
2983 int options,
2984 xmlSchemaPtr schemas) {
2985 xmlDocPtr doc;
2986 xmlSchemaValidCtxtPtr ctxt;
2987 int ret = 0;
Daniel Veillard381ff362006-06-18 17:31:31 +00002988 int validResult = 0;
William M. Brackca15a542005-07-06 20:41:33 +00002989 char *temp;
2990 FILE *schemasOutput;
2991
2992 doc = xmlReadFile(filename, NULL, options);
2993 if (doc == NULL) {
2994 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
2995 return(-1);
2996 }
2997
2998 temp = resultFilename(result, "", ".res");
2999 if (temp == NULL) {
3000 fprintf(stderr, "Out of memory\n");
3001 fatalError();
3002 }
3003 schemasOutput = fopen(temp, "wb");
3004 if (schemasOutput == NULL) {
3005 fprintf(stderr, "failed to open output file %s\n", temp);
3006 xmlFreeDoc(doc);
3007 free(temp);
3008 return(-1);
3009 }
3010
3011 ctxt = xmlSchemaNewValidCtxt(schemas);
3012 xmlSchemaSetValidErrors(ctxt,
3013 (xmlSchemaValidityErrorFunc) testErrorHandler,
3014 (xmlSchemaValidityWarningFunc) testErrorHandler,
3015 ctxt);
Daniel Veillard381ff362006-06-18 17:31:31 +00003016 validResult = xmlSchemaValidateDoc(ctxt, doc);
3017 if (validResult == 0) {
William M. Brackca15a542005-07-06 20:41:33 +00003018 fprintf(schemasOutput, "%s validates\n", filename);
Daniel Veillard381ff362006-06-18 17:31:31 +00003019 } else if (validResult > 0) {
William M. Brackca15a542005-07-06 20:41:33 +00003020 fprintf(schemasOutput, "%s fails to validate\n", filename);
3021 } else {
3022 fprintf(schemasOutput, "%s validation generated an internal error\n",
3023 filename);
3024 }
3025 fclose(schemasOutput);
3026 if (result) {
3027 if (compareFiles(temp, result)) {
3028 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
3029 ret = 1;
3030 }
3031 }
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003032 if (temp != NULL) {
3033 unlink(temp);
3034 free(temp);
3035 }
William M. Brackca15a542005-07-06 20:41:33 +00003036
Daniel Veillard381ff362006-06-18 17:31:31 +00003037 if ((validResult != 0) && (err != NULL)) {
William M. Brackca15a542005-07-06 20:41:33 +00003038 if (compareFileMem(err, testErrors, testErrorsSize)) {
3039 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
3040 ret = 1;
3041 }
3042 }
3043
William M. Brackca15a542005-07-06 20:41:33 +00003044 xmlSchemaFreeValidCtxt(ctxt);
3045 xmlFreeDoc(doc);
3046 return(ret);
3047}
3048/**
3049 * schemasTest:
3050 * @filename: the schemas file
3051 * @result: the file with expected result
3052 * @err: the file with error messages
3053 *
3054 * Parse a file containing URI, compose them against a fixed base and
3055 * check for errors
3056 *
3057 * Returns 0 in case of success, an error code otherwise
3058 */
3059static int
3060schemasTest(const char *filename,
3061 const char *resul ATTRIBUTE_UNUSED,
3062 const char *errr ATTRIBUTE_UNUSED,
3063 int options) {
3064 const char *base = baseFilename(filename);
3065 const char *base2;
3066 const char *instance;
3067 xmlSchemaParserCtxtPtr ctxt;
3068 xmlSchemaPtr schemas;
3069 int res = 0, len, ret;
3070 char pattern[500];
3071 char prefix[500];
3072 char result[500];
3073 char err[500];
3074 glob_t globbuf;
3075 size_t i;
3076 char count = 0;
3077
3078 /* first compile the schemas if possible */
3079 ctxt = xmlSchemaNewParserCtxt(filename);
3080 xmlSchemaSetParserErrors(ctxt,
3081 (xmlSchemaValidityErrorFunc) testErrorHandler,
3082 (xmlSchemaValidityWarningFunc) testErrorHandler,
3083 ctxt);
3084 schemas = xmlSchemaParse(ctxt);
3085 xmlSchemaFreeParserCtxt(ctxt);
3086
3087 /*
3088 * most of the mess is about the output filenames generated by the Makefile
3089 */
3090 len = strlen(base);
3091 if ((len > 499) || (len < 5)) {
3092 xmlSchemaFree(schemas);
3093 return(-1);
3094 }
3095 len -= 4; /* remove trailing .xsd */
3096 if (base[len - 2] == '_') {
3097 len -= 2; /* remove subtest number */
3098 }
3099 if (base[len - 2] == '_') {
3100 len -= 2; /* remove subtest number */
3101 }
3102 memcpy(prefix, base, len);
3103 prefix[len] = 0;
3104
3105 snprintf(pattern, 499, "./test/schemas/%s_?.xml", prefix);
3106 pattern[499] = 0;
3107
3108 if (base[len] == '_') {
3109 len += 2;
3110 memcpy(prefix, base, len);
3111 prefix[len] = 0;
3112 }
3113
3114 globbuf.gl_offs = 0;
3115 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3116 for (i = 0;i < globbuf.gl_pathc;i++) {
3117 testErrorsSize = 0;
3118 testErrors[0] = 0;
3119 instance = globbuf.gl_pathv[i];
3120 base2 = baseFilename(instance);
3121 len = strlen(base2);
3122 if ((len > 6) && (base2[len - 6] == '_')) {
3123 count = base2[len - 5];
3124 snprintf(result, 499, "result/schemas/%s_%c",
3125 prefix, count);
3126 result[499] = 0;
3127 snprintf(err, 499, "result/schemas/%s_%c.err",
3128 prefix, count);
3129 err[499] = 0;
3130 } else {
3131 fprintf(stderr, "don't know how to process %s\n", instance);
3132 continue;
3133 }
3134 if (schemas == NULL) {
3135 } else {
3136 nb_tests++;
3137 ret = schemasOneTest(filename, instance, result, err,
3138 options, schemas);
Daniel Veillard93e577f2005-11-15 08:50:04 +00003139 if (ret != 0)
3140 res = ret;
William M. Brackca15a542005-07-06 20:41:33 +00003141 }
3142 }
3143 globfree(&globbuf);
3144 xmlSchemaFree(schemas);
3145
3146 return(res);
3147}
3148
3149/************************************************************************
3150 * *
3151 * Schemas tests *
3152 * *
3153 ************************************************************************/
3154static int
3155rngOneTest(const char *sch,
3156 const char *filename,
3157 const char *result,
3158 const char *err,
3159 int options,
3160 xmlRelaxNGPtr schemas) {
3161 xmlDocPtr doc;
3162 xmlRelaxNGValidCtxtPtr ctxt;
3163 int ret = 0;
3164 char *temp;
3165 FILE *schemasOutput;
3166
3167 doc = xmlReadFile(filename, NULL, options);
3168 if (doc == NULL) {
3169 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
3170 return(-1);
3171 }
3172
3173 temp = resultFilename(result, "", ".res");
3174 if (temp == NULL) {
3175 fprintf(stderr, "Out of memory\n");
3176 fatalError();
3177 }
3178 schemasOutput = fopen(temp, "wb");
3179 if (schemasOutput == NULL) {
3180 fprintf(stderr, "failed to open output file %s\n", temp);
3181 xmlFreeDoc(doc);
3182 free(temp);
3183 return(-1);
3184 }
3185
3186 ctxt = xmlRelaxNGNewValidCtxt(schemas);
3187 xmlRelaxNGSetValidErrors(ctxt,
3188 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
3189 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
3190 ctxt);
3191 ret = xmlRelaxNGValidateDoc(ctxt, doc);
3192 if (ret == 0) {
3193 testErrorHandler(NULL, "%s validates\n", filename);
3194 } else if (ret > 0) {
3195 testErrorHandler(NULL, "%s fails to validate\n", filename);
3196 } else {
3197 testErrorHandler(NULL, "%s validation generated an internal error\n",
3198 filename);
3199 }
3200 fclose(schemasOutput);
Daniel Veillard594e5df2009-09-07 14:58:47 +02003201 ret = 0;
William M. Brackca15a542005-07-06 20:41:33 +00003202 if (result) {
3203 if (compareFiles(temp, result)) {
3204 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
3205 ret = 1;
3206 }
3207 }
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003208 if (temp != NULL) {
3209 unlink(temp);
3210 free(temp);
3211 }
William M. Brackca15a542005-07-06 20:41:33 +00003212
3213 if (err != NULL) {
3214 if (compareFileMem(err, testErrors, testErrorsSize)) {
3215 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
3216 ret = 1;
3217 printf("%s", testErrors);
3218 }
3219 }
3220
3221
3222 xmlRelaxNGFreeValidCtxt(ctxt);
3223 xmlFreeDoc(doc);
3224 return(ret);
3225}
3226/**
3227 * rngTest:
3228 * @filename: the schemas file
3229 * @result: the file with expected result
3230 * @err: the file with error messages
3231 *
3232 * Parse an RNG schemas and then apply it to the related .xml
3233 *
3234 * Returns 0 in case of success, an error code otherwise
3235 */
3236static int
3237rngTest(const char *filename,
3238 const char *resul ATTRIBUTE_UNUSED,
3239 const char *errr ATTRIBUTE_UNUSED,
3240 int options) {
3241 const char *base = baseFilename(filename);
3242 const char *base2;
3243 const char *instance;
3244 xmlRelaxNGParserCtxtPtr ctxt;
3245 xmlRelaxNGPtr schemas;
Rob Richardsc9667902010-01-22 08:24:25 -05003246 int res = 0, len, ret = 0;
William M. Brackca15a542005-07-06 20:41:33 +00003247 char pattern[500];
3248 char prefix[500];
3249 char result[500];
3250 char err[500];
3251 glob_t globbuf;
3252 size_t i;
3253 char count = 0;
3254
3255 /* first compile the schemas if possible */
3256 ctxt = xmlRelaxNGNewParserCtxt(filename);
3257 xmlRelaxNGSetParserErrors(ctxt,
3258 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
3259 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
3260 ctxt);
3261 schemas = xmlRelaxNGParse(ctxt);
3262 xmlRelaxNGFreeParserCtxt(ctxt);
3263
3264 /*
3265 * most of the mess is about the output filenames generated by the Makefile
3266 */
3267 len = strlen(base);
3268 if ((len > 499) || (len < 5)) {
3269 xmlRelaxNGFree(schemas);
3270 return(-1);
3271 }
3272 len -= 4; /* remove trailing .rng */
3273 memcpy(prefix, base, len);
3274 prefix[len] = 0;
3275
3276 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
3277 pattern[499] = 0;
3278
3279 globbuf.gl_offs = 0;
3280 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3281 for (i = 0;i < globbuf.gl_pathc;i++) {
3282 testErrorsSize = 0;
3283 testErrors[0] = 0;
3284 instance = globbuf.gl_pathv[i];
3285 base2 = baseFilename(instance);
3286 len = strlen(base2);
3287 if ((len > 6) && (base2[len - 6] == '_')) {
3288 count = base2[len - 5];
3289 snprintf(result, 499, "result/relaxng/%s_%c",
3290 prefix, count);
3291 result[499] = 0;
3292 snprintf(err, 499, "result/relaxng/%s_%c.err",
3293 prefix, count);
3294 err[499] = 0;
3295 } else {
3296 fprintf(stderr, "don't know how to process %s\n", instance);
3297 continue;
3298 }
3299 if (schemas == NULL) {
3300 } else {
3301 nb_tests++;
3302 ret = rngOneTest(filename, instance, result, err,
3303 options, schemas);
3304 if (res != 0)
3305 ret = res;
3306 }
3307 }
3308 globfree(&globbuf);
3309 xmlRelaxNGFree(schemas);
3310
Daniel Veillard594e5df2009-09-07 14:58:47 +02003311 return(ret);
William M. Brackca15a542005-07-06 20:41:33 +00003312}
3313
3314#ifdef LIBXML_READER_ENABLED
3315/**
3316 * rngStreamTest:
3317 * @filename: the schemas file
3318 * @result: the file with expected result
3319 * @err: the file with error messages
3320 *
Daniel Veillardaa6de472008-08-25 14:53:31 +00003321 * Parse a set of files with streaming, applying an RNG schemas
William M. Brackca15a542005-07-06 20:41:33 +00003322 *
3323 * Returns 0 in case of success, an error code otherwise
3324 */
3325static int
3326rngStreamTest(const char *filename,
3327 const char *resul ATTRIBUTE_UNUSED,
3328 const char *errr ATTRIBUTE_UNUSED,
3329 int options) {
3330 const char *base = baseFilename(filename);
3331 const char *base2;
3332 const char *instance;
3333 int res = 0, len, ret;
3334 char pattern[500];
3335 char prefix[500];
3336 char result[500];
3337 char err[500];
3338 glob_t globbuf;
3339 size_t i;
3340 char count = 0;
3341 xmlTextReaderPtr reader;
3342 int disable_err = 0;
3343
3344 /*
3345 * most of the mess is about the output filenames generated by the Makefile
3346 */
3347 len = strlen(base);
3348 if ((len > 499) || (len < 5)) {
3349 fprintf(stderr, "len(base) == %d !\n", len);
3350 return(-1);
3351 }
3352 len -= 4; /* remove trailing .rng */
3353 memcpy(prefix, base, len);
3354 prefix[len] = 0;
3355
3356 /*
3357 * strictly unifying the error messages is nearly impossible this
3358 * hack is also done in the Makefile
3359 */
3360 if ((!strcmp(prefix, "tutor10_1")) || (!strcmp(prefix, "tutor10_2")) ||
Daniel Veillardec18c962009-08-26 18:37:43 +02003361 (!strcmp(prefix, "tutor3_2")) || (!strcmp(prefix, "307377")) ||
3362 (!strcmp(prefix, "tutor8_2")))
William M. Brackca15a542005-07-06 20:41:33 +00003363 disable_err = 1;
3364
3365 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
3366 pattern[499] = 0;
3367
3368 globbuf.gl_offs = 0;
3369 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3370 for (i = 0;i < globbuf.gl_pathc;i++) {
3371 testErrorsSize = 0;
3372 testErrors[0] = 0;
3373 instance = globbuf.gl_pathv[i];
3374 base2 = baseFilename(instance);
3375 len = strlen(base2);
3376 if ((len > 6) && (base2[len - 6] == '_')) {
3377 count = base2[len - 5];
3378 snprintf(result, 499, "result/relaxng/%s_%c",
3379 prefix, count);
3380 result[499] = 0;
3381 snprintf(err, 499, "result/relaxng/%s_%c.err",
3382 prefix, count);
3383 err[499] = 0;
3384 } else {
3385 fprintf(stderr, "don't know how to process %s\n", instance);
3386 continue;
3387 }
3388 reader = xmlReaderForFile(instance, NULL, options);
3389 if (reader == NULL) {
3390 fprintf(stderr, "Failed to build reder for %s\n", instance);
3391 }
3392 if (disable_err == 1)
Daniel Veillarda7982ce2012-10-25 15:39:39 +08003393 ret = streamProcessTest(instance, result, NULL, reader, filename,
3394 options);
William M. Brackca15a542005-07-06 20:41:33 +00003395 else
Daniel Veillarda7982ce2012-10-25 15:39:39 +08003396 ret = streamProcessTest(instance, result, err, reader, filename,
3397 options);
William M. Brackca15a542005-07-06 20:41:33 +00003398 xmlFreeTextReader(reader);
3399 if (ret != 0) {
3400 fprintf(stderr, "instance %s failed\n", instance);
3401 res = ret;
3402 }
3403 }
3404 globfree(&globbuf);
3405
3406 return(res);
3407}
3408#endif /* READER */
3409
3410#endif
3411
3412#ifdef LIBXML_PATTERN_ENABLED
3413#ifdef LIBXML_READER_ENABLED
3414/************************************************************************
3415 * *
3416 * Patterns tests *
3417 * *
3418 ************************************************************************/
3419static void patternNode(FILE *out, xmlTextReaderPtr reader,
3420 const char *pattern, xmlPatternPtr patternc,
3421 xmlStreamCtxtPtr patstream) {
3422 xmlChar *path = NULL;
3423 int match = -1;
3424 int type, empty;
3425
3426 type = xmlTextReaderNodeType(reader);
3427 empty = xmlTextReaderIsEmptyElement(reader);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003428
William M. Brackca15a542005-07-06 20:41:33 +00003429 if (type == XML_READER_TYPE_ELEMENT) {
3430 /* do the check only on element start */
3431 match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader));
3432
3433 if (match) {
3434 path = xmlGetNodePath(xmlTextReaderCurrentNode(reader));
3435 fprintf(out, "Node %s matches pattern %s\n", path, pattern);
3436 }
3437 }
3438 if (patstream != NULL) {
3439 int ret;
3440
3441 if (type == XML_READER_TYPE_ELEMENT) {
3442 ret = xmlStreamPush(patstream,
3443 xmlTextReaderConstLocalName(reader),
3444 xmlTextReaderConstNamespaceUri(reader));
3445 if (ret < 0) {
3446 fprintf(out, "xmlStreamPush() failure\n");
3447 xmlFreeStreamCtxt(patstream);
3448 patstream = NULL;
3449 } else if (ret != match) {
3450 if (path == NULL) {
3451 path = xmlGetNodePath(
3452 xmlTextReaderCurrentNode(reader));
3453 }
3454 fprintf(out,
3455 "xmlPatternMatch and xmlStreamPush disagree\n");
3456 fprintf(out,
3457 " pattern %s node %s\n",
3458 pattern, path);
3459 }
William M. Brackca15a542005-07-06 20:41:33 +00003460
Daniel Veillardaa6de472008-08-25 14:53:31 +00003461
3462 }
William M. Brackca15a542005-07-06 20:41:33 +00003463 if ((type == XML_READER_TYPE_END_ELEMENT) ||
3464 ((type == XML_READER_TYPE_ELEMENT) && (empty))) {
3465 ret = xmlStreamPop(patstream);
3466 if (ret < 0) {
3467 fprintf(out, "xmlStreamPop() failure\n");
3468 xmlFreeStreamCtxt(patstream);
3469 patstream = NULL;
3470 }
3471 }
3472 }
3473 if (path != NULL)
3474 xmlFree(path);
3475}
3476
3477/**
3478 * patternTest:
3479 * @filename: the schemas file
3480 * @result: the file with expected result
3481 * @err: the file with error messages
3482 *
Daniel Veillardaa6de472008-08-25 14:53:31 +00003483 * Parse a set of files with streaming, applying an RNG schemas
William M. Brackca15a542005-07-06 20:41:33 +00003484 *
3485 * Returns 0 in case of success, an error code otherwise
3486 */
3487static int
3488patternTest(const char *filename,
3489 const char *resul ATTRIBUTE_UNUSED,
3490 const char *err ATTRIBUTE_UNUSED,
3491 int options) {
3492 xmlPatternPtr patternc = NULL;
3493 xmlStreamCtxtPtr patstream = NULL;
3494 FILE *o, *f;
3495 char str[1024];
3496 char xml[500];
3497 char result[500];
3498 int len, i;
3499 int ret = 0, res;
3500 char *temp;
3501 xmlTextReaderPtr reader;
3502 xmlDocPtr doc;
3503
3504 len = strlen(filename);
3505 len -= 4;
3506 memcpy(xml, filename, len);
3507 xml[len] = 0;
3508 snprintf(result, 499, "result/pattern/%s", baseFilename(xml));
3509 result[499] = 0;
3510 memcpy(xml + len, ".xml", 5);
3511
David Kilzer5c373822016-05-22 09:58:30 +08003512 if (!checkTestFile(xml) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00003513 fprintf(stderr, "Missing xml file %s\n", xml);
3514 return(-1);
3515 }
David Kilzer5c373822016-05-22 09:58:30 +08003516 if (!checkTestFile(result) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00003517 fprintf(stderr, "Missing result file %s\n", result);
3518 return(-1);
3519 }
3520 f = fopen(filename, "rb");
3521 if (f == NULL) {
3522 fprintf(stderr, "Failed to open %s\n", filename);
3523 return(-1);
3524 }
3525 temp = resultFilename(filename, "", ".res");
3526 if (temp == NULL) {
3527 fprintf(stderr, "Out of memory\n");
3528 fatalError();
3529 }
3530 o = fopen(temp, "wb");
3531 if (o == NULL) {
3532 fprintf(stderr, "failed to open output file %s\n", temp);
3533 fclose(f);
3534 free(temp);
3535 return(-1);
3536 }
3537 while (1) {
3538 /*
3539 * read one line in string buffer.
3540 */
3541 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
3542 break;
3543
3544 /*
3545 * remove the ending spaces
3546 */
3547 i = strlen(str);
3548 while ((i > 0) &&
3549 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
3550 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
3551 i--;
3552 str[i] = 0;
3553 }
3554 doc = xmlReadFile(xml, NULL, options);
3555 if (doc == NULL) {
3556 fprintf(stderr, "Failed to parse %s\n", xml);
3557 ret = 1;
3558 } else {
3559 xmlNodePtr root;
3560 const xmlChar *namespaces[22];
3561 int j;
3562 xmlNsPtr ns;
3563
3564 root = xmlDocGetRootElement(doc);
3565 for (ns = root->nsDef, j = 0;ns != NULL && j < 20;ns=ns->next) {
3566 namespaces[j++] = ns->href;
3567 namespaces[j++] = ns->prefix;
3568 }
3569 namespaces[j++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003570 namespaces[j] = NULL;
William M. Brackca15a542005-07-06 20:41:33 +00003571
3572 patternc = xmlPatterncompile((const xmlChar *) str, doc->dict,
3573 0, &namespaces[0]);
3574 if (patternc == NULL) {
3575 testErrorHandler(NULL,
3576 "Pattern %s failed to compile\n", str);
3577 xmlFreeDoc(doc);
3578 ret = 1;
3579 continue;
3580 }
3581 patstream = xmlPatternGetStreamCtxt(patternc);
3582 if (patstream != NULL) {
3583 ret = xmlStreamPush(patstream, NULL, NULL);
3584 if (ret < 0) {
3585 fprintf(stderr, "xmlStreamPush() failure\n");
3586 xmlFreeStreamCtxt(patstream);
3587 patstream = NULL;
3588 }
3589 }
3590 nb_tests++;
3591
3592 reader = xmlReaderWalker(doc);
3593 res = xmlTextReaderRead(reader);
3594 while (res == 1) {
3595 patternNode(o, reader, str, patternc, patstream);
3596 res = xmlTextReaderRead(reader);
3597 }
3598 if (res != 0) {
3599 fprintf(o, "%s : failed to parse\n", filename);
3600 }
3601 xmlFreeTextReader(reader);
3602 xmlFreeDoc(doc);
3603 xmlFreeStreamCtxt(patstream);
3604 patstream = NULL;
3605 xmlFreePattern(patternc);
3606
3607 }
3608 }
3609
3610 fclose(f);
3611 fclose(o);
3612
3613 ret = compareFiles(temp, result);
3614 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08003615 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00003616 ret = 1;
3617 }
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003618 if (temp != NULL) {
3619 unlink(temp);
3620 free(temp);
3621 }
William M. Brackca15a542005-07-06 20:41:33 +00003622 return(ret);
3623}
3624#endif /* READER */
3625#endif /* PATTERN */
3626#ifdef LIBXML_C14N_ENABLED
3627/************************************************************************
3628 * *
3629 * Canonicalization tests *
3630 * *
3631 ************************************************************************/
3632static xmlXPathObjectPtr
3633load_xpath_expr (xmlDocPtr parent_doc, const char* filename) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00003634 xmlXPathObjectPtr xpath;
William M. Brackca15a542005-07-06 20:41:33 +00003635 xmlDocPtr doc;
3636 xmlChar *expr;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003637 xmlXPathContextPtr ctx;
William M. Brackca15a542005-07-06 20:41:33 +00003638 xmlNodePtr node;
3639 xmlNsPtr ns;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003640
William M. Brackca15a542005-07-06 20:41:33 +00003641 /*
3642 * load XPath expr as a file
3643 */
3644 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3645 xmlSubstituteEntitiesDefault(1);
3646
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003647 doc = xmlReadFile(filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
William M. Brackca15a542005-07-06 20:41:33 +00003648 if (doc == NULL) {
3649 fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
3650 return(NULL);
3651 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003652
William M. Brackca15a542005-07-06 20:41:33 +00003653 /*
3654 * Check the document is of the right kind
Daniel Veillardaa6de472008-08-25 14:53:31 +00003655 */
William M. Brackca15a542005-07-06 20:41:33 +00003656 if(xmlDocGetRootElement(doc) == NULL) {
3657 fprintf(stderr,"Error: empty document for file \"%s\"\n", filename);
3658 xmlFreeDoc(doc);
3659 return(NULL);
3660 }
3661
3662 node = doc->children;
3663 while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) {
3664 node = node->next;
3665 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003666
3667 if(node == NULL) {
William M. Brackca15a542005-07-06 20:41:33 +00003668 fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename);
3669 xmlFreeDoc(doc);
3670 return(NULL);
3671 }
3672
3673 expr = xmlNodeGetContent(node);
3674 if(expr == NULL) {
3675 fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename);
3676 xmlFreeDoc(doc);
3677 return(NULL);
3678 }
3679
3680 ctx = xmlXPathNewContext(parent_doc);
3681 if(ctx == NULL) {
3682 fprintf(stderr,"Error: unable to create new context\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003683 xmlFree(expr);
3684 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003685 return(NULL);
3686 }
3687
3688 /*
3689 * Register namespaces
3690 */
3691 ns = node->nsDef;
3692 while(ns != NULL) {
3693 if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) {
3694 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 +00003695 xmlFree(expr);
3696 xmlXPathFreeContext(ctx);
3697 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003698 return(NULL);
3699 }
3700 ns = ns->next;
3701 }
3702
Daniel Veillardaa6de472008-08-25 14:53:31 +00003703 /*
William M. Brackca15a542005-07-06 20:41:33 +00003704 * Evaluate xpath
3705 */
3706 xpath = xmlXPathEvalExpression(expr, ctx);
3707 if(xpath == NULL) {
3708 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003709xmlFree(expr);
3710 xmlXPathFreeContext(ctx);
3711 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003712 return(NULL);
3713 }
3714
3715 /* print_xpath_nodes(xpath->nodesetval); */
3716
Daniel Veillardaa6de472008-08-25 14:53:31 +00003717 xmlFree(expr);
3718 xmlXPathFreeContext(ctx);
3719 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003720 return(xpath);
3721}
3722
3723/*
3724 * Macro used to grow the current buffer.
3725 */
3726#define xxx_growBufferReentrant() { \
3727 buffer_size *= 2; \
3728 buffer = (xmlChar **) \
Daniel Veillardaa6de472008-08-25 14:53:31 +00003729 xmlRealloc(buffer, buffer_size * sizeof(xmlChar*)); \
William M. Brackca15a542005-07-06 20:41:33 +00003730 if (buffer == NULL) { \
3731 perror("realloc failed"); \
3732 return(NULL); \
3733 } \
3734}
3735
3736static xmlChar **
3737parse_list(xmlChar *str) {
3738 xmlChar **buffer;
3739 xmlChar **out = NULL;
3740 int buffer_size = 0;
3741 int len;
3742
3743 if(str == NULL) {
3744 return(NULL);
3745 }
3746
3747 len = xmlStrlen(str);
3748 if((str[0] == '\'') && (str[len - 1] == '\'')) {
3749 str[len - 1] = '\0';
3750 str++;
William M. Brackca15a542005-07-06 20:41:33 +00003751 }
3752 /*
3753 * allocate an translation buffer.
3754 */
3755 buffer_size = 1000;
3756 buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*));
3757 if (buffer == NULL) {
3758 perror("malloc failed");
3759 return(NULL);
3760 }
3761 out = buffer;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003762
William M. Brackca15a542005-07-06 20:41:33 +00003763 while(*str != '\0') {
3764 if (out - buffer > buffer_size - 10) {
3765 int indx = out - buffer;
3766
3767 xxx_growBufferReentrant();
3768 out = &buffer[indx];
3769 }
3770 (*out++) = str;
3771 while(*str != ',' && *str != '\0') ++str;
3772 if(*str == ',') *(str++) = '\0';
3773 }
3774 (*out) = NULL;
3775 return buffer;
3776}
3777
Daniel Veillardaa6de472008-08-25 14:53:31 +00003778static int
Aleksey Sanin83868242009-07-09 10:26:22 +02003779c14nRunTest(const char* xml_filename, int with_comments, int mode,
William M. Brackca15a542005-07-06 20:41:33 +00003780 const char* xpath_filename, const char *ns_filename,
3781 const char* result_file) {
3782 xmlDocPtr doc;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003783 xmlXPathObjectPtr xpath = NULL;
William M. Brackca15a542005-07-06 20:41:33 +00003784 xmlChar *result = NULL;
3785 int ret;
3786 xmlChar **inclusive_namespaces = NULL;
3787 const char *nslist = NULL;
3788 int nssize;
3789
3790
3791 /*
3792 * build an XML tree from a the file; we need to add default
3793 * attributes and resolve all character and entities references
3794 */
3795 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3796 xmlSubstituteEntitiesDefault(1);
3797
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003798 doc = xmlReadFile(xml_filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
William M. Brackca15a542005-07-06 20:41:33 +00003799 if (doc == NULL) {
3800 fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename);
3801 return(-1);
3802 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003803
William M. Brackca15a542005-07-06 20:41:33 +00003804 /*
3805 * Check the document is of the right kind
Daniel Veillardaa6de472008-08-25 14:53:31 +00003806 */
William M. Brackca15a542005-07-06 20:41:33 +00003807 if(xmlDocGetRootElement(doc) == NULL) {
3808 fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename);
3809 xmlFreeDoc(doc);
3810 return(-1);
3811 }
3812
Daniel Veillardaa6de472008-08-25 14:53:31 +00003813 /*
3814 * load xpath file if specified
William M. Brackca15a542005-07-06 20:41:33 +00003815 */
3816 if(xpath_filename) {
3817 xpath = load_xpath_expr(doc, xpath_filename);
3818 if(xpath == NULL) {
3819 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003820 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003821 return(-1);
3822 }
3823 }
3824
3825 if (ns_filename != NULL) {
3826 if (loadMem(ns_filename, &nslist, &nssize)) {
3827 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3828 if(xpath != NULL) xmlXPathFreeObject(xpath);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003829 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003830 return(-1);
3831 }
3832 inclusive_namespaces = parse_list((xmlChar *) nslist);
3833 }
3834
3835 /*
3836 * Canonical form
Daniel Veillardaa6de472008-08-25 14:53:31 +00003837 */
William M. Brackca15a542005-07-06 20:41:33 +00003838 /* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */
Daniel Veillardaa6de472008-08-25 14:53:31 +00003839 ret = xmlC14NDocDumpMemory(doc,
3840 (xpath) ? xpath->nodesetval : NULL,
Aleksey Sanin83868242009-07-09 10:26:22 +02003841 mode, inclusive_namespaces,
William M. Brackca15a542005-07-06 20:41:33 +00003842 with_comments, &result);
3843 if (ret >= 0) {
3844 if(result != NULL) {
3845 if (compareFileMem(result_file, (const char *) result, ret)) {
3846 fprintf(stderr, "Result mismatch for %s\n", xml_filename);
Aleksey Sanin83868242009-07-09 10:26:22 +02003847 fprintf(stderr, "RESULT:\n%s\n", (const char*)result);
William M. Brackca15a542005-07-06 20:41:33 +00003848 ret = -1;
3849 }
3850 }
3851 } else {
3852 fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret);
3853 ret = -1;
3854 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003855
William M. Brackca15a542005-07-06 20:41:33 +00003856 /*
3857 * Cleanup
Daniel Veillardaa6de472008-08-25 14:53:31 +00003858 */
William M. Brackca15a542005-07-06 20:41:33 +00003859 if (result != NULL) xmlFree(result);
3860 if(xpath != NULL) xmlXPathFreeObject(xpath);
3861 if (inclusive_namespaces != NULL) xmlFree(inclusive_namespaces);
3862 if (nslist != NULL) free((char *) nslist);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003863 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003864
3865 return(ret);
3866}
3867
3868static int
Aleksey Sanin83868242009-07-09 10:26:22 +02003869c14nCommonTest(const char *filename, int with_comments, int mode,
William M. Brackca15a542005-07-06 20:41:33 +00003870 const char *subdir) {
3871 char buf[500];
3872 char prefix[500];
3873 const char *base;
3874 int len;
3875 char *result = NULL;
3876 char *xpath = NULL;
3877 char *ns = NULL;
3878 int ret = 0;
3879
3880 base = baseFilename(filename);
3881 len = strlen(base);
3882 len -= 4;
3883 memcpy(prefix, base, len);
3884 prefix[len] = 0;
3885
3886 snprintf(buf, 499, "result/c14n/%s/%s", subdir,prefix);
David Kilzer5c373822016-05-22 09:58:30 +08003887 if (!checkTestFile(buf) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00003888 fprintf(stderr, "Missing result file %s", buf);
3889 return(-1);
3890 }
3891 result = strdup(buf);
3892 snprintf(buf, 499, "test/c14n/%s/%s.xpath", subdir,prefix);
3893 if (checkTestFile(buf)) {
3894 xpath = strdup(buf);
3895 }
3896 snprintf(buf, 499, "test/c14n/%s/%s.ns", subdir,prefix);
3897 if (checkTestFile(buf)) {
3898 ns = strdup(buf);
3899 }
3900
3901 nb_tests++;
Aleksey Sanin83868242009-07-09 10:26:22 +02003902 if (c14nRunTest(filename, with_comments, mode,
William M. Brackca15a542005-07-06 20:41:33 +00003903 xpath, ns, result) < 0)
3904 ret = 1;
3905
3906 if (result != NULL) free(result);
3907 if (xpath != NULL) free(xpath);
3908 if (ns != NULL) free(ns);
3909 return(ret);
3910}
3911
3912static int
3913c14nWithCommentTest(const char *filename,
3914 const char *resul ATTRIBUTE_UNUSED,
3915 const char *err ATTRIBUTE_UNUSED,
3916 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003917 return(c14nCommonTest(filename, 1, XML_C14N_1_0, "with-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003918}
3919static int
3920c14nWithoutCommentTest(const char *filename,
3921 const char *resul ATTRIBUTE_UNUSED,
3922 const char *err ATTRIBUTE_UNUSED,
3923 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003924 return(c14nCommonTest(filename, 0, XML_C14N_1_0, "without-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003925}
3926static int
3927c14nExcWithoutCommentTest(const char *filename,
3928 const char *resul ATTRIBUTE_UNUSED,
3929 const char *err ATTRIBUTE_UNUSED,
3930 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003931 return(c14nCommonTest(filename, 0, XML_C14N_EXCLUSIVE_1_0, "exc-without-comments"));
3932}
3933static int
3934c14n11WithoutCommentTest(const char *filename,
3935 const char *resul ATTRIBUTE_UNUSED,
3936 const char *err ATTRIBUTE_UNUSED,
3937 int options ATTRIBUTE_UNUSED) {
3938 return(c14nCommonTest(filename, 0, XML_C14N_1_1, "1-1-without-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003939}
3940#endif
Nick Wellnhofer01a4b812017-06-16 21:27:47 +02003941#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
William M. Brackca15a542005-07-06 20:41:33 +00003942/************************************************************************
3943 * *
3944 * Catalog and threads test *
3945 * *
3946 ************************************************************************/
3947
3948/*
3949 * mostly a cut and paste from testThreads.c
3950 */
3951#define MAX_ARGC 20
3952
3953static const char *catalog = "test/threads/complex.xml";
3954static const char *testfiles[] = {
3955 "test/threads/abc.xml",
3956 "test/threads/acb.xml",
3957 "test/threads/bac.xml",
3958 "test/threads/bca.xml",
3959 "test/threads/cab.xml",
3960 "test/threads/cba.xml",
3961 "test/threads/invalid.xml",
3962};
3963
Daniel Veillard24505b02005-07-28 23:49:35 +00003964static const char *Okay = "OK";
3965static const char *Failed = "Failed";
William M. Brackca15a542005-07-06 20:41:33 +00003966
3967#ifndef xmlDoValidityCheckingDefaultValue
3968#error xmlDoValidityCheckingDefaultValue is not a macro
3969#endif
3970#ifndef xmlGenericErrorContext
3971#error xmlGenericErrorContext is not a macro
3972#endif
3973
3974static void *
3975thread_specific_data(void *private_data)
3976{
3977 xmlDocPtr myDoc;
3978 const char *filename = (const char *) private_data;
3979 int okay = 1;
3980
3981 if (!strcmp(filename, "test/threads/invalid.xml")) {
3982 xmlDoValidityCheckingDefaultValue = 0;
3983 xmlGenericErrorContext = stdout;
3984 } else {
3985 xmlDoValidityCheckingDefaultValue = 1;
3986 xmlGenericErrorContext = stderr;
3987 }
Nick Wellnhofer01a4b812017-06-16 21:27:47 +02003988#ifdef LIBXML_SAX1_ENABLED
William M. Brackca15a542005-07-06 20:41:33 +00003989 myDoc = xmlParseFile(filename);
Nick Wellnhofer01a4b812017-06-16 21:27:47 +02003990#else
3991 myDoc = xmlReadFile(filename, NULL, XML_WITH_CATALOG);
3992#endif
William M. Brackca15a542005-07-06 20:41:33 +00003993 if (myDoc) {
3994 xmlFreeDoc(myDoc);
3995 } else {
3996 printf("parse failed\n");
3997 okay = 0;
3998 }
3999 if (!strcmp(filename, "test/threads/invalid.xml")) {
4000 if (xmlDoValidityCheckingDefaultValue != 0) {
4001 printf("ValidityCheckingDefaultValue override failed\n");
4002 okay = 0;
4003 }
4004 if (xmlGenericErrorContext != stdout) {
4005 printf("xmlGenericErrorContext override failed\n");
4006 okay = 0;
4007 }
4008 } else {
4009 if (xmlDoValidityCheckingDefaultValue != 1) {
4010 printf("ValidityCheckingDefaultValue override failed\n");
4011 okay = 0;
4012 }
4013 if (xmlGenericErrorContext != stderr) {
4014 printf("xmlGenericErrorContext override failed\n");
4015 okay = 0;
4016 }
4017 }
4018 if (okay == 0)
4019 return ((void *) Failed);
4020 return ((void *) Okay);
4021}
4022
Daniel Richard G495a73d2012-08-07 10:14:56 +08004023#if defined WIN32
William M. Brackca15a542005-07-06 20:41:33 +00004024#include <windows.h>
4025#include <string.h>
4026
4027#define TEST_REPEAT_COUNT 500
4028
4029static HANDLE tid[MAX_ARGC];
4030
4031static DWORD WINAPI
4032win32_thread_specific_data(void *private_data)
4033{
4034 return((DWORD) thread_specific_data(private_data));
4035}
4036
4037static int
4038testThread(void)
4039{
4040 unsigned int i, repeat;
4041 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
4042 DWORD results[MAX_ARGC];
4043 BOOL ret;
4044 int res = 0;
4045
4046 xmlInitParser();
4047 for (repeat = 0; repeat < TEST_REPEAT_COUNT; repeat++) {
4048 xmlLoadCatalog(catalog);
4049 nb_tests++;
4050
4051 for (i = 0; i < num_threads; i++) {
4052 results[i] = 0;
4053 tid[i] = (HANDLE) - 1;
4054 }
4055
4056 for (i = 0; i < num_threads; i++) {
4057 DWORD useless;
4058
4059 tid[i] = CreateThread(NULL, 0,
Daniel Veillardaa6de472008-08-25 14:53:31 +00004060 win32_thread_specific_data,
William M. Brackca15a542005-07-06 20:41:33 +00004061 (void *) testfiles[i], 0,
4062 &useless);
4063 if (tid[i] == NULL) {
4064 fprintf(stderr, "CreateThread failed\n");
4065 return(1);
4066 }
4067 }
4068
4069 if (WaitForMultipleObjects(num_threads, tid, TRUE, INFINITE) ==
4070 WAIT_FAILED) {
4071 fprintf(stderr, "WaitForMultipleObjects failed\n");
4072 return(1);
4073 }
4074
4075 for (i = 0; i < num_threads; i++) {
4076 ret = GetExitCodeThread(tid[i], &results[i]);
4077 if (ret == 0) {
4078 fprintf(stderr, "GetExitCodeThread failed\n");
4079 return(1);
4080 }
4081 CloseHandle(tid[i]);
4082 }
4083
4084 xmlCatalogCleanup();
4085 for (i = 0; i < num_threads; i++) {
4086 if (results[i] != (DWORD) Okay) {
4087 fprintf(stderr, "Thread %d handling %s failed\n",
4088 i, testfiles[i]);
4089 res = 1;
4090 }
4091 }
4092 }
4093
4094 return (res);
4095}
4096
4097#elif defined __BEOS__
4098#include <OS.h>
4099
4100static thread_id tid[MAX_ARGC];
4101
4102static int
4103testThread(void)
4104{
4105 unsigned int i, repeat;
4106 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
4107 void *results[MAX_ARGC];
4108 status_t ret;
4109 int res = 0;
4110
4111 xmlInitParser();
4112 for (repeat = 0; repeat < 500; repeat++) {
4113 xmlLoadCatalog(catalog);
4114 for (i = 0; i < num_threads; i++) {
4115 results[i] = NULL;
4116 tid[i] = (thread_id) - 1;
4117 }
4118 for (i = 0; i < num_threads; i++) {
4119 tid[i] =
4120 spawn_thread(thread_specific_data, "xmlTestThread",
4121 B_NORMAL_PRIORITY, (void *) testfiles[i]);
4122 if (tid[i] < B_OK) {
4123 fprintf(stderr, "beos_thread_create failed\n");
4124 return (1);
4125 }
4126 printf("beos_thread_create %d -> %d\n", i, tid[i]);
4127 }
4128 for (i = 0; i < num_threads; i++) {
4129 ret = wait_for_thread(tid[i], &results[i]);
4130 printf("beos_thread_wait %d -> %d\n", i, ret);
4131 if (ret != B_OK) {
4132 fprintf(stderr, "beos_thread_wait failed\n");
4133 return (1);
4134 }
4135 }
4136
4137 xmlCatalogCleanup();
4138 ret = B_OK;
4139 for (i = 0; i < num_threads; i++)
4140 if (results[i] != (void *) Okay) {
4141 printf("Thread %d handling %s failed\n", i, testfiles[i]);
4142 ret = B_ERROR;
4143 }
4144 }
4145 if (ret != B_OK)
4146 return(1);
4147 return (0);
4148}
Daniel Richard G495a73d2012-08-07 10:14:56 +08004149
4150#elif defined HAVE_PTHREAD_H
4151#include <pthread.h>
4152
4153static pthread_t tid[MAX_ARGC];
4154
4155static int
4156testThread(void)
4157{
4158 unsigned int i, repeat;
4159 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
4160 void *results[MAX_ARGC];
4161 int ret;
4162 int res = 0;
4163
4164 xmlInitParser();
4165
4166 for (repeat = 0; repeat < 500; repeat++) {
4167 xmlLoadCatalog(catalog);
4168 nb_tests++;
4169
4170 for (i = 0; i < num_threads; i++) {
4171 results[i] = NULL;
4172 tid[i] = (pthread_t) - 1;
4173 }
4174
4175 for (i = 0; i < num_threads; i++) {
4176 ret = pthread_create(&tid[i], 0, thread_specific_data,
4177 (void *) testfiles[i]);
4178 if (ret != 0) {
4179 fprintf(stderr, "pthread_create failed\n");
4180 return (1);
4181 }
4182 }
4183 for (i = 0; i < num_threads; i++) {
4184 ret = pthread_join(tid[i], &results[i]);
4185 if (ret != 0) {
4186 fprintf(stderr, "pthread_join failed\n");
4187 return (1);
4188 }
4189 }
4190
4191 xmlCatalogCleanup();
4192 for (i = 0; i < num_threads; i++)
4193 if (results[i] != (void *) Okay) {
4194 fprintf(stderr, "Thread %d handling %s failed\n",
4195 i, testfiles[i]);
4196 res = 1;
4197 }
4198 }
4199 return (res);
4200}
4201
William M. Brackca15a542005-07-06 20:41:33 +00004202#else
4203static int
4204testThread(void)
4205{
4206 fprintf(stderr,
4207 "Specific platform thread support not detected\n");
4208 return (-1);
4209}
4210#endif
Daniel Veillardaa6de472008-08-25 14:53:31 +00004211static int
William M. Brackca15a542005-07-06 20:41:33 +00004212threadsTest(const char *filename ATTRIBUTE_UNUSED,
4213 const char *resul ATTRIBUTE_UNUSED,
4214 const char *err ATTRIBUTE_UNUSED,
4215 int options ATTRIBUTE_UNUSED) {
4216 return(testThread());
4217}
4218#endif
4219/************************************************************************
4220 * *
4221 * Tests Descriptions *
4222 * *
4223 ************************************************************************/
4224
4225static
4226testDesc testDescriptions[] = {
4227 { "XML regression tests" ,
4228 oldParseTest, "./test/*", "result/", "", NULL,
4229 0 },
4230 { "XML regression tests on memory" ,
4231 memParseTest, "./test/*", "result/", "", NULL,
4232 0 },
4233 { "XML entity subst regression tests" ,
4234 noentParseTest, "./test/*", "result/noent/", "", NULL,
4235 XML_PARSE_NOENT },
4236 { "XML Namespaces regression tests",
4237 errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err",
4238 0 },
4239 { "Error cases regression tests",
4240 errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err",
4241 0 },
Nick Wellnhofere2663052017-06-05 15:37:17 +02004242 { "Error cases regression tests (old 1.0)",
4243 errParseTest, "./test/errors10/*.xml", "result/errors10/", "", ".err",
4244 XML_PARSE_OLD10 },
William M. Brackca15a542005-07-06 20:41:33 +00004245#ifdef LIBXML_READER_ENABLED
4246 { "Error cases stream regression tests",
4247 streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str",
4248 0 },
4249 { "Reader regression tests",
4250 streamParseTest, "./test/*", "result/", ".rdr", NULL,
4251 0 },
4252 { "Reader entities substitution regression tests",
4253 streamParseTest, "./test/*", "result/", ".rde", NULL,
4254 XML_PARSE_NOENT },
4255 { "Reader on memory regression tests",
4256 streamMemParseTest, "./test/*", "result/", ".rdr", NULL,
4257 0 },
4258 { "Walker regression tests",
4259 walkerParseTest, "./test/*", "result/", ".rdr", NULL,
4260 0 },
4261#endif
4262#ifdef LIBXML_SAX1_ENABLED
4263 { "SAX1 callbacks regression tests" ,
4264 saxParseTest, "./test/*", "result/", ".sax", NULL,
4265 XML_PARSE_SAX1 },
Nick Wellnhoferdbaab1f2017-06-16 21:38:57 +02004266#endif
William M. Brackca15a542005-07-06 20:41:33 +00004267 { "SAX2 callbacks regression tests" ,
4268 saxParseTest, "./test/*", "result/", ".sax2", NULL,
4269 0 },
Nick Wellnhoferdbaab1f2017-06-16 21:38:57 +02004270 { "SAX2 callbacks regression tests with entity substitution" ,
4271 saxParseTest, "./test/*", "result/noent/", ".sax2", NULL,
4272 XML_PARSE_NOENT },
William M. Brackca15a542005-07-06 20:41:33 +00004273#ifdef LIBXML_PUSH_ENABLED
4274 { "XML push regression tests" ,
4275 pushParseTest, "./test/*", "result/", "", NULL,
4276 0 },
4277#endif
4278#ifdef LIBXML_HTML_ENABLED
4279 { "HTML regression tests" ,
4280 errParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4281 XML_PARSE_HTML },
4282#ifdef LIBXML_PUSH_ENABLED
4283 { "Push HTML regression tests" ,
4284 pushParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4285 XML_PARSE_HTML },
4286#endif
William M. Brackca15a542005-07-06 20:41:33 +00004287 { "HTML SAX regression tests" ,
4288 saxParseTest, "./test/HTML/*", "result/HTML/", ".sax", NULL,
4289 XML_PARSE_HTML },
4290#endif
William M. Brackca15a542005-07-06 20:41:33 +00004291#ifdef LIBXML_VALID_ENABLED
4292 { "Valid documents regression tests" ,
4293 errParseTest, "./test/VCM/*", NULL, NULL, NULL,
4294 XML_PARSE_DTDVALID },
4295 { "Validity checking regression tests" ,
4296 errParseTest, "./test/VC/*", "result/VC/", NULL, "",
4297 XML_PARSE_DTDVALID },
Daniel Veillarda7982ce2012-10-25 15:39:39 +08004298#ifdef LIBXML_READER_ENABLED
4299 { "Streaming validity checking regression tests" ,
4300 streamParseTest, "./test/valid/*.xml", "result/valid/", NULL, ".err.rdr",
4301 XML_PARSE_DTDVALID },
4302 { "Streaming validity error checking regression tests" ,
4303 streamParseTest, "./test/VC/*", "result/VC/", NULL, ".rdr",
4304 XML_PARSE_DTDVALID },
4305#endif
William M. Brackca15a542005-07-06 20:41:33 +00004306 { "General documents valid regression tests" ,
4307 errParseTest, "./test/valid/*", "result/valid/", "", ".err",
4308 XML_PARSE_DTDVALID },
4309#endif
4310#ifdef LIBXML_XINCLUDE_ENABLED
4311 { "XInclude regression tests" ,
4312 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4313 /* Ignore errors at this point ".err", */
4314 XML_PARSE_XINCLUDE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004315#ifdef LIBXML_READER_ENABLED
William M. Brackca15a542005-07-06 20:41:33 +00004316 { "XInclude xmlReader regression tests",
4317 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4318 /* Ignore errors at this point ".err", */
4319 NULL, XML_PARSE_XINCLUDE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004320#endif
William M. Brackca15a542005-07-06 20:41:33 +00004321 { "XInclude regression tests stripping include nodes" ,
4322 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4323 /* Ignore errors at this point ".err", */
4324 XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004325#ifdef LIBXML_READER_ENABLED
William M. Brackca15a542005-07-06 20:41:33 +00004326 { "XInclude xmlReader regression tests stripping include nodes",
4327 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4328 /* Ignore errors at this point ".err", */
4329 NULL, XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
4330#endif
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004331#endif
William M. Brackca15a542005-07-06 20:41:33 +00004332#ifdef LIBXML_XPATH_ENABLED
4333#ifdef LIBXML_DEBUG_ENABLED
4334 { "XPath expressions regression tests" ,
4335 xpathExprTest, "./test/XPath/expr/*", "result/XPath/expr/", "", NULL,
4336 0 },
4337 { "XPath document queries regression tests" ,
4338 xpathDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4339 0 },
4340#ifdef LIBXML_XPTR_ENABLED
4341 { "XPointer document queries regression tests" ,
4342 xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4343 0 },
4344#endif
4345 { "xml:id regression tests" ,
4346 xmlidDocTest, "./test/xmlid/*", "result/xmlid/", "", ".err",
4347 0 },
4348#endif
4349#endif
4350 { "URI parsing tests" ,
4351 uriParseTest, "./test/URI/*.uri", "result/URI/", "", NULL,
4352 0 },
4353 { "URI base composition tests" ,
4354 uriBaseTest, "./test/URI/*.data", "result/URI/", "", NULL,
4355 0 },
Daniel Veillard336a8e12005-08-07 10:46:19 +00004356 { "Path URI conversion tests" ,
4357 uriPathTest, NULL, NULL, NULL, NULL,
4358 0 },
William M. Brackca15a542005-07-06 20:41:33 +00004359#ifdef LIBXML_SCHEMAS_ENABLED
4360 { "Schemas regression tests" ,
4361 schemasTest, "./test/schemas/*_*.xsd", NULL, NULL, NULL,
4362 0 },
4363 { "Relax-NG regression tests" ,
4364 rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4365 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4366#ifdef LIBXML_READER_ENABLED
4367 { "Relax-NG streaming regression tests" ,
4368 rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4369 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4370#endif
4371#endif
4372#ifdef LIBXML_PATTERN_ENABLED
4373#ifdef LIBXML_READER_ENABLED
4374 { "Pattern regression tests" ,
4375 patternTest, "./test/pattern/*.pat", "result/pattern/", NULL, NULL,
4376 0 },
4377#endif
4378#endif
4379#ifdef LIBXML_C14N_ENABLED
4380 { "C14N with comments regression tests" ,
4381 c14nWithCommentTest, "./test/c14n/with-comments/*.xml", NULL, NULL, NULL,
4382 0 },
4383 { "C14N without comments regression tests" ,
4384 c14nWithoutCommentTest, "./test/c14n/without-comments/*.xml", NULL, NULL, NULL,
4385 0 },
4386 { "C14N exclusive without comments regression tests" ,
4387 c14nExcWithoutCommentTest, "./test/c14n/exc-without-comments/*.xml", NULL, NULL, NULL,
4388 0 },
Aleksey Sanin83868242009-07-09 10:26:22 +02004389 { "C14N 1.1 without comments regression tests" ,
4390 c14n11WithoutCommentTest, "./test/c14n/1-1-without-comments/*.xml", NULL, NULL, NULL,
4391 0 },
William M. Brackca15a542005-07-06 20:41:33 +00004392#endif
Nick Wellnhofer01a4b812017-06-16 21:27:47 +02004393#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
William M. Brackca15a542005-07-06 20:41:33 +00004394 { "Catalog and Threads regression tests" ,
4395 threadsTest, NULL, NULL, NULL, NULL,
4396 0 },
4397#endif
4398 {NULL, NULL, NULL, NULL, NULL, NULL, 0}
4399};
4400
4401/************************************************************************
4402 * *
4403 * The main code driving the tests *
4404 * *
4405 ************************************************************************/
4406
4407static int
4408launchTests(testDescPtr tst) {
4409 int res = 0, err = 0;
4410 size_t i;
4411 char *result;
4412 char *error;
4413 int mem;
4414
4415 if (tst == NULL) return(-1);
4416 if (tst->in != NULL) {
4417 glob_t globbuf;
4418
4419 globbuf.gl_offs = 0;
4420 glob(tst->in, GLOB_DOOFFS, NULL, &globbuf);
4421 for (i = 0;i < globbuf.gl_pathc;i++) {
4422 if (!checkTestFile(globbuf.gl_pathv[i]))
4423 continue;
4424 if (tst->suffix != NULL) {
4425 result = resultFilename(globbuf.gl_pathv[i], tst->out,
4426 tst->suffix);
4427 if (result == NULL) {
4428 fprintf(stderr, "Out of memory !\n");
4429 fatalError();
4430 }
4431 } else {
4432 result = NULL;
4433 }
4434 if (tst->err != NULL) {
4435 error = resultFilename(globbuf.gl_pathv[i], tst->out,
4436 tst->err);
4437 if (error == NULL) {
4438 fprintf(stderr, "Out of memory !\n");
4439 fatalError();
4440 }
4441 } else {
4442 error = NULL;
4443 }
David Kilzer5c373822016-05-22 09:58:30 +08004444 if ((result) &&(!checkTestFile(result)) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00004445 fprintf(stderr, "Missing result file %s\n", result);
David Kilzer5c373822016-05-22 09:58:30 +08004446 } else if ((error) &&(!checkTestFile(error)) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00004447 fprintf(stderr, "Missing error file %s\n", error);
4448 } else {
4449 mem = xmlMemUsed();
4450 extraMemoryFromResolver = 0;
4451 testErrorsSize = 0;
4452 testErrors[0] = 0;
4453 res = tst->func(globbuf.gl_pathv[i], result, error,
Daniel Veillard8874b942005-08-25 13:19:21 +00004454 tst->options | XML_PARSE_COMPACT);
William M. Brackca15a542005-07-06 20:41:33 +00004455 xmlResetLastError();
4456 if (res != 0) {
4457 fprintf(stderr, "File %s generated an error\n",
4458 globbuf.gl_pathv[i]);
4459 nb_errors++;
4460 err++;
4461 }
4462 else if (xmlMemUsed() != mem) {
4463 if ((xmlMemUsed() != mem) &&
4464 (extraMemoryFromResolver == 0)) {
4465 fprintf(stderr, "File %s leaked %d bytes\n",
4466 globbuf.gl_pathv[i], xmlMemUsed() - mem);
4467 nb_leaks++;
4468 err++;
4469 }
4470 }
4471 testErrorsSize = 0;
4472 }
4473 if (result)
4474 free(result);
4475 if (error)
4476 free(error);
4477 }
4478 globfree(&globbuf);
4479 } else {
4480 testErrorsSize = 0;
4481 testErrors[0] = 0;
4482 extraMemoryFromResolver = 0;
4483 res = tst->func(NULL, NULL, NULL, tst->options);
4484 if (res != 0) {
4485 nb_errors++;
4486 err++;
4487 }
4488 }
4489 return(err);
4490}
4491
Daniel Veillarddb68b742005-07-30 13:18:24 +00004492static int verbose = 0;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004493static int tests_quiet = 0;
Daniel Veillarddb68b742005-07-30 13:18:24 +00004494
4495static int
4496runtest(int i) {
4497 int ret = 0, res;
4498 int old_errors, old_tests, old_leaks;
4499
4500 old_errors = nb_errors;
4501 old_tests = nb_tests;
4502 old_leaks = nb_leaks;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004503 if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
Daniel Veillarddb68b742005-07-30 13:18:24 +00004504 printf("## %s\n", testDescriptions[i].desc);
4505 res = launchTests(&testDescriptions[i]);
4506 if (res != 0)
4507 ret++;
4508 if (verbose) {
4509 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
4510 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
4511 else
4512 printf("Ran %d tests, %d errors, %d leaks\n",
4513 nb_tests - old_tests,
4514 nb_errors - old_errors,
4515 nb_leaks - old_leaks);
4516 }
4517 return(ret);
4518}
4519
William M. Brackca15a542005-07-06 20:41:33 +00004520int
4521main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
Daniel Veillarddb68b742005-07-30 13:18:24 +00004522 int i, a, ret = 0;
4523 int subset = 0;
William M. Brackca15a542005-07-06 20:41:33 +00004524
4525 initializeLibxml2();
4526
Daniel Veillarddb68b742005-07-30 13:18:24 +00004527 for (a = 1; a < argc;a++) {
4528 if (!strcmp(argv[a], "-v"))
4529 verbose = 1;
David Kilzer5c373822016-05-22 09:58:30 +08004530 else if (!strcmp(argv[a], "-u"))
4531 update_results = 1;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004532 else if (!strcmp(argv[a], "-quiet"))
4533 tests_quiet = 1;
Daniel Veillarddb68b742005-07-30 13:18:24 +00004534 else {
4535 for (i = 0; testDescriptions[i].func != NULL; i++) {
4536 if (strstr(testDescriptions[i].desc, argv[a])) {
4537 ret += runtest(i);
4538 subset++;
4539 }
4540 }
4541 }
4542 }
4543 if (subset == 0) {
4544 for (i = 0; testDescriptions[i].func != NULL; i++) {
4545 ret += runtest(i);
William M. Brackca15a542005-07-06 20:41:33 +00004546 }
4547 }
4548 if ((nb_errors == 0) && (nb_leaks == 0)) {
4549 ret = 0;
4550 printf("Total %d tests, no errors\n",
4551 nb_tests);
4552 } else {
4553 ret = 1;
4554 printf("Total %d tests, %d errors, %d leaks\n",
4555 nb_tests, nb_errors, nb_leaks);
4556 }
4557 xmlCleanupParser();
4558 xmlMemoryDump();
4559
4560 return(ret);
4561}
4562
4563#else /* ! LIBXML_OUTPUT_ENABLED */
4564int
4565main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
4566 fprintf(stderr, "runtest requires output to be enabled in libxml2\n");
4567 return(1);
4568}
4569#endif