blob: 981fd8d9ca8b0f4883ad009e0a4847ce1a5c3ec8 [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
Nick Wellnhofer82e03942017-10-09 02:05:41 +0200122static int glob(const char *pattern, ATTRIBUTE_UNUSED int flags,
123 ATTRIBUTE_UNUSED int errfunc(const char *epath, int eerrno),
William M. Brackca15a542005-07-06 20:41:33 +0000124 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,
Nick Wellnhofer81c01ee2017-06-17 14:12:53 +02002166 xmlTextReaderPtr reader, const char *rng,
2167 int options ATTRIBUTE_UNUSED) {
William M. Brackca15a542005-07-06 20:41:33 +00002168 int ret;
2169 char *temp = NULL;
2170 FILE *t = NULL;
2171
2172 if (reader == NULL)
2173 return(-1);
2174
2175 nb_tests++;
2176 if (result != NULL) {
2177 temp = resultFilename(filename, "", ".res");
2178 if (temp == NULL) {
2179 fprintf(stderr, "Out of memory\n");
2180 fatalError();
2181 }
2182 t = fopen(temp, "wb");
2183 if (t == NULL) {
2184 fprintf(stderr, "Can't open temp file %s\n", temp);
2185 free(temp);
2186 return(-1);
2187 }
2188 }
2189#ifdef LIBXML_SCHEMAS_ENABLED
2190 if (rng != NULL) {
2191 ret = xmlTextReaderRelaxNGValidate(reader, rng);
2192 if (ret < 0) {
2193 testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n",
2194 rng);
2195 fclose(t);
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002196 if (temp != NULL) {
2197 unlink(temp);
2198 free(temp);
2199 }
William M. Brackca15a542005-07-06 20:41:33 +00002200 return(0);
2201 }
2202 }
2203#endif
2204 xmlGetWarningsDefaultValue = 1;
2205 ret = xmlTextReaderRead(reader);
2206 while (ret == 1) {
2207 if ((t != NULL) && (rng == NULL))
2208 processNode(t, reader);
2209 ret = xmlTextReaderRead(reader);
2210 }
2211 if (ret != 0) {
2212 testErrorHandler(NULL, "%s : failed to parse\n", filename);
2213 }
2214 if (rng != NULL) {
2215 if (xmlTextReaderIsValid(reader) != 1) {
2216 testErrorHandler(NULL, "%s fails to validate\n", filename);
2217 } else {
2218 testErrorHandler(NULL, "%s validates\n", filename);
2219 }
2220 }
2221 xmlGetWarningsDefaultValue = 0;
2222 if (t != NULL) {
2223 fclose(t);
2224 ret = compareFiles(temp, result);
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002225 if (temp != NULL) {
2226 unlink(temp);
2227 free(temp);
2228 }
William M. Brackca15a542005-07-06 20:41:33 +00002229 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002230 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002231 return(-1);
2232 }
2233 }
2234 if (err != NULL) {
2235 ret = compareFileMem(err, testErrors, testErrorsSize);
2236 if (ret != 0) {
2237 fprintf(stderr, "Error for %s failed\n", filename);
2238 printf("%s", testErrors);
2239 return(-1);
2240 }
2241 }
2242
2243 return(0);
2244}
2245
2246/**
2247 * streamParseTest:
2248 * @filename: the file to parse
2249 * @result: the file with expected result
2250 * @err: the file with error messages
2251 *
2252 * Parse a file using the reader API and check for errors.
2253 *
2254 * Returns 0 in case of success, an error code otherwise
2255 */
2256static int
2257streamParseTest(const char *filename, const char *result, const char *err,
2258 int options) {
2259 xmlTextReaderPtr reader;
2260 int ret;
2261
2262 reader = xmlReaderForFile(filename, NULL, options);
Daniel Veillarda7982ce2012-10-25 15:39:39 +08002263 ret = streamProcessTest(filename, result, err, reader, NULL, options);
William M. Brackca15a542005-07-06 20:41:33 +00002264 xmlFreeTextReader(reader);
2265 return(ret);
2266}
2267
2268/**
2269 * walkerParseTest:
2270 * @filename: the file to parse
2271 * @result: the file with expected result
2272 * @err: the file with error messages
2273 *
2274 * Parse a file using the walker, i.e. a reader built from a atree.
2275 *
2276 * Returns 0 in case of success, an error code otherwise
2277 */
2278static int
2279walkerParseTest(const char *filename, const char *result, const char *err,
2280 int options) {
2281 xmlDocPtr doc;
2282 xmlTextReaderPtr reader;
2283 int ret;
2284
2285 doc = xmlReadFile(filename, NULL, options);
2286 if (doc == NULL) {
2287 fprintf(stderr, "Failed to parse %s\n", filename);
2288 return(-1);
2289 }
2290 reader = xmlReaderWalker(doc);
Daniel Veillarda7982ce2012-10-25 15:39:39 +08002291 ret = streamProcessTest(filename, result, err, reader, NULL, options);
William M. Brackca15a542005-07-06 20:41:33 +00002292 xmlFreeTextReader(reader);
2293 xmlFreeDoc(doc);
2294 return(ret);
2295}
2296
2297/**
2298 * streamMemParseTest:
2299 * @filename: the file to parse
2300 * @result: the file with expected result
2301 * @err: the file with error messages
2302 *
2303 * Parse a file using the reader API from memory and check for errors.
2304 *
2305 * Returns 0 in case of success, an error code otherwise
2306 */
2307static int
2308streamMemParseTest(const char *filename, const char *result, const char *err,
2309 int options) {
2310 xmlTextReaderPtr reader;
2311 int ret;
2312 const char *base;
2313 int size;
2314
2315 /*
2316 * load and parse the memory
2317 */
2318 if (loadMem(filename, &base, &size) != 0) {
2319 fprintf(stderr, "Failed to load %s\n", filename);
2320 return(-1);
2321 }
2322 reader = xmlReaderForMemory(base, size, filename, NULL, options);
Daniel Veillarda7982ce2012-10-25 15:39:39 +08002323 ret = streamProcessTest(filename, result, err, reader, NULL, options);
William M. Brackca15a542005-07-06 20:41:33 +00002324 free((char *)base);
2325 xmlFreeTextReader(reader);
2326 return(ret);
2327}
2328#endif
2329
2330#ifdef LIBXML_XPATH_ENABLED
2331#ifdef LIBXML_DEBUG_ENABLED
2332/************************************************************************
2333 * *
2334 * XPath and XPointer based tests *
2335 * *
2336 ************************************************************************/
2337
Daniel Veillard24505b02005-07-28 23:49:35 +00002338static FILE *xpathOutput;
2339static xmlDocPtr xpathDocument;
William M. Brackca15a542005-07-06 20:41:33 +00002340
2341static void
Nick Wellnhofer1fc55ca2016-06-25 12:35:09 +02002342ignoreGenericError(void *ctx ATTRIBUTE_UNUSED,
2343 const char *msg ATTRIBUTE_UNUSED, ...) {
2344}
2345
2346static void
William M. Brackca15a542005-07-06 20:41:33 +00002347testXPath(const char *str, int xptr, int expr) {
Nick Wellnhofer1fc55ca2016-06-25 12:35:09 +02002348 xmlGenericErrorFunc handler = ignoreGenericError;
William M. Brackca15a542005-07-06 20:41:33 +00002349 xmlXPathObjectPtr res;
2350 xmlXPathContextPtr ctxt;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002351
Nick Wellnhofer1fc55ca2016-06-25 12:35:09 +02002352 /* Don't print generic errors to stderr. */
2353 initGenericErrorDefaultFunc(&handler);
2354
William M. Brackca15a542005-07-06 20:41:33 +00002355 nb_tests++;
2356#if defined(LIBXML_XPTR_ENABLED)
2357 if (xptr) {
2358 ctxt = xmlXPtrNewContext(xpathDocument, NULL, NULL);
2359 res = xmlXPtrEval(BAD_CAST str, ctxt);
2360 } else {
2361#endif
2362 ctxt = xmlXPathNewContext(xpathDocument);
2363 ctxt->node = xmlDocGetRootElement(xpathDocument);
2364 if (expr)
2365 res = xmlXPathEvalExpression(BAD_CAST str, ctxt);
2366 else {
2367 /* res = xmlXPathEval(BAD_CAST str, ctxt); */
2368 xmlXPathCompExprPtr comp;
2369
2370 comp = xmlXPathCompile(BAD_CAST str);
2371 if (comp != NULL) {
2372 res = xmlXPathCompiledEval(comp, ctxt);
2373 xmlXPathFreeCompExpr(comp);
2374 } else
2375 res = NULL;
2376 }
2377#if defined(LIBXML_XPTR_ENABLED)
2378 }
2379#endif
2380 xmlXPathDebugDumpObject(xpathOutput, res, 0);
2381 xmlXPathFreeObject(res);
2382 xmlXPathFreeContext(ctxt);
Nick Wellnhofer1fc55ca2016-06-25 12:35:09 +02002383
2384 /* Reset generic error handler. */
2385 initGenericErrorDefaultFunc(NULL);
William M. Brackca15a542005-07-06 20:41:33 +00002386}
2387
2388/**
2389 * xpathExprTest:
2390 * @filename: the file to parse
2391 * @result: the file with expected result
2392 * @err: the file with error messages
2393 *
2394 * Parse a file containing XPath standalone expressions and evaluate them
2395 *
2396 * Returns 0 in case of success, an error code otherwise
2397 */
2398static int
2399xpathCommonTest(const char *filename, const char *result,
2400 int xptr, int expr) {
2401 FILE *input;
2402 char expression[5000];
2403 int len, ret = 0;
2404 char *temp;
2405
2406 temp = resultFilename(filename, "", ".res");
2407 if (temp == NULL) {
2408 fprintf(stderr, "Out of memory\n");
2409 fatalError();
2410 }
2411 xpathOutput = fopen(temp, "wb");
2412 if (xpathOutput == NULL) {
2413 fprintf(stderr, "failed to open output file %s\n", temp);
2414 free(temp);
2415 return(-1);
2416 }
2417
2418 input = fopen(filename, "rb");
2419 if (input == NULL) {
2420 xmlGenericError(xmlGenericErrorContext,
2421 "Cannot open %s for reading\n", filename);
2422 free(temp);
2423 return(-1);
2424 }
2425 while (fgets(expression, 4500, input) != NULL) {
2426 len = strlen(expression);
2427 len--;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002428 while ((len >= 0) &&
William M. Brackca15a542005-07-06 20:41:33 +00002429 ((expression[len] == '\n') || (expression[len] == '\t') ||
2430 (expression[len] == '\r') || (expression[len] == ' '))) len--;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002431 expression[len + 1] = 0;
William M. Brackca15a542005-07-06 20:41:33 +00002432 if (len >= 0) {
2433 fprintf(xpathOutput,
2434 "\n========================\nExpression: %s\n",
2435 expression) ;
2436 testXPath(expression, xptr, expr);
2437 }
2438 }
2439
2440 fclose(input);
2441 fclose(xpathOutput);
2442 if (result != NULL) {
2443 ret = compareFiles(temp, result);
2444 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002445 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002446 }
2447 }
2448
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002449 if (temp != NULL) {
2450 unlink(temp);
2451 free(temp);
2452 }
William M. Brackca15a542005-07-06 20:41:33 +00002453 return(ret);
2454}
2455
2456/**
2457 * xpathExprTest:
2458 * @filename: the file to parse
2459 * @result: the file with expected result
2460 * @err: the file with error messages
2461 *
2462 * Parse a file containing XPath standalone expressions and evaluate them
2463 *
2464 * Returns 0 in case of success, an error code otherwise
2465 */
2466static int
2467xpathExprTest(const char *filename, const char *result,
2468 const char *err ATTRIBUTE_UNUSED,
2469 int options ATTRIBUTE_UNUSED) {
2470 return(xpathCommonTest(filename, result, 0, 1));
2471}
2472
2473/**
2474 * xpathDocTest:
2475 * @filename: the file to parse
2476 * @result: the file with expected result
2477 * @err: the file with error messages
2478 *
2479 * Parse a file containing XPath expressions and evaluate them against
2480 * a set of corresponding documents.
2481 *
2482 * Returns 0 in case of success, an error code otherwise
2483 */
2484static int
2485xpathDocTest(const char *filename,
2486 const char *resul ATTRIBUTE_UNUSED,
2487 const char *err ATTRIBUTE_UNUSED,
2488 int options) {
2489
2490 char pattern[500];
2491 char result[500];
2492 glob_t globbuf;
2493 size_t i;
2494 int ret = 0, res;
2495
2496 xpathDocument = xmlReadFile(filename, NULL,
2497 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2498 if (xpathDocument == NULL) {
2499 fprintf(stderr, "Failed to load %s\n", filename);
2500 return(-1);
2501 }
2502
2503 snprintf(pattern, 499, "./test/XPath/tests/%s*", baseFilename(filename));
2504 pattern[499] = 0;
2505 globbuf.gl_offs = 0;
2506 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2507 for (i = 0;i < globbuf.gl_pathc;i++) {
2508 snprintf(result, 499, "result/XPath/tests/%s",
2509 baseFilename(globbuf.gl_pathv[i]));
2510 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 0, 0);
2511 if (res != 0)
2512 ret = res;
2513 }
2514 globfree(&globbuf);
2515
2516 xmlFreeDoc(xpathDocument);
2517 return(ret);
2518}
2519
2520#ifdef LIBXML_XPTR_ENABLED
2521/**
2522 * xptrDocTest:
2523 * @filename: the file to parse
2524 * @result: the file with expected result
2525 * @err: the file with error messages
2526 *
2527 * Parse a file containing XPath expressions and evaluate them against
2528 * a set of corresponding documents.
2529 *
2530 * Returns 0 in case of success, an error code otherwise
2531 */
2532static int
2533xptrDocTest(const char *filename,
2534 const char *resul ATTRIBUTE_UNUSED,
2535 const char *err ATTRIBUTE_UNUSED,
2536 int options) {
2537
2538 char pattern[500];
2539 char result[500];
2540 glob_t globbuf;
2541 size_t i;
2542 int ret = 0, res;
2543
2544 xpathDocument = xmlReadFile(filename, NULL,
2545 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2546 if (xpathDocument == NULL) {
2547 fprintf(stderr, "Failed to load %s\n", filename);
2548 return(-1);
2549 }
2550
2551 snprintf(pattern, 499, "./test/XPath/xptr/%s*", baseFilename(filename));
2552 pattern[499] = 0;
2553 globbuf.gl_offs = 0;
2554 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2555 for (i = 0;i < globbuf.gl_pathc;i++) {
2556 snprintf(result, 499, "result/XPath/xptr/%s",
2557 baseFilename(globbuf.gl_pathv[i]));
2558 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 1, 0);
2559 if (res != 0)
2560 ret = res;
2561 }
2562 globfree(&globbuf);
2563
2564 xmlFreeDoc(xpathDocument);
2565 return(ret);
2566}
2567#endif /* LIBXML_XPTR_ENABLED */
2568
2569/**
2570 * xmlidDocTest:
2571 * @filename: the file to parse
2572 * @result: the file with expected result
2573 * @err: the file with error messages
2574 *
2575 * Parse a file containing xml:id and check for errors and verify
2576 * that XPath queries will work on them as expected.
2577 *
2578 * Returns 0 in case of success, an error code otherwise
2579 */
2580static int
2581xmlidDocTest(const char *filename,
2582 const char *result,
2583 const char *err,
2584 int options) {
2585
2586 int res = 0;
2587 int ret = 0;
2588 char *temp;
2589
2590 xpathDocument = xmlReadFile(filename, NULL,
2591 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2592 if (xpathDocument == NULL) {
2593 fprintf(stderr, "Failed to load %s\n", filename);
2594 return(-1);
2595 }
2596
2597 temp = resultFilename(filename, "", ".res");
2598 if (temp == NULL) {
2599 fprintf(stderr, "Out of memory\n");
2600 fatalError();
2601 }
2602 xpathOutput = fopen(temp, "wb");
2603 if (xpathOutput == NULL) {
2604 fprintf(stderr, "failed to open output file %s\n", temp);
2605 xmlFreeDoc(xpathDocument);
2606 free(temp);
2607 return(-1);
2608 }
2609
2610 testXPath("id('bar')", 0, 0);
2611
2612 fclose(xpathOutput);
2613 if (result != NULL) {
2614 ret = compareFiles(temp, result);
2615 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002616 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002617 res = 1;
2618 }
2619 }
2620
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002621 if (temp != NULL) {
2622 unlink(temp);
2623 free(temp);
2624 }
William M. Brackca15a542005-07-06 20:41:33 +00002625 xmlFreeDoc(xpathDocument);
2626
2627 if (err != NULL) {
2628 ret = compareFileMem(err, testErrors, testErrorsSize);
2629 if (ret != 0) {
2630 fprintf(stderr, "Error for %s failed\n", filename);
2631 res = 1;
2632 }
2633 }
2634 return(res);
2635}
2636
2637#endif /* LIBXML_DEBUG_ENABLED */
2638#endif /* XPATH */
2639/************************************************************************
2640 * *
2641 * URI based tests *
2642 * *
2643 ************************************************************************/
2644
2645static void
2646handleURI(const char *str, const char *base, FILE *o) {
2647 int ret;
2648 xmlURIPtr uri;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002649 xmlChar *res = NULL;
William M. Brackca15a542005-07-06 20:41:33 +00002650
2651 uri = xmlCreateURI();
2652
2653 if (base == NULL) {
2654 ret = xmlParseURIReference(uri, str);
2655 if (ret != 0)
2656 fprintf(o, "%s : error %d\n", str, ret);
2657 else {
2658 xmlNormalizeURIPath(uri->path);
2659 xmlPrintURI(o, uri);
2660 fprintf(o, "\n");
2661 }
2662 } else {
2663 res = xmlBuildURI((xmlChar *)str, (xmlChar *) base);
2664 if (res != NULL) {
2665 fprintf(o, "%s\n", (char *) res);
2666 }
2667 else
2668 fprintf(o, "::ERROR::\n");
2669 }
2670 if (res != NULL)
2671 xmlFree(res);
William M. Brackca15a542005-07-06 20:41:33 +00002672 xmlFreeURI(uri);
2673}
2674
2675/**
2676 * uriCommonTest:
2677 * @filename: the file to parse
2678 * @result: the file with expected result
2679 * @err: the file with error messages
2680 *
2681 * Parse a file containing URI and check for errors
2682 *
2683 * Returns 0 in case of success, an error code otherwise
2684 */
2685static int
2686uriCommonTest(const char *filename,
2687 const char *result,
2688 const char *err,
2689 const char *base) {
2690 char *temp;
2691 FILE *o, *f;
2692 char str[1024];
2693 int res = 0, i, ret;
2694
2695 temp = resultFilename(filename, "", ".res");
2696 if (temp == NULL) {
2697 fprintf(stderr, "Out of memory\n");
2698 fatalError();
2699 }
2700 o = fopen(temp, "wb");
2701 if (o == NULL) {
2702 fprintf(stderr, "failed to open output file %s\n", temp);
2703 free(temp);
2704 return(-1);
2705 }
2706 f = fopen(filename, "rb");
2707 if (f == NULL) {
2708 fprintf(stderr, "failed to open input file %s\n", filename);
2709 fclose(o);
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002710 if (temp != NULL) {
2711 unlink(temp);
2712 free(temp);
2713 }
William M. Brackca15a542005-07-06 20:41:33 +00002714 return(-1);
2715 }
2716
2717 while (1) {
2718 /*
2719 * read one line in string buffer.
2720 */
2721 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
2722 break;
2723
2724 /*
2725 * remove the ending spaces
2726 */
2727 i = strlen(str);
2728 while ((i > 0) &&
2729 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
2730 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
2731 i--;
2732 str[i] = 0;
2733 }
2734 nb_tests++;
2735 handleURI(str, base, o);
2736 }
2737
2738 fclose(f);
2739 fclose(o);
2740
2741 if (result != NULL) {
2742 ret = compareFiles(temp, result);
2743 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002744 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002745 res = 1;
2746 }
2747 }
2748 if (err != NULL) {
2749 ret = compareFileMem(err, testErrors, testErrorsSize);
2750 if (ret != 0) {
2751 fprintf(stderr, "Error for %s failed\n", filename);
2752 res = 1;
2753 }
2754 }
2755
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002756 if (temp != NULL) {
2757 unlink(temp);
2758 free(temp);
2759 }
William M. Brackca15a542005-07-06 20:41:33 +00002760 return(res);
2761}
2762
2763/**
2764 * uriParseTest:
2765 * @filename: the file to parse
2766 * @result: the file with expected result
2767 * @err: the file with error messages
2768 *
2769 * Parse a file containing URI and check for errors
2770 *
2771 * Returns 0 in case of success, an error code otherwise
2772 */
2773static int
2774uriParseTest(const char *filename,
2775 const char *result,
2776 const char *err,
2777 int options ATTRIBUTE_UNUSED) {
2778 return(uriCommonTest(filename, result, err, NULL));
2779}
2780
2781/**
2782 * uriBaseTest:
2783 * @filename: the file to parse
2784 * @result: the file with expected result
2785 * @err: the file with error messages
2786 *
2787 * Parse a file containing URI, compose them against a fixed base and
2788 * check for errors
2789 *
2790 * Returns 0 in case of success, an error code otherwise
2791 */
2792static int
2793uriBaseTest(const char *filename,
2794 const char *result,
2795 const char *err,
2796 int options ATTRIBUTE_UNUSED) {
2797 return(uriCommonTest(filename, result, err,
2798 "http://foo.com/path/to/index.html?orig#help"));
2799}
2800
Daniel Veillard336a8e12005-08-07 10:46:19 +00002801static int urip_success = 1;
2802static int urip_current = 0;
2803static const char *urip_testURLs[] = {
2804 "urip://example.com/a b.html",
2805 "urip://example.com/a%20b.html",
2806 "file:///path/to/a b.html",
2807 "file:///path/to/a%20b.html",
2808 "/path/to/a b.html",
2809 "/path/to/a%20b.html",
Daniel Veillardff7227f2012-08-20 20:58:24 +08002810 "urip://example.com/r" "\xe9" "sum" "\xe9" ".html",
Daniel Veillard336a8e12005-08-07 10:46:19 +00002811 "urip://example.com/test?a=1&b=2%263&c=4#foo",
2812 NULL
2813};
2814static const char *urip_rcvsURLs[] = {
2815 /* it is an URI the strings must be escaped */
2816 "urip://example.com/a%20b.html",
2817 /* check that % escaping is not broken */
2818 "urip://example.com/a%20b.html",
2819 /* it's an URI path the strings must be escaped */
2820 "file:///path/to/a%20b.html",
2821 /* check that % escaping is not broken */
2822 "file:///path/to/a%20b.html",
2823 /* this is not an URI, this is a path, so this should not be escaped */
2824 "/path/to/a b.html",
2825 /* check that paths with % are not broken */
2826 "/path/to/a%20b.html",
2827 /* out of context the encoding can't be guessed byte by byte conversion */
2828 "urip://example.com/r%E9sum%E9.html",
2829 /* verify we don't destroy URIs especially the query part */
2830 "urip://example.com/test?a=1&b=2%263&c=4#foo",
2831 NULL
2832};
2833static const char *urip_res = "<list/>";
2834static const char *urip_cur = NULL;
2835static int urip_rlen;
2836
2837/**
2838 * uripMatch:
2839 * @URI: an URI to test
2840 *
2841 * Check for an urip: query
2842 *
2843 * Returns 1 if yes and 0 if another Input module should be used
2844 */
2845static int
2846uripMatch(const char * URI) {
2847 if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog")))
2848 return(0);
2849 /* Verify we received the escaped URL */
2850 if (strcmp(urip_rcvsURLs[urip_current], URI))
2851 urip_success = 0;
2852 return(1);
2853}
2854
2855/**
2856 * uripOpen:
2857 * @URI: an URI to test
2858 *
2859 * Return a pointer to the urip: query handler, in this example simply
2860 * the urip_current pointer...
2861 *
2862 * Returns an Input context or NULL in case or error
2863 */
2864static void *
2865uripOpen(const char * URI) {
2866 if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog")))
2867 return(NULL);
2868 /* Verify we received the escaped URL */
2869 if (strcmp(urip_rcvsURLs[urip_current], URI))
2870 urip_success = 0;
2871 urip_cur = urip_res;
2872 urip_rlen = strlen(urip_res);
2873 return((void *) urip_cur);
2874}
2875
2876/**
2877 * uripClose:
2878 * @context: the read context
2879 *
2880 * Close the urip: query handler
2881 *
2882 * Returns 0 or -1 in case of error
2883 */
2884static int
2885uripClose(void * context) {
2886 if (context == NULL) return(-1);
2887 urip_cur = NULL;
2888 urip_rlen = 0;
2889 return(0);
2890}
2891
2892/**
2893 * uripRead:
2894 * @context: the read context
2895 * @buffer: where to store data
2896 * @len: number of bytes to read
2897 *
2898 * Implement an urip: query read.
2899 *
2900 * Returns the number of bytes read or -1 in case of error
2901 */
2902static int
2903uripRead(void * context, char * buffer, int len) {
2904 const char *ptr = (const char *) context;
2905
2906 if ((context == NULL) || (buffer == NULL) || (len < 0))
2907 return(-1);
2908
2909 if (len > urip_rlen) len = urip_rlen;
2910 memcpy(buffer, ptr, len);
2911 urip_rlen -= len;
2912 return(len);
2913}
2914
2915static int
2916urip_checkURL(const char *URL) {
2917 xmlDocPtr doc;
2918
2919 doc = xmlReadFile(URL, NULL, 0);
2920 if (doc == NULL)
2921 return(-1);
2922 xmlFreeDoc(doc);
2923 return(1);
2924}
2925
2926/**
2927 * uriPathTest:
2928 * @filename: ignored
2929 * @result: ignored
2930 * @err: ignored
2931 *
2932 * Run a set of tests to check how Path and URI are handled before
2933 * being passed to the I/O layer
2934 *
2935 * Returns 0 in case of success, an error code otherwise
2936 */
2937static int
2938uriPathTest(const char *filename ATTRIBUTE_UNUSED,
2939 const char *result ATTRIBUTE_UNUSED,
2940 const char *err ATTRIBUTE_UNUSED,
2941 int options ATTRIBUTE_UNUSED) {
2942 int parsed;
2943 int failures = 0;
2944
2945 /*
2946 * register the new I/O handlers
2947 */
2948 if (xmlRegisterInputCallbacks(uripMatch, uripOpen, uripRead, uripClose) < 0)
2949 {
2950 fprintf(stderr, "failed to register HTTP handler\n");
2951 return(-1);
2952 }
2953
2954 for (urip_current = 0;urip_testURLs[urip_current] != NULL;urip_current++) {
2955 urip_success = 1;
2956 parsed = urip_checkURL(urip_testURLs[urip_current]);
2957 if (urip_success != 1) {
2958 fprintf(stderr, "failed the URL passing test for %s",
2959 urip_testURLs[urip_current]);
2960 failures++;
2961 } else if (parsed != 1) {
2962 fprintf(stderr, "failed the parsing test for %s",
2963 urip_testURLs[urip_current]);
2964 failures++;
2965 }
2966 nb_tests++;
2967 }
2968
2969 xmlPopInputCallbacks();
2970 return(failures);
2971}
2972
William M. Brackca15a542005-07-06 20:41:33 +00002973#ifdef LIBXML_SCHEMAS_ENABLED
2974/************************************************************************
2975 * *
2976 * Schemas tests *
2977 * *
2978 ************************************************************************/
2979static int
2980schemasOneTest(const char *sch,
2981 const char *filename,
2982 const char *result,
2983 const char *err,
2984 int options,
2985 xmlSchemaPtr schemas) {
2986 xmlDocPtr doc;
2987 xmlSchemaValidCtxtPtr ctxt;
2988 int ret = 0;
Daniel Veillard381ff362006-06-18 17:31:31 +00002989 int validResult = 0;
William M. Brackca15a542005-07-06 20:41:33 +00002990 char *temp;
2991 FILE *schemasOutput;
2992
2993 doc = xmlReadFile(filename, NULL, options);
2994 if (doc == NULL) {
2995 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
2996 return(-1);
2997 }
2998
2999 temp = resultFilename(result, "", ".res");
3000 if (temp == NULL) {
3001 fprintf(stderr, "Out of memory\n");
3002 fatalError();
3003 }
3004 schemasOutput = fopen(temp, "wb");
3005 if (schemasOutput == NULL) {
3006 fprintf(stderr, "failed to open output file %s\n", temp);
3007 xmlFreeDoc(doc);
3008 free(temp);
3009 return(-1);
3010 }
3011
3012 ctxt = xmlSchemaNewValidCtxt(schemas);
3013 xmlSchemaSetValidErrors(ctxt,
3014 (xmlSchemaValidityErrorFunc) testErrorHandler,
3015 (xmlSchemaValidityWarningFunc) testErrorHandler,
3016 ctxt);
Daniel Veillard381ff362006-06-18 17:31:31 +00003017 validResult = xmlSchemaValidateDoc(ctxt, doc);
3018 if (validResult == 0) {
William M. Brackca15a542005-07-06 20:41:33 +00003019 fprintf(schemasOutput, "%s validates\n", filename);
Daniel Veillard381ff362006-06-18 17:31:31 +00003020 } else if (validResult > 0) {
William M. Brackca15a542005-07-06 20:41:33 +00003021 fprintf(schemasOutput, "%s fails to validate\n", filename);
3022 } else {
3023 fprintf(schemasOutput, "%s validation generated an internal error\n",
3024 filename);
3025 }
3026 fclose(schemasOutput);
3027 if (result) {
3028 if (compareFiles(temp, result)) {
3029 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
3030 ret = 1;
3031 }
3032 }
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003033 if (temp != NULL) {
3034 unlink(temp);
3035 free(temp);
3036 }
William M. Brackca15a542005-07-06 20:41:33 +00003037
Daniel Veillard381ff362006-06-18 17:31:31 +00003038 if ((validResult != 0) && (err != NULL)) {
William M. Brackca15a542005-07-06 20:41:33 +00003039 if (compareFileMem(err, testErrors, testErrorsSize)) {
3040 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
3041 ret = 1;
3042 }
3043 }
3044
William M. Brackca15a542005-07-06 20:41:33 +00003045 xmlSchemaFreeValidCtxt(ctxt);
3046 xmlFreeDoc(doc);
3047 return(ret);
3048}
3049/**
3050 * schemasTest:
3051 * @filename: the schemas file
3052 * @result: the file with expected result
3053 * @err: the file with error messages
3054 *
3055 * Parse a file containing URI, compose them against a fixed base and
3056 * check for errors
3057 *
3058 * Returns 0 in case of success, an error code otherwise
3059 */
3060static int
3061schemasTest(const char *filename,
3062 const char *resul ATTRIBUTE_UNUSED,
3063 const char *errr ATTRIBUTE_UNUSED,
3064 int options) {
3065 const char *base = baseFilename(filename);
3066 const char *base2;
3067 const char *instance;
3068 xmlSchemaParserCtxtPtr ctxt;
3069 xmlSchemaPtr schemas;
3070 int res = 0, len, ret;
3071 char pattern[500];
3072 char prefix[500];
3073 char result[500];
3074 char err[500];
3075 glob_t globbuf;
3076 size_t i;
3077 char count = 0;
3078
3079 /* first compile the schemas if possible */
3080 ctxt = xmlSchemaNewParserCtxt(filename);
3081 xmlSchemaSetParserErrors(ctxt,
3082 (xmlSchemaValidityErrorFunc) testErrorHandler,
3083 (xmlSchemaValidityWarningFunc) testErrorHandler,
3084 ctxt);
3085 schemas = xmlSchemaParse(ctxt);
3086 xmlSchemaFreeParserCtxt(ctxt);
3087
3088 /*
3089 * most of the mess is about the output filenames generated by the Makefile
3090 */
3091 len = strlen(base);
3092 if ((len > 499) || (len < 5)) {
3093 xmlSchemaFree(schemas);
3094 return(-1);
3095 }
3096 len -= 4; /* remove trailing .xsd */
3097 if (base[len - 2] == '_') {
3098 len -= 2; /* remove subtest number */
3099 }
3100 if (base[len - 2] == '_') {
3101 len -= 2; /* remove subtest number */
3102 }
3103 memcpy(prefix, base, len);
3104 prefix[len] = 0;
3105
3106 snprintf(pattern, 499, "./test/schemas/%s_?.xml", prefix);
3107 pattern[499] = 0;
3108
3109 if (base[len] == '_') {
3110 len += 2;
3111 memcpy(prefix, base, len);
3112 prefix[len] = 0;
3113 }
3114
3115 globbuf.gl_offs = 0;
3116 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3117 for (i = 0;i < globbuf.gl_pathc;i++) {
3118 testErrorsSize = 0;
3119 testErrors[0] = 0;
3120 instance = globbuf.gl_pathv[i];
3121 base2 = baseFilename(instance);
3122 len = strlen(base2);
3123 if ((len > 6) && (base2[len - 6] == '_')) {
3124 count = base2[len - 5];
3125 snprintf(result, 499, "result/schemas/%s_%c",
3126 prefix, count);
3127 result[499] = 0;
3128 snprintf(err, 499, "result/schemas/%s_%c.err",
3129 prefix, count);
3130 err[499] = 0;
3131 } else {
3132 fprintf(stderr, "don't know how to process %s\n", instance);
3133 continue;
3134 }
3135 if (schemas == NULL) {
3136 } else {
3137 nb_tests++;
3138 ret = schemasOneTest(filename, instance, result, err,
3139 options, schemas);
Daniel Veillard93e577f2005-11-15 08:50:04 +00003140 if (ret != 0)
3141 res = ret;
William M. Brackca15a542005-07-06 20:41:33 +00003142 }
3143 }
3144 globfree(&globbuf);
3145 xmlSchemaFree(schemas);
3146
3147 return(res);
3148}
3149
3150/************************************************************************
3151 * *
3152 * Schemas tests *
3153 * *
3154 ************************************************************************/
3155static int
3156rngOneTest(const char *sch,
3157 const char *filename,
3158 const char *result,
3159 const char *err,
3160 int options,
3161 xmlRelaxNGPtr schemas) {
3162 xmlDocPtr doc;
3163 xmlRelaxNGValidCtxtPtr ctxt;
3164 int ret = 0;
3165 char *temp;
3166 FILE *schemasOutput;
3167
3168 doc = xmlReadFile(filename, NULL, options);
3169 if (doc == NULL) {
3170 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
3171 return(-1);
3172 }
3173
3174 temp = resultFilename(result, "", ".res");
3175 if (temp == NULL) {
3176 fprintf(stderr, "Out of memory\n");
3177 fatalError();
3178 }
3179 schemasOutput = fopen(temp, "wb");
3180 if (schemasOutput == NULL) {
3181 fprintf(stderr, "failed to open output file %s\n", temp);
3182 xmlFreeDoc(doc);
3183 free(temp);
3184 return(-1);
3185 }
3186
3187 ctxt = xmlRelaxNGNewValidCtxt(schemas);
3188 xmlRelaxNGSetValidErrors(ctxt,
3189 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
3190 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
3191 ctxt);
3192 ret = xmlRelaxNGValidateDoc(ctxt, doc);
3193 if (ret == 0) {
3194 testErrorHandler(NULL, "%s validates\n", filename);
3195 } else if (ret > 0) {
3196 testErrorHandler(NULL, "%s fails to validate\n", filename);
3197 } else {
3198 testErrorHandler(NULL, "%s validation generated an internal error\n",
3199 filename);
3200 }
3201 fclose(schemasOutput);
Daniel Veillard594e5df2009-09-07 14:58:47 +02003202 ret = 0;
William M. Brackca15a542005-07-06 20:41:33 +00003203 if (result) {
3204 if (compareFiles(temp, result)) {
3205 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
3206 ret = 1;
3207 }
3208 }
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003209 if (temp != NULL) {
3210 unlink(temp);
3211 free(temp);
3212 }
William M. Brackca15a542005-07-06 20:41:33 +00003213
3214 if (err != NULL) {
3215 if (compareFileMem(err, testErrors, testErrorsSize)) {
3216 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
3217 ret = 1;
3218 printf("%s", testErrors);
3219 }
3220 }
3221
3222
3223 xmlRelaxNGFreeValidCtxt(ctxt);
3224 xmlFreeDoc(doc);
3225 return(ret);
3226}
3227/**
3228 * rngTest:
3229 * @filename: the schemas file
3230 * @result: the file with expected result
3231 * @err: the file with error messages
3232 *
3233 * Parse an RNG schemas and then apply it to the related .xml
3234 *
3235 * Returns 0 in case of success, an error code otherwise
3236 */
3237static int
3238rngTest(const char *filename,
3239 const char *resul ATTRIBUTE_UNUSED,
3240 const char *errr ATTRIBUTE_UNUSED,
3241 int options) {
3242 const char *base = baseFilename(filename);
3243 const char *base2;
3244 const char *instance;
3245 xmlRelaxNGParserCtxtPtr ctxt;
3246 xmlRelaxNGPtr schemas;
Rob Richardsc9667902010-01-22 08:24:25 -05003247 int res = 0, len, ret = 0;
William M. Brackca15a542005-07-06 20:41:33 +00003248 char pattern[500];
3249 char prefix[500];
3250 char result[500];
3251 char err[500];
3252 glob_t globbuf;
3253 size_t i;
3254 char count = 0;
3255
3256 /* first compile the schemas if possible */
3257 ctxt = xmlRelaxNGNewParserCtxt(filename);
3258 xmlRelaxNGSetParserErrors(ctxt,
3259 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
3260 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
3261 ctxt);
3262 schemas = xmlRelaxNGParse(ctxt);
3263 xmlRelaxNGFreeParserCtxt(ctxt);
3264
3265 /*
3266 * most of the mess is about the output filenames generated by the Makefile
3267 */
3268 len = strlen(base);
3269 if ((len > 499) || (len < 5)) {
3270 xmlRelaxNGFree(schemas);
3271 return(-1);
3272 }
3273 len -= 4; /* remove trailing .rng */
3274 memcpy(prefix, base, len);
3275 prefix[len] = 0;
3276
3277 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
3278 pattern[499] = 0;
3279
3280 globbuf.gl_offs = 0;
3281 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3282 for (i = 0;i < globbuf.gl_pathc;i++) {
3283 testErrorsSize = 0;
3284 testErrors[0] = 0;
3285 instance = globbuf.gl_pathv[i];
3286 base2 = baseFilename(instance);
3287 len = strlen(base2);
3288 if ((len > 6) && (base2[len - 6] == '_')) {
3289 count = base2[len - 5];
3290 snprintf(result, 499, "result/relaxng/%s_%c",
3291 prefix, count);
3292 result[499] = 0;
3293 snprintf(err, 499, "result/relaxng/%s_%c.err",
3294 prefix, count);
3295 err[499] = 0;
3296 } else {
3297 fprintf(stderr, "don't know how to process %s\n", instance);
3298 continue;
3299 }
3300 if (schemas == NULL) {
3301 } else {
3302 nb_tests++;
3303 ret = rngOneTest(filename, instance, result, err,
3304 options, schemas);
3305 if (res != 0)
3306 ret = res;
3307 }
3308 }
3309 globfree(&globbuf);
3310 xmlRelaxNGFree(schemas);
3311
Daniel Veillard594e5df2009-09-07 14:58:47 +02003312 return(ret);
William M. Brackca15a542005-07-06 20:41:33 +00003313}
3314
3315#ifdef LIBXML_READER_ENABLED
3316/**
3317 * rngStreamTest:
3318 * @filename: the schemas file
3319 * @result: the file with expected result
3320 * @err: the file with error messages
3321 *
Daniel Veillardaa6de472008-08-25 14:53:31 +00003322 * Parse a set of files with streaming, applying an RNG schemas
William M. Brackca15a542005-07-06 20:41:33 +00003323 *
3324 * Returns 0 in case of success, an error code otherwise
3325 */
3326static int
3327rngStreamTest(const char *filename,
3328 const char *resul ATTRIBUTE_UNUSED,
3329 const char *errr ATTRIBUTE_UNUSED,
3330 int options) {
3331 const char *base = baseFilename(filename);
3332 const char *base2;
3333 const char *instance;
3334 int res = 0, len, ret;
3335 char pattern[500];
3336 char prefix[500];
3337 char result[500];
3338 char err[500];
3339 glob_t globbuf;
3340 size_t i;
3341 char count = 0;
3342 xmlTextReaderPtr reader;
3343 int disable_err = 0;
3344
3345 /*
3346 * most of the mess is about the output filenames generated by the Makefile
3347 */
3348 len = strlen(base);
3349 if ((len > 499) || (len < 5)) {
3350 fprintf(stderr, "len(base) == %d !\n", len);
3351 return(-1);
3352 }
3353 len -= 4; /* remove trailing .rng */
3354 memcpy(prefix, base, len);
3355 prefix[len] = 0;
3356
3357 /*
3358 * strictly unifying the error messages is nearly impossible this
3359 * hack is also done in the Makefile
3360 */
3361 if ((!strcmp(prefix, "tutor10_1")) || (!strcmp(prefix, "tutor10_2")) ||
Daniel Veillardec18c962009-08-26 18:37:43 +02003362 (!strcmp(prefix, "tutor3_2")) || (!strcmp(prefix, "307377")) ||
3363 (!strcmp(prefix, "tutor8_2")))
William M. Brackca15a542005-07-06 20:41:33 +00003364 disable_err = 1;
3365
3366 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
3367 pattern[499] = 0;
3368
3369 globbuf.gl_offs = 0;
3370 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3371 for (i = 0;i < globbuf.gl_pathc;i++) {
3372 testErrorsSize = 0;
3373 testErrors[0] = 0;
3374 instance = globbuf.gl_pathv[i];
3375 base2 = baseFilename(instance);
3376 len = strlen(base2);
3377 if ((len > 6) && (base2[len - 6] == '_')) {
3378 count = base2[len - 5];
3379 snprintf(result, 499, "result/relaxng/%s_%c",
3380 prefix, count);
3381 result[499] = 0;
3382 snprintf(err, 499, "result/relaxng/%s_%c.err",
3383 prefix, count);
3384 err[499] = 0;
3385 } else {
3386 fprintf(stderr, "don't know how to process %s\n", instance);
3387 continue;
3388 }
3389 reader = xmlReaderForFile(instance, NULL, options);
3390 if (reader == NULL) {
3391 fprintf(stderr, "Failed to build reder for %s\n", instance);
3392 }
3393 if (disable_err == 1)
Daniel Veillarda7982ce2012-10-25 15:39:39 +08003394 ret = streamProcessTest(instance, result, NULL, reader, filename,
3395 options);
William M. Brackca15a542005-07-06 20:41:33 +00003396 else
Daniel Veillarda7982ce2012-10-25 15:39:39 +08003397 ret = streamProcessTest(instance, result, err, reader, filename,
3398 options);
William M. Brackca15a542005-07-06 20:41:33 +00003399 xmlFreeTextReader(reader);
3400 if (ret != 0) {
3401 fprintf(stderr, "instance %s failed\n", instance);
3402 res = ret;
3403 }
3404 }
3405 globfree(&globbuf);
3406
3407 return(res);
3408}
3409#endif /* READER */
3410
3411#endif
3412
3413#ifdef LIBXML_PATTERN_ENABLED
3414#ifdef LIBXML_READER_ENABLED
3415/************************************************************************
3416 * *
3417 * Patterns tests *
3418 * *
3419 ************************************************************************/
3420static void patternNode(FILE *out, xmlTextReaderPtr reader,
3421 const char *pattern, xmlPatternPtr patternc,
3422 xmlStreamCtxtPtr patstream) {
3423 xmlChar *path = NULL;
3424 int match = -1;
3425 int type, empty;
3426
3427 type = xmlTextReaderNodeType(reader);
3428 empty = xmlTextReaderIsEmptyElement(reader);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003429
William M. Brackca15a542005-07-06 20:41:33 +00003430 if (type == XML_READER_TYPE_ELEMENT) {
3431 /* do the check only on element start */
3432 match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader));
3433
3434 if (match) {
3435 path = xmlGetNodePath(xmlTextReaderCurrentNode(reader));
3436 fprintf(out, "Node %s matches pattern %s\n", path, pattern);
3437 }
3438 }
3439 if (patstream != NULL) {
3440 int ret;
3441
3442 if (type == XML_READER_TYPE_ELEMENT) {
3443 ret = xmlStreamPush(patstream,
3444 xmlTextReaderConstLocalName(reader),
3445 xmlTextReaderConstNamespaceUri(reader));
3446 if (ret < 0) {
3447 fprintf(out, "xmlStreamPush() failure\n");
3448 xmlFreeStreamCtxt(patstream);
3449 patstream = NULL;
3450 } else if (ret != match) {
3451 if (path == NULL) {
3452 path = xmlGetNodePath(
3453 xmlTextReaderCurrentNode(reader));
3454 }
3455 fprintf(out,
3456 "xmlPatternMatch and xmlStreamPush disagree\n");
3457 fprintf(out,
3458 " pattern %s node %s\n",
3459 pattern, path);
3460 }
William M. Brackca15a542005-07-06 20:41:33 +00003461
Daniel Veillardaa6de472008-08-25 14:53:31 +00003462
3463 }
William M. Brackca15a542005-07-06 20:41:33 +00003464 if ((type == XML_READER_TYPE_END_ELEMENT) ||
3465 ((type == XML_READER_TYPE_ELEMENT) && (empty))) {
3466 ret = xmlStreamPop(patstream);
3467 if (ret < 0) {
3468 fprintf(out, "xmlStreamPop() failure\n");
3469 xmlFreeStreamCtxt(patstream);
3470 patstream = NULL;
3471 }
3472 }
3473 }
3474 if (path != NULL)
3475 xmlFree(path);
3476}
3477
3478/**
3479 * patternTest:
3480 * @filename: the schemas file
3481 * @result: the file with expected result
3482 * @err: the file with error messages
3483 *
Daniel Veillardaa6de472008-08-25 14:53:31 +00003484 * Parse a set of files with streaming, applying an RNG schemas
William M. Brackca15a542005-07-06 20:41:33 +00003485 *
3486 * Returns 0 in case of success, an error code otherwise
3487 */
3488static int
3489patternTest(const char *filename,
3490 const char *resul ATTRIBUTE_UNUSED,
3491 const char *err ATTRIBUTE_UNUSED,
3492 int options) {
3493 xmlPatternPtr patternc = NULL;
3494 xmlStreamCtxtPtr patstream = NULL;
3495 FILE *o, *f;
3496 char str[1024];
3497 char xml[500];
3498 char result[500];
3499 int len, i;
3500 int ret = 0, res;
3501 char *temp;
3502 xmlTextReaderPtr reader;
3503 xmlDocPtr doc;
3504
3505 len = strlen(filename);
3506 len -= 4;
3507 memcpy(xml, filename, len);
3508 xml[len] = 0;
3509 snprintf(result, 499, "result/pattern/%s", baseFilename(xml));
3510 result[499] = 0;
3511 memcpy(xml + len, ".xml", 5);
3512
David Kilzer5c373822016-05-22 09:58:30 +08003513 if (!checkTestFile(xml) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00003514 fprintf(stderr, "Missing xml file %s\n", xml);
3515 return(-1);
3516 }
David Kilzer5c373822016-05-22 09:58:30 +08003517 if (!checkTestFile(result) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00003518 fprintf(stderr, "Missing result file %s\n", result);
3519 return(-1);
3520 }
3521 f = fopen(filename, "rb");
3522 if (f == NULL) {
3523 fprintf(stderr, "Failed to open %s\n", filename);
3524 return(-1);
3525 }
3526 temp = resultFilename(filename, "", ".res");
3527 if (temp == NULL) {
3528 fprintf(stderr, "Out of memory\n");
3529 fatalError();
3530 }
3531 o = fopen(temp, "wb");
3532 if (o == NULL) {
3533 fprintf(stderr, "failed to open output file %s\n", temp);
3534 fclose(f);
3535 free(temp);
3536 return(-1);
3537 }
3538 while (1) {
3539 /*
3540 * read one line in string buffer.
3541 */
3542 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
3543 break;
3544
3545 /*
3546 * remove the ending spaces
3547 */
3548 i = strlen(str);
3549 while ((i > 0) &&
3550 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
3551 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
3552 i--;
3553 str[i] = 0;
3554 }
3555 doc = xmlReadFile(xml, NULL, options);
3556 if (doc == NULL) {
3557 fprintf(stderr, "Failed to parse %s\n", xml);
3558 ret = 1;
3559 } else {
3560 xmlNodePtr root;
3561 const xmlChar *namespaces[22];
3562 int j;
3563 xmlNsPtr ns;
3564
3565 root = xmlDocGetRootElement(doc);
3566 for (ns = root->nsDef, j = 0;ns != NULL && j < 20;ns=ns->next) {
3567 namespaces[j++] = ns->href;
3568 namespaces[j++] = ns->prefix;
3569 }
3570 namespaces[j++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003571 namespaces[j] = NULL;
William M. Brackca15a542005-07-06 20:41:33 +00003572
3573 patternc = xmlPatterncompile((const xmlChar *) str, doc->dict,
3574 0, &namespaces[0]);
3575 if (patternc == NULL) {
3576 testErrorHandler(NULL,
3577 "Pattern %s failed to compile\n", str);
3578 xmlFreeDoc(doc);
3579 ret = 1;
3580 continue;
3581 }
3582 patstream = xmlPatternGetStreamCtxt(patternc);
3583 if (patstream != NULL) {
3584 ret = xmlStreamPush(patstream, NULL, NULL);
3585 if (ret < 0) {
3586 fprintf(stderr, "xmlStreamPush() failure\n");
3587 xmlFreeStreamCtxt(patstream);
3588 patstream = NULL;
3589 }
3590 }
3591 nb_tests++;
3592
3593 reader = xmlReaderWalker(doc);
3594 res = xmlTextReaderRead(reader);
3595 while (res == 1) {
3596 patternNode(o, reader, str, patternc, patstream);
3597 res = xmlTextReaderRead(reader);
3598 }
3599 if (res != 0) {
3600 fprintf(o, "%s : failed to parse\n", filename);
3601 }
3602 xmlFreeTextReader(reader);
3603 xmlFreeDoc(doc);
3604 xmlFreeStreamCtxt(patstream);
3605 patstream = NULL;
3606 xmlFreePattern(patternc);
3607
3608 }
3609 }
3610
3611 fclose(f);
3612 fclose(o);
3613
3614 ret = compareFiles(temp, result);
3615 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08003616 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00003617 ret = 1;
3618 }
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003619 if (temp != NULL) {
3620 unlink(temp);
3621 free(temp);
3622 }
William M. Brackca15a542005-07-06 20:41:33 +00003623 return(ret);
3624}
3625#endif /* READER */
3626#endif /* PATTERN */
3627#ifdef LIBXML_C14N_ENABLED
3628/************************************************************************
3629 * *
3630 * Canonicalization tests *
3631 * *
3632 ************************************************************************/
3633static xmlXPathObjectPtr
3634load_xpath_expr (xmlDocPtr parent_doc, const char* filename) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00003635 xmlXPathObjectPtr xpath;
William M. Brackca15a542005-07-06 20:41:33 +00003636 xmlDocPtr doc;
3637 xmlChar *expr;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003638 xmlXPathContextPtr ctx;
William M. Brackca15a542005-07-06 20:41:33 +00003639 xmlNodePtr node;
3640 xmlNsPtr ns;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003641
William M. Brackca15a542005-07-06 20:41:33 +00003642 /*
3643 * load XPath expr as a file
3644 */
3645 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3646 xmlSubstituteEntitiesDefault(1);
3647
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003648 doc = xmlReadFile(filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
William M. Brackca15a542005-07-06 20:41:33 +00003649 if (doc == NULL) {
3650 fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
3651 return(NULL);
3652 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003653
William M. Brackca15a542005-07-06 20:41:33 +00003654 /*
3655 * Check the document is of the right kind
Daniel Veillardaa6de472008-08-25 14:53:31 +00003656 */
William M. Brackca15a542005-07-06 20:41:33 +00003657 if(xmlDocGetRootElement(doc) == NULL) {
3658 fprintf(stderr,"Error: empty document for file \"%s\"\n", filename);
3659 xmlFreeDoc(doc);
3660 return(NULL);
3661 }
3662
3663 node = doc->children;
3664 while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) {
3665 node = node->next;
3666 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003667
3668 if(node == NULL) {
William M. Brackca15a542005-07-06 20:41:33 +00003669 fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename);
3670 xmlFreeDoc(doc);
3671 return(NULL);
3672 }
3673
3674 expr = xmlNodeGetContent(node);
3675 if(expr == NULL) {
3676 fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename);
3677 xmlFreeDoc(doc);
3678 return(NULL);
3679 }
3680
3681 ctx = xmlXPathNewContext(parent_doc);
3682 if(ctx == NULL) {
3683 fprintf(stderr,"Error: unable to create new context\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003684 xmlFree(expr);
3685 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003686 return(NULL);
3687 }
3688
3689 /*
3690 * Register namespaces
3691 */
3692 ns = node->nsDef;
3693 while(ns != NULL) {
3694 if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) {
3695 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 +00003696 xmlFree(expr);
3697 xmlXPathFreeContext(ctx);
3698 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003699 return(NULL);
3700 }
3701 ns = ns->next;
3702 }
3703
Daniel Veillardaa6de472008-08-25 14:53:31 +00003704 /*
William M. Brackca15a542005-07-06 20:41:33 +00003705 * Evaluate xpath
3706 */
3707 xpath = xmlXPathEvalExpression(expr, ctx);
3708 if(xpath == NULL) {
3709 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003710xmlFree(expr);
3711 xmlXPathFreeContext(ctx);
3712 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003713 return(NULL);
3714 }
3715
3716 /* print_xpath_nodes(xpath->nodesetval); */
3717
Daniel Veillardaa6de472008-08-25 14:53:31 +00003718 xmlFree(expr);
3719 xmlXPathFreeContext(ctx);
3720 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003721 return(xpath);
3722}
3723
3724/*
3725 * Macro used to grow the current buffer.
3726 */
3727#define xxx_growBufferReentrant() { \
3728 buffer_size *= 2; \
3729 buffer = (xmlChar **) \
Daniel Veillardaa6de472008-08-25 14:53:31 +00003730 xmlRealloc(buffer, buffer_size * sizeof(xmlChar*)); \
William M. Brackca15a542005-07-06 20:41:33 +00003731 if (buffer == NULL) { \
3732 perror("realloc failed"); \
3733 return(NULL); \
3734 } \
3735}
3736
3737static xmlChar **
3738parse_list(xmlChar *str) {
3739 xmlChar **buffer;
3740 xmlChar **out = NULL;
3741 int buffer_size = 0;
3742 int len;
3743
3744 if(str == NULL) {
3745 return(NULL);
3746 }
3747
3748 len = xmlStrlen(str);
3749 if((str[0] == '\'') && (str[len - 1] == '\'')) {
3750 str[len - 1] = '\0';
3751 str++;
William M. Brackca15a542005-07-06 20:41:33 +00003752 }
3753 /*
3754 * allocate an translation buffer.
3755 */
3756 buffer_size = 1000;
3757 buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*));
3758 if (buffer == NULL) {
3759 perror("malloc failed");
3760 return(NULL);
3761 }
3762 out = buffer;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003763
William M. Brackca15a542005-07-06 20:41:33 +00003764 while(*str != '\0') {
3765 if (out - buffer > buffer_size - 10) {
3766 int indx = out - buffer;
3767
3768 xxx_growBufferReentrant();
3769 out = &buffer[indx];
3770 }
3771 (*out++) = str;
3772 while(*str != ',' && *str != '\0') ++str;
3773 if(*str == ',') *(str++) = '\0';
3774 }
3775 (*out) = NULL;
3776 return buffer;
3777}
3778
Daniel Veillardaa6de472008-08-25 14:53:31 +00003779static int
Aleksey Sanin83868242009-07-09 10:26:22 +02003780c14nRunTest(const char* xml_filename, int with_comments, int mode,
William M. Brackca15a542005-07-06 20:41:33 +00003781 const char* xpath_filename, const char *ns_filename,
3782 const char* result_file) {
3783 xmlDocPtr doc;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003784 xmlXPathObjectPtr xpath = NULL;
William M. Brackca15a542005-07-06 20:41:33 +00003785 xmlChar *result = NULL;
3786 int ret;
3787 xmlChar **inclusive_namespaces = NULL;
3788 const char *nslist = NULL;
3789 int nssize;
3790
3791
3792 /*
3793 * build an XML tree from a the file; we need to add default
3794 * attributes and resolve all character and entities references
3795 */
3796 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3797 xmlSubstituteEntitiesDefault(1);
3798
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003799 doc = xmlReadFile(xml_filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
William M. Brackca15a542005-07-06 20:41:33 +00003800 if (doc == NULL) {
3801 fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename);
3802 return(-1);
3803 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003804
William M. Brackca15a542005-07-06 20:41:33 +00003805 /*
3806 * Check the document is of the right kind
Daniel Veillardaa6de472008-08-25 14:53:31 +00003807 */
William M. Brackca15a542005-07-06 20:41:33 +00003808 if(xmlDocGetRootElement(doc) == NULL) {
3809 fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename);
3810 xmlFreeDoc(doc);
3811 return(-1);
3812 }
3813
Daniel Veillardaa6de472008-08-25 14:53:31 +00003814 /*
3815 * load xpath file if specified
William M. Brackca15a542005-07-06 20:41:33 +00003816 */
3817 if(xpath_filename) {
3818 xpath = load_xpath_expr(doc, xpath_filename);
3819 if(xpath == NULL) {
3820 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003821 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003822 return(-1);
3823 }
3824 }
3825
3826 if (ns_filename != NULL) {
3827 if (loadMem(ns_filename, &nslist, &nssize)) {
3828 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3829 if(xpath != NULL) xmlXPathFreeObject(xpath);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003830 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003831 return(-1);
3832 }
3833 inclusive_namespaces = parse_list((xmlChar *) nslist);
3834 }
3835
3836 /*
3837 * Canonical form
Daniel Veillardaa6de472008-08-25 14:53:31 +00003838 */
William M. Brackca15a542005-07-06 20:41:33 +00003839 /* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */
Daniel Veillardaa6de472008-08-25 14:53:31 +00003840 ret = xmlC14NDocDumpMemory(doc,
3841 (xpath) ? xpath->nodesetval : NULL,
Aleksey Sanin83868242009-07-09 10:26:22 +02003842 mode, inclusive_namespaces,
William M. Brackca15a542005-07-06 20:41:33 +00003843 with_comments, &result);
3844 if (ret >= 0) {
3845 if(result != NULL) {
3846 if (compareFileMem(result_file, (const char *) result, ret)) {
3847 fprintf(stderr, "Result mismatch for %s\n", xml_filename);
Aleksey Sanin83868242009-07-09 10:26:22 +02003848 fprintf(stderr, "RESULT:\n%s\n", (const char*)result);
William M. Brackca15a542005-07-06 20:41:33 +00003849 ret = -1;
3850 }
3851 }
3852 } else {
3853 fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret);
3854 ret = -1;
3855 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003856
William M. Brackca15a542005-07-06 20:41:33 +00003857 /*
3858 * Cleanup
Daniel Veillardaa6de472008-08-25 14:53:31 +00003859 */
William M. Brackca15a542005-07-06 20:41:33 +00003860 if (result != NULL) xmlFree(result);
3861 if(xpath != NULL) xmlXPathFreeObject(xpath);
3862 if (inclusive_namespaces != NULL) xmlFree(inclusive_namespaces);
3863 if (nslist != NULL) free((char *) nslist);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003864 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003865
3866 return(ret);
3867}
3868
3869static int
Aleksey Sanin83868242009-07-09 10:26:22 +02003870c14nCommonTest(const char *filename, int with_comments, int mode,
William M. Brackca15a542005-07-06 20:41:33 +00003871 const char *subdir) {
3872 char buf[500];
3873 char prefix[500];
3874 const char *base;
3875 int len;
3876 char *result = NULL;
3877 char *xpath = NULL;
3878 char *ns = NULL;
3879 int ret = 0;
3880
3881 base = baseFilename(filename);
3882 len = strlen(base);
3883 len -= 4;
3884 memcpy(prefix, base, len);
3885 prefix[len] = 0;
3886
3887 snprintf(buf, 499, "result/c14n/%s/%s", subdir,prefix);
David Kilzer5c373822016-05-22 09:58:30 +08003888 if (!checkTestFile(buf) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00003889 fprintf(stderr, "Missing result file %s", buf);
3890 return(-1);
3891 }
3892 result = strdup(buf);
3893 snprintf(buf, 499, "test/c14n/%s/%s.xpath", subdir,prefix);
3894 if (checkTestFile(buf)) {
3895 xpath = strdup(buf);
3896 }
3897 snprintf(buf, 499, "test/c14n/%s/%s.ns", subdir,prefix);
3898 if (checkTestFile(buf)) {
3899 ns = strdup(buf);
3900 }
3901
3902 nb_tests++;
Aleksey Sanin83868242009-07-09 10:26:22 +02003903 if (c14nRunTest(filename, with_comments, mode,
William M. Brackca15a542005-07-06 20:41:33 +00003904 xpath, ns, result) < 0)
3905 ret = 1;
3906
3907 if (result != NULL) free(result);
3908 if (xpath != NULL) free(xpath);
3909 if (ns != NULL) free(ns);
3910 return(ret);
3911}
3912
3913static int
3914c14nWithCommentTest(const char *filename,
3915 const char *resul ATTRIBUTE_UNUSED,
3916 const char *err ATTRIBUTE_UNUSED,
3917 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003918 return(c14nCommonTest(filename, 1, XML_C14N_1_0, "with-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003919}
3920static int
3921c14nWithoutCommentTest(const char *filename,
3922 const char *resul ATTRIBUTE_UNUSED,
3923 const char *err ATTRIBUTE_UNUSED,
3924 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003925 return(c14nCommonTest(filename, 0, XML_C14N_1_0, "without-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003926}
3927static int
3928c14nExcWithoutCommentTest(const char *filename,
3929 const char *resul ATTRIBUTE_UNUSED,
3930 const char *err ATTRIBUTE_UNUSED,
3931 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003932 return(c14nCommonTest(filename, 0, XML_C14N_EXCLUSIVE_1_0, "exc-without-comments"));
3933}
3934static int
3935c14n11WithoutCommentTest(const char *filename,
3936 const char *resul ATTRIBUTE_UNUSED,
3937 const char *err ATTRIBUTE_UNUSED,
3938 int options ATTRIBUTE_UNUSED) {
3939 return(c14nCommonTest(filename, 0, XML_C14N_1_1, "1-1-without-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003940}
3941#endif
Nick Wellnhofer01a4b812017-06-16 21:27:47 +02003942#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
William M. Brackca15a542005-07-06 20:41:33 +00003943/************************************************************************
3944 * *
3945 * Catalog and threads test *
3946 * *
3947 ************************************************************************/
3948
3949/*
3950 * mostly a cut and paste from testThreads.c
3951 */
3952#define MAX_ARGC 20
3953
3954static const char *catalog = "test/threads/complex.xml";
3955static const char *testfiles[] = {
3956 "test/threads/abc.xml",
3957 "test/threads/acb.xml",
3958 "test/threads/bac.xml",
3959 "test/threads/bca.xml",
3960 "test/threads/cab.xml",
3961 "test/threads/cba.xml",
3962 "test/threads/invalid.xml",
3963};
3964
Daniel Veillard24505b02005-07-28 23:49:35 +00003965static const char *Okay = "OK";
3966static const char *Failed = "Failed";
William M. Brackca15a542005-07-06 20:41:33 +00003967
3968#ifndef xmlDoValidityCheckingDefaultValue
3969#error xmlDoValidityCheckingDefaultValue is not a macro
3970#endif
3971#ifndef xmlGenericErrorContext
3972#error xmlGenericErrorContext is not a macro
3973#endif
3974
3975static void *
3976thread_specific_data(void *private_data)
3977{
3978 xmlDocPtr myDoc;
3979 const char *filename = (const char *) private_data;
3980 int okay = 1;
3981
3982 if (!strcmp(filename, "test/threads/invalid.xml")) {
3983 xmlDoValidityCheckingDefaultValue = 0;
3984 xmlGenericErrorContext = stdout;
3985 } else {
3986 xmlDoValidityCheckingDefaultValue = 1;
3987 xmlGenericErrorContext = stderr;
3988 }
Nick Wellnhofer01a4b812017-06-16 21:27:47 +02003989#ifdef LIBXML_SAX1_ENABLED
William M. Brackca15a542005-07-06 20:41:33 +00003990 myDoc = xmlParseFile(filename);
Nick Wellnhofer01a4b812017-06-16 21:27:47 +02003991#else
3992 myDoc = xmlReadFile(filename, NULL, XML_WITH_CATALOG);
3993#endif
William M. Brackca15a542005-07-06 20:41:33 +00003994 if (myDoc) {
3995 xmlFreeDoc(myDoc);
3996 } else {
3997 printf("parse failed\n");
3998 okay = 0;
3999 }
4000 if (!strcmp(filename, "test/threads/invalid.xml")) {
4001 if (xmlDoValidityCheckingDefaultValue != 0) {
4002 printf("ValidityCheckingDefaultValue override failed\n");
4003 okay = 0;
4004 }
4005 if (xmlGenericErrorContext != stdout) {
4006 printf("xmlGenericErrorContext override failed\n");
4007 okay = 0;
4008 }
4009 } else {
4010 if (xmlDoValidityCheckingDefaultValue != 1) {
4011 printf("ValidityCheckingDefaultValue override failed\n");
4012 okay = 0;
4013 }
4014 if (xmlGenericErrorContext != stderr) {
4015 printf("xmlGenericErrorContext override failed\n");
4016 okay = 0;
4017 }
4018 }
4019 if (okay == 0)
4020 return ((void *) Failed);
4021 return ((void *) Okay);
4022}
4023
Nick Wellnhofere3890542017-10-09 00:20:01 +02004024#if defined(_WIN32) && !defined(__CYGWIN__)
William M. Brackca15a542005-07-06 20:41:33 +00004025#include <windows.h>
4026#include <string.h>
4027
4028#define TEST_REPEAT_COUNT 500
4029
4030static HANDLE tid[MAX_ARGC];
4031
4032static DWORD WINAPI
4033win32_thread_specific_data(void *private_data)
4034{
4035 return((DWORD) thread_specific_data(private_data));
4036}
4037
4038static int
4039testThread(void)
4040{
4041 unsigned int i, repeat;
4042 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
4043 DWORD results[MAX_ARGC];
4044 BOOL ret;
4045 int res = 0;
4046
4047 xmlInitParser();
4048 for (repeat = 0; repeat < TEST_REPEAT_COUNT; repeat++) {
4049 xmlLoadCatalog(catalog);
4050 nb_tests++;
4051
4052 for (i = 0; i < num_threads; i++) {
4053 results[i] = 0;
4054 tid[i] = (HANDLE) - 1;
4055 }
4056
4057 for (i = 0; i < num_threads; i++) {
4058 DWORD useless;
4059
4060 tid[i] = CreateThread(NULL, 0,
Daniel Veillardaa6de472008-08-25 14:53:31 +00004061 win32_thread_specific_data,
William M. Brackca15a542005-07-06 20:41:33 +00004062 (void *) testfiles[i], 0,
4063 &useless);
4064 if (tid[i] == NULL) {
4065 fprintf(stderr, "CreateThread failed\n");
4066 return(1);
4067 }
4068 }
4069
4070 if (WaitForMultipleObjects(num_threads, tid, TRUE, INFINITE) ==
4071 WAIT_FAILED) {
4072 fprintf(stderr, "WaitForMultipleObjects failed\n");
4073 return(1);
4074 }
4075
4076 for (i = 0; i < num_threads; i++) {
4077 ret = GetExitCodeThread(tid[i], &results[i]);
4078 if (ret == 0) {
4079 fprintf(stderr, "GetExitCodeThread failed\n");
4080 return(1);
4081 }
4082 CloseHandle(tid[i]);
4083 }
4084
4085 xmlCatalogCleanup();
4086 for (i = 0; i < num_threads; i++) {
4087 if (results[i] != (DWORD) Okay) {
4088 fprintf(stderr, "Thread %d handling %s failed\n",
4089 i, testfiles[i]);
4090 res = 1;
4091 }
4092 }
4093 }
4094
4095 return (res);
4096}
4097
4098#elif defined __BEOS__
4099#include <OS.h>
4100
4101static thread_id tid[MAX_ARGC];
4102
4103static int
4104testThread(void)
4105{
4106 unsigned int i, repeat;
4107 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
4108 void *results[MAX_ARGC];
4109 status_t ret;
4110 int res = 0;
4111
4112 xmlInitParser();
4113 for (repeat = 0; repeat < 500; repeat++) {
4114 xmlLoadCatalog(catalog);
4115 for (i = 0; i < num_threads; i++) {
4116 results[i] = NULL;
4117 tid[i] = (thread_id) - 1;
4118 }
4119 for (i = 0; i < num_threads; i++) {
4120 tid[i] =
4121 spawn_thread(thread_specific_data, "xmlTestThread",
4122 B_NORMAL_PRIORITY, (void *) testfiles[i]);
4123 if (tid[i] < B_OK) {
4124 fprintf(stderr, "beos_thread_create failed\n");
4125 return (1);
4126 }
4127 printf("beos_thread_create %d -> %d\n", i, tid[i]);
4128 }
4129 for (i = 0; i < num_threads; i++) {
4130 ret = wait_for_thread(tid[i], &results[i]);
4131 printf("beos_thread_wait %d -> %d\n", i, ret);
4132 if (ret != B_OK) {
4133 fprintf(stderr, "beos_thread_wait failed\n");
4134 return (1);
4135 }
4136 }
4137
4138 xmlCatalogCleanup();
4139 ret = B_OK;
4140 for (i = 0; i < num_threads; i++)
4141 if (results[i] != (void *) Okay) {
4142 printf("Thread %d handling %s failed\n", i, testfiles[i]);
4143 ret = B_ERROR;
4144 }
4145 }
4146 if (ret != B_OK)
4147 return(1);
4148 return (0);
4149}
Daniel Richard G495a73d2012-08-07 10:14:56 +08004150
4151#elif defined HAVE_PTHREAD_H
4152#include <pthread.h>
4153
4154static pthread_t tid[MAX_ARGC];
4155
4156static int
4157testThread(void)
4158{
4159 unsigned int i, repeat;
4160 unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
4161 void *results[MAX_ARGC];
4162 int ret;
4163 int res = 0;
4164
4165 xmlInitParser();
4166
4167 for (repeat = 0; repeat < 500; repeat++) {
4168 xmlLoadCatalog(catalog);
4169 nb_tests++;
4170
4171 for (i = 0; i < num_threads; i++) {
4172 results[i] = NULL;
4173 tid[i] = (pthread_t) - 1;
4174 }
4175
4176 for (i = 0; i < num_threads; i++) {
4177 ret = pthread_create(&tid[i], 0, thread_specific_data,
4178 (void *) testfiles[i]);
4179 if (ret != 0) {
4180 fprintf(stderr, "pthread_create failed\n");
4181 return (1);
4182 }
4183 }
4184 for (i = 0; i < num_threads; i++) {
4185 ret = pthread_join(tid[i], &results[i]);
4186 if (ret != 0) {
4187 fprintf(stderr, "pthread_join failed\n");
4188 return (1);
4189 }
4190 }
4191
4192 xmlCatalogCleanup();
4193 for (i = 0; i < num_threads; i++)
4194 if (results[i] != (void *) Okay) {
4195 fprintf(stderr, "Thread %d handling %s failed\n",
4196 i, testfiles[i]);
4197 res = 1;
4198 }
4199 }
4200 return (res);
4201}
4202
William M. Brackca15a542005-07-06 20:41:33 +00004203#else
4204static int
4205testThread(void)
4206{
4207 fprintf(stderr,
4208 "Specific platform thread support not detected\n");
4209 return (-1);
4210}
4211#endif
Daniel Veillardaa6de472008-08-25 14:53:31 +00004212static int
William M. Brackca15a542005-07-06 20:41:33 +00004213threadsTest(const char *filename ATTRIBUTE_UNUSED,
4214 const char *resul ATTRIBUTE_UNUSED,
4215 const char *err ATTRIBUTE_UNUSED,
4216 int options ATTRIBUTE_UNUSED) {
4217 return(testThread());
4218}
4219#endif
4220/************************************************************************
4221 * *
4222 * Tests Descriptions *
4223 * *
4224 ************************************************************************/
4225
4226static
4227testDesc testDescriptions[] = {
4228 { "XML regression tests" ,
4229 oldParseTest, "./test/*", "result/", "", NULL,
4230 0 },
4231 { "XML regression tests on memory" ,
4232 memParseTest, "./test/*", "result/", "", NULL,
4233 0 },
4234 { "XML entity subst regression tests" ,
4235 noentParseTest, "./test/*", "result/noent/", "", NULL,
4236 XML_PARSE_NOENT },
4237 { "XML Namespaces regression tests",
4238 errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err",
4239 0 },
4240 { "Error cases regression tests",
4241 errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err",
4242 0 },
Nick Wellnhofere2663052017-06-05 15:37:17 +02004243 { "Error cases regression tests (old 1.0)",
4244 errParseTest, "./test/errors10/*.xml", "result/errors10/", "", ".err",
4245 XML_PARSE_OLD10 },
William M. Brackca15a542005-07-06 20:41:33 +00004246#ifdef LIBXML_READER_ENABLED
4247 { "Error cases stream regression tests",
4248 streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str",
4249 0 },
4250 { "Reader regression tests",
4251 streamParseTest, "./test/*", "result/", ".rdr", NULL,
4252 0 },
4253 { "Reader entities substitution regression tests",
4254 streamParseTest, "./test/*", "result/", ".rde", NULL,
4255 XML_PARSE_NOENT },
4256 { "Reader on memory regression tests",
4257 streamMemParseTest, "./test/*", "result/", ".rdr", NULL,
4258 0 },
4259 { "Walker regression tests",
4260 walkerParseTest, "./test/*", "result/", ".rdr", NULL,
4261 0 },
4262#endif
4263#ifdef LIBXML_SAX1_ENABLED
4264 { "SAX1 callbacks regression tests" ,
4265 saxParseTest, "./test/*", "result/", ".sax", NULL,
4266 XML_PARSE_SAX1 },
Nick Wellnhoferdbaab1f2017-06-16 21:38:57 +02004267#endif
William M. Brackca15a542005-07-06 20:41:33 +00004268 { "SAX2 callbacks regression tests" ,
4269 saxParseTest, "./test/*", "result/", ".sax2", NULL,
4270 0 },
Nick Wellnhoferdbaab1f2017-06-16 21:38:57 +02004271 { "SAX2 callbacks regression tests with entity substitution" ,
4272 saxParseTest, "./test/*", "result/noent/", ".sax2", NULL,
4273 XML_PARSE_NOENT },
William M. Brackca15a542005-07-06 20:41:33 +00004274#ifdef LIBXML_PUSH_ENABLED
4275 { "XML push regression tests" ,
4276 pushParseTest, "./test/*", "result/", "", NULL,
4277 0 },
4278#endif
4279#ifdef LIBXML_HTML_ENABLED
4280 { "HTML regression tests" ,
4281 errParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4282 XML_PARSE_HTML },
4283#ifdef LIBXML_PUSH_ENABLED
4284 { "Push HTML regression tests" ,
4285 pushParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4286 XML_PARSE_HTML },
4287#endif
William M. Brackca15a542005-07-06 20:41:33 +00004288 { "HTML SAX regression tests" ,
4289 saxParseTest, "./test/HTML/*", "result/HTML/", ".sax", NULL,
4290 XML_PARSE_HTML },
4291#endif
William M. Brackca15a542005-07-06 20:41:33 +00004292#ifdef LIBXML_VALID_ENABLED
4293 { "Valid documents regression tests" ,
4294 errParseTest, "./test/VCM/*", NULL, NULL, NULL,
4295 XML_PARSE_DTDVALID },
4296 { "Validity checking regression tests" ,
4297 errParseTest, "./test/VC/*", "result/VC/", NULL, "",
4298 XML_PARSE_DTDVALID },
Daniel Veillarda7982ce2012-10-25 15:39:39 +08004299#ifdef LIBXML_READER_ENABLED
4300 { "Streaming validity checking regression tests" ,
4301 streamParseTest, "./test/valid/*.xml", "result/valid/", NULL, ".err.rdr",
4302 XML_PARSE_DTDVALID },
4303 { "Streaming validity error checking regression tests" ,
4304 streamParseTest, "./test/VC/*", "result/VC/", NULL, ".rdr",
4305 XML_PARSE_DTDVALID },
4306#endif
William M. Brackca15a542005-07-06 20:41:33 +00004307 { "General documents valid regression tests" ,
4308 errParseTest, "./test/valid/*", "result/valid/", "", ".err",
4309 XML_PARSE_DTDVALID },
4310#endif
4311#ifdef LIBXML_XINCLUDE_ENABLED
4312 { "XInclude regression tests" ,
4313 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4314 /* Ignore errors at this point ".err", */
4315 XML_PARSE_XINCLUDE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004316#ifdef LIBXML_READER_ENABLED
William M. Brackca15a542005-07-06 20:41:33 +00004317 { "XInclude xmlReader regression tests",
4318 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4319 /* Ignore errors at this point ".err", */
4320 NULL, XML_PARSE_XINCLUDE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004321#endif
William M. Brackca15a542005-07-06 20:41:33 +00004322 { "XInclude regression tests stripping include nodes" ,
4323 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4324 /* Ignore errors at this point ".err", */
4325 XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004326#ifdef LIBXML_READER_ENABLED
William M. Brackca15a542005-07-06 20:41:33 +00004327 { "XInclude xmlReader regression tests stripping include nodes",
4328 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4329 /* Ignore errors at this point ".err", */
4330 NULL, XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
4331#endif
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004332#endif
William M. Brackca15a542005-07-06 20:41:33 +00004333#ifdef LIBXML_XPATH_ENABLED
4334#ifdef LIBXML_DEBUG_ENABLED
4335 { "XPath expressions regression tests" ,
4336 xpathExprTest, "./test/XPath/expr/*", "result/XPath/expr/", "", NULL,
4337 0 },
4338 { "XPath document queries regression tests" ,
4339 xpathDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4340 0 },
4341#ifdef LIBXML_XPTR_ENABLED
4342 { "XPointer document queries regression tests" ,
4343 xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4344 0 },
4345#endif
4346 { "xml:id regression tests" ,
4347 xmlidDocTest, "./test/xmlid/*", "result/xmlid/", "", ".err",
4348 0 },
4349#endif
4350#endif
4351 { "URI parsing tests" ,
4352 uriParseTest, "./test/URI/*.uri", "result/URI/", "", NULL,
4353 0 },
4354 { "URI base composition tests" ,
4355 uriBaseTest, "./test/URI/*.data", "result/URI/", "", NULL,
4356 0 },
Daniel Veillard336a8e12005-08-07 10:46:19 +00004357 { "Path URI conversion tests" ,
4358 uriPathTest, NULL, NULL, NULL, NULL,
4359 0 },
William M. Brackca15a542005-07-06 20:41:33 +00004360#ifdef LIBXML_SCHEMAS_ENABLED
4361 { "Schemas regression tests" ,
4362 schemasTest, "./test/schemas/*_*.xsd", NULL, NULL, NULL,
4363 0 },
4364 { "Relax-NG regression tests" ,
4365 rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4366 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4367#ifdef LIBXML_READER_ENABLED
4368 { "Relax-NG streaming regression tests" ,
4369 rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4370 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4371#endif
4372#endif
4373#ifdef LIBXML_PATTERN_ENABLED
4374#ifdef LIBXML_READER_ENABLED
4375 { "Pattern regression tests" ,
4376 patternTest, "./test/pattern/*.pat", "result/pattern/", NULL, NULL,
4377 0 },
4378#endif
4379#endif
4380#ifdef LIBXML_C14N_ENABLED
4381 { "C14N with comments regression tests" ,
4382 c14nWithCommentTest, "./test/c14n/with-comments/*.xml", NULL, NULL, NULL,
4383 0 },
4384 { "C14N without comments regression tests" ,
4385 c14nWithoutCommentTest, "./test/c14n/without-comments/*.xml", NULL, NULL, NULL,
4386 0 },
4387 { "C14N exclusive without comments regression tests" ,
4388 c14nExcWithoutCommentTest, "./test/c14n/exc-without-comments/*.xml", NULL, NULL, NULL,
4389 0 },
Aleksey Sanin83868242009-07-09 10:26:22 +02004390 { "C14N 1.1 without comments regression tests" ,
4391 c14n11WithoutCommentTest, "./test/c14n/1-1-without-comments/*.xml", NULL, NULL, NULL,
4392 0 },
William M. Brackca15a542005-07-06 20:41:33 +00004393#endif
Nick Wellnhofer01a4b812017-06-16 21:27:47 +02004394#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
William M. Brackca15a542005-07-06 20:41:33 +00004395 { "Catalog and Threads regression tests" ,
4396 threadsTest, NULL, NULL, NULL, NULL,
4397 0 },
4398#endif
4399 {NULL, NULL, NULL, NULL, NULL, NULL, 0}
4400};
4401
4402/************************************************************************
4403 * *
4404 * The main code driving the tests *
4405 * *
4406 ************************************************************************/
4407
4408static int
4409launchTests(testDescPtr tst) {
4410 int res = 0, err = 0;
4411 size_t i;
4412 char *result;
4413 char *error;
4414 int mem;
4415
4416 if (tst == NULL) return(-1);
4417 if (tst->in != NULL) {
4418 glob_t globbuf;
4419
4420 globbuf.gl_offs = 0;
4421 glob(tst->in, GLOB_DOOFFS, NULL, &globbuf);
4422 for (i = 0;i < globbuf.gl_pathc;i++) {
4423 if (!checkTestFile(globbuf.gl_pathv[i]))
4424 continue;
4425 if (tst->suffix != NULL) {
4426 result = resultFilename(globbuf.gl_pathv[i], tst->out,
4427 tst->suffix);
4428 if (result == NULL) {
4429 fprintf(stderr, "Out of memory !\n");
4430 fatalError();
4431 }
4432 } else {
4433 result = NULL;
4434 }
4435 if (tst->err != NULL) {
4436 error = resultFilename(globbuf.gl_pathv[i], tst->out,
4437 tst->err);
4438 if (error == NULL) {
4439 fprintf(stderr, "Out of memory !\n");
4440 fatalError();
4441 }
4442 } else {
4443 error = NULL;
4444 }
David Kilzer5c373822016-05-22 09:58:30 +08004445 if ((result) &&(!checkTestFile(result)) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00004446 fprintf(stderr, "Missing result file %s\n", result);
David Kilzer5c373822016-05-22 09:58:30 +08004447 } else if ((error) &&(!checkTestFile(error)) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00004448 fprintf(stderr, "Missing error file %s\n", error);
4449 } else {
4450 mem = xmlMemUsed();
4451 extraMemoryFromResolver = 0;
4452 testErrorsSize = 0;
4453 testErrors[0] = 0;
4454 res = tst->func(globbuf.gl_pathv[i], result, error,
Daniel Veillard8874b942005-08-25 13:19:21 +00004455 tst->options | XML_PARSE_COMPACT);
William M. Brackca15a542005-07-06 20:41:33 +00004456 xmlResetLastError();
4457 if (res != 0) {
4458 fprintf(stderr, "File %s generated an error\n",
4459 globbuf.gl_pathv[i]);
4460 nb_errors++;
4461 err++;
4462 }
4463 else if (xmlMemUsed() != mem) {
4464 if ((xmlMemUsed() != mem) &&
4465 (extraMemoryFromResolver == 0)) {
4466 fprintf(stderr, "File %s leaked %d bytes\n",
4467 globbuf.gl_pathv[i], xmlMemUsed() - mem);
4468 nb_leaks++;
4469 err++;
4470 }
4471 }
4472 testErrorsSize = 0;
4473 }
4474 if (result)
4475 free(result);
4476 if (error)
4477 free(error);
4478 }
4479 globfree(&globbuf);
4480 } else {
4481 testErrorsSize = 0;
4482 testErrors[0] = 0;
4483 extraMemoryFromResolver = 0;
4484 res = tst->func(NULL, NULL, NULL, tst->options);
4485 if (res != 0) {
4486 nb_errors++;
4487 err++;
4488 }
4489 }
4490 return(err);
4491}
4492
Daniel Veillarddb68b742005-07-30 13:18:24 +00004493static int verbose = 0;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004494static int tests_quiet = 0;
Daniel Veillarddb68b742005-07-30 13:18:24 +00004495
4496static int
4497runtest(int i) {
4498 int ret = 0, res;
4499 int old_errors, old_tests, old_leaks;
4500
4501 old_errors = nb_errors;
4502 old_tests = nb_tests;
4503 old_leaks = nb_leaks;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004504 if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
Daniel Veillarddb68b742005-07-30 13:18:24 +00004505 printf("## %s\n", testDescriptions[i].desc);
4506 res = launchTests(&testDescriptions[i]);
4507 if (res != 0)
4508 ret++;
4509 if (verbose) {
4510 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
4511 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
4512 else
4513 printf("Ran %d tests, %d errors, %d leaks\n",
4514 nb_tests - old_tests,
4515 nb_errors - old_errors,
4516 nb_leaks - old_leaks);
4517 }
4518 return(ret);
4519}
4520
William M. Brackca15a542005-07-06 20:41:33 +00004521int
4522main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
Daniel Veillarddb68b742005-07-30 13:18:24 +00004523 int i, a, ret = 0;
4524 int subset = 0;
William M. Brackca15a542005-07-06 20:41:33 +00004525
Nick Wellnhofer82e03942017-10-09 02:05:41 +02004526#if defined(_WIN32) && !defined(__CYGWIN__)
4527 setvbuf(stdout, NULL, _IONBF, 0);
4528 setvbuf(stderr, NULL, _IONBF, 0);
4529#endif
4530
William M. Brackca15a542005-07-06 20:41:33 +00004531 initializeLibxml2();
4532
Daniel Veillarddb68b742005-07-30 13:18:24 +00004533 for (a = 1; a < argc;a++) {
4534 if (!strcmp(argv[a], "-v"))
4535 verbose = 1;
David Kilzer5c373822016-05-22 09:58:30 +08004536 else if (!strcmp(argv[a], "-u"))
4537 update_results = 1;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004538 else if (!strcmp(argv[a], "-quiet"))
4539 tests_quiet = 1;
Daniel Veillarddb68b742005-07-30 13:18:24 +00004540 else {
4541 for (i = 0; testDescriptions[i].func != NULL; i++) {
4542 if (strstr(testDescriptions[i].desc, argv[a])) {
4543 ret += runtest(i);
4544 subset++;
4545 }
4546 }
4547 }
4548 }
4549 if (subset == 0) {
4550 for (i = 0; testDescriptions[i].func != NULL; i++) {
4551 ret += runtest(i);
William M. Brackca15a542005-07-06 20:41:33 +00004552 }
4553 }
4554 if ((nb_errors == 0) && (nb_leaks == 0)) {
4555 ret = 0;
4556 printf("Total %d tests, no errors\n",
4557 nb_tests);
4558 } else {
4559 ret = 1;
4560 printf("Total %d tests, %d errors, %d leaks\n",
4561 nb_tests, nb_errors, nb_leaks);
4562 }
4563 xmlCleanupParser();
4564 xmlMemoryDump();
4565
4566 return(ret);
4567}
4568
4569#else /* ! LIBXML_OUTPUT_ENABLED */
4570int
4571main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
4572 fprintf(stderr, "runtest requires output to be enabled in libxml2\n");
4573 return(1);
4574}
4575#endif