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