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