blob: 605c1d1adf825b3e40ad64f4b8eb2a5949d92758 [file] [log] [blame]
William M. Brackca15a542005-07-06 20:41:33 +00001/*
2 * runtest.c: C program to run libxml2 regression tests without
3 * requiring make or Python, and reducing platform dependancies
4 * to a strict minimum.
5 *
6 * To compile on Unixes:
7 * cc -o runtest `xml2-config --cflags` runtest.c `xml2-config --libs` -lpthread
8 *
9 * See Copyright for the status of this software.
10 *
11 * daniel@veillard.com
12 */
13
Daniel Veillardf93a67e2005-10-28 16:37:05 +000014#include "libxml.h"
Daniel Veillardf93a67e2005-10-28 16:37:05 +000015#include <stdio.h>
Daniel Veillardf93a67e2005-10-28 16:37:05 +000016
William M. Brackca15a542005-07-06 20:41:33 +000017#if !defined(_WIN32) || defined(__CYGWIN__)
18#include <unistd.h>
19#endif
20#include <string.h>
William M. Brackca15a542005-07-06 20:41:33 +000021#include <sys/types.h>
22#include <sys/stat.h>
23#include <fcntl.h>
24
25#include <libxml/parser.h>
Nick Wellnhoferdbaab1f2017-06-16 21:38:57 +020026#include <libxml/parserInternals.h>
William M. Brackca15a542005-07-06 20:41:33 +000027#include <libxml/tree.h>
28#include <libxml/uri.h>
Nick Wellnhofer4b413592017-10-31 17:17:16 +010029#include <libxml/encoding.h>
William M. Brackca15a542005-07-06 20:41:33 +000030
31#ifdef LIBXML_OUTPUT_ENABLED
32#ifdef LIBXML_READER_ENABLED
33#include <libxml/xmlreader.h>
34#endif
35
36#ifdef LIBXML_XINCLUDE_ENABLED
37#include <libxml/xinclude.h>
38#endif
39
40#ifdef LIBXML_XPATH_ENABLED
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#ifdef LIBXML_XPTR_ENABLED
44#include <libxml/xpointer.h>
45#endif
46#endif
47
48#ifdef LIBXML_SCHEMAS_ENABLED
49#include <libxml/relaxng.h>
50#include <libxml/xmlschemas.h>
51#include <libxml/xmlschemastypes.h>
52#endif
53
54#ifdef LIBXML_PATTERN_ENABLED
55#include <libxml/pattern.h>
56#endif
57
58#ifdef LIBXML_C14N_ENABLED
59#include <libxml/c14n.h>
60#endif
61
62#ifdef LIBXML_HTML_ENABLED
63#include <libxml/HTMLparser.h>
64#include <libxml/HTMLtree.h>
65
66/*
67 * pseudo flag for the unification of HTML and XML tests
68 */
69#define XML_PARSE_HTML 1 << 24
70#endif
71
72#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
73#include <libxml/globals.h>
74#include <libxml/threads.h>
75#include <libxml/parser.h>
76#include <libxml/catalog.h>
77#include <string.h>
78#endif
79
80/*
81 * O_BINARY is just for Windows compatibility - if it isn't defined
82 * on this system, avoid any compilation error
83 */
84#ifdef O_BINARY
85#define RD_FLAGS O_RDONLY | O_BINARY
David Kilzer5c373822016-05-22 09:58:30 +080086#define WR_FLAGS O_WRONLY | O_CREAT | O_TRUNC | O_BINARY
William M. Brackca15a542005-07-06 20:41:33 +000087#else
David Kilzer5c373822016-05-22 09:58:30 +080088#define RD_FLAGS O_RDONLY
89#define WR_FLAGS O_WRONLY | O_CREAT | O_TRUNC
William M. Brackca15a542005-07-06 20:41:33 +000090#endif
91
92typedef int (*functest) (const char *filename, const char *result,
93 const char *error, int options);
94
95typedef struct testDesc testDesc;
96typedef testDesc *testDescPtr;
97struct testDesc {
98 const char *desc; /* descripton of the test */
99 functest func; /* function implementing the test */
100 const char *in; /* glob to path for input files */
101 const char *out; /* output directory */
102 const char *suffix;/* suffix for output files */
103 const char *err; /* suffix for error output files */
104 int options; /* parser options for the test */
105};
106
David Kilzer5c373822016-05-22 09:58:30 +0800107static int update_results = 0;
William M. Brackca15a542005-07-06 20:41:33 +0000108static int checkTestFile(const char *filename);
109
110#if defined(_WIN32) && !defined(__CYGWIN__)
111
112#include <windows.h>
113#include <io.h>
114
115typedef struct
116{
117 size_t gl_pathc; /* Count of paths matched so far */
118 char **gl_pathv; /* List of matched pathnames. */
119 size_t gl_offs; /* Slots to reserve in 'gl_pathv'. */
120} glob_t;
121
122#define GLOB_DOOFFS 0
Nick Wellnhofer82e03942017-10-09 02:05:41 +0200123static int glob(const char *pattern, ATTRIBUTE_UNUSED int flags,
124 ATTRIBUTE_UNUSED int errfunc(const char *epath, int eerrno),
William M. Brackca15a542005-07-06 20:41:33 +0000125 glob_t *pglob) {
126 glob_t *ret;
127 WIN32_FIND_DATA FindFileData;
128 HANDLE hFind;
129 unsigned int nb_paths = 0;
130 char directory[500];
131 int len;
132
133 if ((pattern == NULL) || (pglob == NULL)) return(-1);
Daniel Veillardaa6de472008-08-25 14:53:31 +0000134
William M. Brackca15a542005-07-06 20:41:33 +0000135 strncpy(directory, pattern, 499);
136 for (len = strlen(directory);len >= 0;len--) {
137 if (directory[len] == '/') {
138 len++;
139 directory[len] = 0;
140 break;
141 }
142 }
143 if (len <= 0)
144 len = 0;
145
Daniel Veillardaa6de472008-08-25 14:53:31 +0000146
William M. Brackca15a542005-07-06 20:41:33 +0000147 ret = pglob;
148 memset(ret, 0, sizeof(glob_t));
Daniel Veillardaa6de472008-08-25 14:53:31 +0000149
William M. Brackca15a542005-07-06 20:41:33 +0000150 hFind = FindFirstFileA(pattern, &FindFileData);
Daniel Veillardaa6de472008-08-25 14:53:31 +0000151 if (hFind == INVALID_HANDLE_VALUE)
William M. Brackca15a542005-07-06 20:41:33 +0000152 return(0);
153 nb_paths = 20;
154 ret->gl_pathv = (char **) malloc(nb_paths * sizeof(char *));
155 if (ret->gl_pathv == NULL) {
156 FindClose(hFind);
157 return(-1);
158 }
159 strncpy(directory + len, FindFileData.cFileName, 499 - len);
160 ret->gl_pathv[ret->gl_pathc] = strdup(directory);
161 if (ret->gl_pathv[ret->gl_pathc] == NULL)
162 goto done;
163 ret->gl_pathc++;
164 while(FindNextFileA(hFind, &FindFileData)) {
165 if (FindFileData.cFileName[0] == '.')
166 continue;
167 if (ret->gl_pathc + 2 > nb_paths) {
168 char **tmp = realloc(ret->gl_pathv, nb_paths * 2 * sizeof(char *));
169 if (tmp == NULL)
170 break;
171 ret->gl_pathv = tmp;
172 nb_paths *= 2;
173 }
174 strncpy(directory + len, FindFileData.cFileName, 499 - len);
175 ret->gl_pathv[ret->gl_pathc] = strdup(directory);
176 if (ret->gl_pathv[ret->gl_pathc] == NULL)
177 break;
178 ret->gl_pathc++;
179 }
180 ret->gl_pathv[ret->gl_pathc] = NULL;
181
182done:
183 FindClose(hFind);
184 return(0);
185}
Daniel Veillardaa6de472008-08-25 14:53:31 +0000186
William M. Brackca15a542005-07-06 20:41:33 +0000187
188
189static void globfree(glob_t *pglob) {
190 unsigned int i;
191 if (pglob == NULL)
192 return;
Daniel Veillardaa6de472008-08-25 14:53:31 +0000193
William M. Brackca15a542005-07-06 20:41:33 +0000194 for (i = 0;i < pglob->gl_pathc;i++) {
195 if (pglob->gl_pathv[i] != NULL)
196 free(pglob->gl_pathv[i]);
197 }
198}
Daniel Veillard22030ef2012-05-23 15:52:45 +0800199
William M. Brackca15a542005-07-06 20:41:33 +0000200#else
201#include <glob.h>
202#endif
203
204/************************************************************************
205 * *
206 * Libxml2 specific routines *
207 * *
208 ************************************************************************/
209
210static int nb_tests = 0;
211static int nb_errors = 0;
212static int nb_leaks = 0;
William M. Brackca15a542005-07-06 20:41:33 +0000213static int extraMemoryFromResolver = 0;
214
215static int
216fatalError(void) {
217 fprintf(stderr, "Exitting tests on fatal error\n");
218 exit(1);
219}
220
221/*
222 * We need to trap calls to the resolver to not account memory for the catalog
223 * which is shared to the current running test. We also don't want to have
224 * network downloads modifying tests.
225 */
Daniel Veillardaa6de472008-08-25 14:53:31 +0000226static xmlParserInputPtr
William M. Brackca15a542005-07-06 20:41:33 +0000227testExternalEntityLoader(const char *URL, const char *ID,
228 xmlParserCtxtPtr ctxt) {
229 xmlParserInputPtr ret;
230
231 if (checkTestFile(URL)) {
232 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
233 } else {
234 int memused = xmlMemUsed();
235 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
236 extraMemoryFromResolver += xmlMemUsed() - memused;
237 }
Daniel Veillardaa6de472008-08-25 14:53:31 +0000238
William M. Brackca15a542005-07-06 20:41:33 +0000239 return(ret);
240}
241
242/*
243 * Trapping the error messages at the generic level to grab the equivalent of
244 * stderr messages on CLI tools.
245 */
246static char testErrors[32769];
247static int testErrorsSize = 0;
248
Daniel Veillardffa3c742005-07-21 13:24:09 +0000249static void XMLCDECL
William M. Brackca15a542005-07-06 20:41:33 +0000250testErrorHandler(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
251 va_list args;
252 int res;
253
254 if (testErrorsSize >= 32768)
255 return;
256 va_start(args, msg);
257 res = vsnprintf(&testErrors[testErrorsSize],
258 32768 - testErrorsSize,
259 msg, args);
260 va_end(args);
261 if (testErrorsSize + res >= 32768) {
262 /* buffer is full */
263 testErrorsSize = 32768;
264 testErrors[testErrorsSize] = 0;
265 } else {
266 testErrorsSize += res;
267 }
268 testErrors[testErrorsSize] = 0;
269}
270
Daniel Veillardffa3c742005-07-21 13:24:09 +0000271static void XMLCDECL
William M. Brackca15a542005-07-06 20:41:33 +0000272channel(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
273 va_list args;
274 int res;
275
276 if (testErrorsSize >= 32768)
277 return;
278 va_start(args, msg);
279 res = vsnprintf(&testErrors[testErrorsSize],
280 32768 - testErrorsSize,
281 msg, args);
282 va_end(args);
283 if (testErrorsSize + res >= 32768) {
284 /* buffer is full */
285 testErrorsSize = 32768;
286 testErrors[testErrorsSize] = 0;
287 } else {
288 testErrorsSize += res;
289 }
290 testErrors[testErrorsSize] = 0;
291}
292
293/**
294 * xmlParserPrintFileContext:
295 * @input: an xmlParserInputPtr input
Daniel Veillardaa6de472008-08-25 14:53:31 +0000296 *
William M. Brackca15a542005-07-06 20:41:33 +0000297 * Displays current context within the input content for error tracking
298 */
299
300static void
Daniel Veillardaa6de472008-08-25 14:53:31 +0000301xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
William M. Brackca15a542005-07-06 20:41:33 +0000302 xmlGenericErrorFunc chanl, void *data ) {
303 const xmlChar *cur, *base;
304 unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */
305 xmlChar content[81]; /* space for 80 chars + line terminator */
306 xmlChar *ctnt;
307
308 if (input == NULL) return;
309 cur = input->cur;
310 base = input->base;
311 /* skip backwards over any end-of-lines */
312 while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
313 cur--;
314 }
315 n = 0;
316 /* search backwards for beginning-of-line (to max buff size) */
Daniel Veillardaa6de472008-08-25 14:53:31 +0000317 while ((n++ < (sizeof(content)-1)) && (cur > base) &&
318 (*(cur) != '\n') && (*(cur) != '\r'))
William M. Brackca15a542005-07-06 20:41:33 +0000319 cur--;
320 if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
321 /* calculate the error position in terms of the current position */
322 col = input->cur - cur;
323 /* search forward for end-of-line (to max buff size) */
324 n = 0;
325 ctnt = content;
326 /* copy selected text to our buffer */
Daniel Veillardaa6de472008-08-25 14:53:31 +0000327 while ((*cur != 0) && (*(cur) != '\n') &&
328 (*(cur) != '\r') && (n < sizeof(content)-1)) {
William M. Brackca15a542005-07-06 20:41:33 +0000329 *ctnt++ = *cur++;
330 n++;
331 }
332 *ctnt = 0;
333 /* print out the selected text */
334 chanl(data ,"%s\n", content);
335 /* create blank line with problem pointer */
336 n = 0;
337 ctnt = content;
338 /* (leave buffer space for pointer + line terminator) */
339 while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
340 if (*(ctnt) != '\t')
341 *(ctnt) = ' ';
342 ctnt++;
343 }
344 *ctnt++ = '^';
345 *ctnt = 0;
346 chanl(data ,"%s\n", content);
347}
348
349static void
350testStructuredErrorHandler(void *ctx ATTRIBUTE_UNUSED, xmlErrorPtr err) {
351 char *file = NULL;
352 int line = 0;
353 int code = -1;
354 int domain;
355 void *data = NULL;
356 const char *str;
357 const xmlChar *name = NULL;
358 xmlNodePtr node;
359 xmlErrorLevel level;
360 xmlParserInputPtr input = NULL;
361 xmlParserInputPtr cur = NULL;
362 xmlParserCtxtPtr ctxt = NULL;
363
364 if (err == NULL)
365 return;
366
367 file = err->file;
368 line = err->line;
369 code = err->code;
370 domain = err->domain;
371 level = err->level;
372 node = err->node;
373 if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
374 (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
375 (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
376 ctxt = err->ctxt;
377 }
378 str = err->message;
379
380 if (code == XML_ERR_OK)
381 return;
382
383 if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
384 name = node->name;
385
386 /*
387 * Maintain the compatibility with the legacy error handling
388 */
389 if (ctxt != NULL) {
390 input = ctxt->input;
391 if ((input != NULL) && (input->filename == NULL) &&
392 (ctxt->inputNr > 1)) {
393 cur = input;
394 input = ctxt->inputTab[ctxt->inputNr - 2];
395 }
396 if (input != NULL) {
397 if (input->filename)
398 channel(data, "%s:%d: ", input->filename, input->line);
399 else if ((line != 0) && (domain == XML_FROM_PARSER))
400 channel(data, "Entity: line %d: ", input->line);
401 }
402 } else {
403 if (file != NULL)
404 channel(data, "%s:%d: ", file, line);
405 else if ((line != 0) && (domain == XML_FROM_PARSER))
406 channel(data, "Entity: line %d: ", line);
407 }
408 if (name != NULL) {
409 channel(data, "element %s: ", name);
410 }
411 if (code == XML_ERR_OK)
412 return;
413 switch (domain) {
414 case XML_FROM_PARSER:
415 channel(data, "parser ");
416 break;
417 case XML_FROM_NAMESPACE:
418 channel(data, "namespace ");
419 break;
420 case XML_FROM_DTD:
421 case XML_FROM_VALID:
422 channel(data, "validity ");
423 break;
424 case XML_FROM_HTML:
425 channel(data, "HTML parser ");
426 break;
427 case XML_FROM_MEMORY:
428 channel(data, "memory ");
429 break;
430 case XML_FROM_OUTPUT:
431 channel(data, "output ");
432 break;
433 case XML_FROM_IO:
434 channel(data, "I/O ");
435 break;
436 case XML_FROM_XINCLUDE:
437 channel(data, "XInclude ");
438 break;
439 case XML_FROM_XPATH:
440 channel(data, "XPath ");
441 break;
442 case XML_FROM_XPOINTER:
443 channel(data, "parser ");
444 break;
445 case XML_FROM_REGEXP:
446 channel(data, "regexp ");
447 break;
448 case XML_FROM_MODULE:
449 channel(data, "module ");
450 break;
451 case XML_FROM_SCHEMASV:
452 channel(data, "Schemas validity ");
453 break;
454 case XML_FROM_SCHEMASP:
455 channel(data, "Schemas parser ");
456 break;
457 case XML_FROM_RELAXNGP:
458 channel(data, "Relax-NG parser ");
459 break;
460 case XML_FROM_RELAXNGV:
461 channel(data, "Relax-NG validity ");
462 break;
463 case XML_FROM_CATALOG:
464 channel(data, "Catalog ");
465 break;
466 case XML_FROM_C14N:
467 channel(data, "C14N ");
468 break;
469 case XML_FROM_XSLT:
470 channel(data, "XSLT ");
471 break;
472 default:
473 break;
474 }
475 if (code == XML_ERR_OK)
476 return;
477 switch (level) {
478 case XML_ERR_NONE:
479 channel(data, ": ");
480 break;
481 case XML_ERR_WARNING:
482 channel(data, "warning : ");
483 break;
484 case XML_ERR_ERROR:
485 channel(data, "error : ");
486 break;
487 case XML_ERR_FATAL:
488 channel(data, "error : ");
489 break;
490 }
491 if (code == XML_ERR_OK)
492 return;
493 if (str != NULL) {
494 int len;
495 len = xmlStrlen((const xmlChar *)str);
496 if ((len > 0) && (str[len - 1] != '\n'))
497 channel(data, "%s\n", str);
498 else
499 channel(data, "%s", str);
500 } else {
501 channel(data, "%s\n", "out of memory error");
502 }
503 if (code == XML_ERR_OK)
504 return;
505
506 if (ctxt != NULL) {
507 xmlParserPrintFileContextInternal(input, channel, data);
508 if (cur != NULL) {
509 if (cur->filename)
510 channel(data, "%s:%d: \n", cur->filename, cur->line);
511 else if ((line != 0) && (domain == XML_FROM_PARSER))
512 channel(data, "Entity: line %d: \n", cur->line);
513 xmlParserPrintFileContextInternal(cur, channel, data);
514 }
515 }
516 if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
517 (err->int1 < 100) &&
518 (err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
519 xmlChar buf[150];
520 int i;
521
522 channel(data, "%s\n", err->str1);
523 for (i=0;i < err->int1;i++)
524 buf[i] = ' ';
525 buf[i++] = '^';
526 buf[i] = 0;
527 channel(data, "%s\n", buf);
528 }
529}
530
531static void
532initializeLibxml2(void) {
533 xmlGetWarningsDefaultValue = 0;
534 xmlPedanticParserDefault(0);
535
536 xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
537 xmlInitParser();
538 xmlSetExternalEntityLoader(testExternalEntityLoader);
539 xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
540#ifdef LIBXML_SCHEMAS_ENABLED
541 xmlSchemaInitTypes();
542 xmlRelaxNGInitTypes();
543#endif
William M. Brackca15a542005-07-06 20:41:33 +0000544}
545
546
547/************************************************************************
548 * *
549 * File name and path utilities *
550 * *
551 ************************************************************************/
552
553static const char *baseFilename(const char *filename) {
554 const char *cur;
555 if (filename == NULL)
556 return(NULL);
557 cur = &filename[strlen(filename)];
558 while ((cur > filename) && (*cur != '/'))
559 cur--;
560 if (*cur == '/')
561 return(cur + 1);
562 return(cur);
563}
564
565static char *resultFilename(const char *filename, const char *out,
566 const char *suffix) {
567 const char *base;
568 char res[500];
Daniel Veillard381ff362006-06-18 17:31:31 +0000569 char suffixbuff[500];
William M. Brackca15a542005-07-06 20:41:33 +0000570
571/*************
572 if ((filename[0] == 't') && (filename[1] == 'e') &&
573 (filename[2] == 's') && (filename[3] == 't') &&
574 (filename[4] == '/'))
575 filename = &filename[5];
576 *************/
Daniel Veillardaa6de472008-08-25 14:53:31 +0000577
William M. Brackca15a542005-07-06 20:41:33 +0000578 base = baseFilename(filename);
579 if (suffix == NULL)
580 suffix = ".tmp";
581 if (out == NULL)
582 out = "";
Daniel Veillard381ff362006-06-18 17:31:31 +0000583
584 strncpy(suffixbuff,suffix,499);
585#ifdef VMS
586 if(strstr(base,".") && suffixbuff[0]=='.')
587 suffixbuff[0]='_';
588#endif
589
590 snprintf(res, 499, "%s%s%s", out, base, suffixbuff);
William M. Brackca15a542005-07-06 20:41:33 +0000591 res[499] = 0;
592 return(strdup(res));
593}
594
595static int checkTestFile(const char *filename) {
596 struct stat buf;
597
598 if (stat(filename, &buf) == -1)
599 return(0);
600
601#if defined(_WIN32) && !defined(__CYGWIN__)
602 if (!(buf.st_mode & _S_IFREG))
603 return(0);
604#else
605 if (!S_ISREG(buf.st_mode))
606 return(0);
607#endif
608
609 return(1);
610}
611
David Kilzer5c373822016-05-22 09:58:30 +0800612static int compareFiles(const char *r1 /* temp */, const char *r2 /* result */) {
William M. Brackca15a542005-07-06 20:41:33 +0000613 int res1, res2;
614 int fd1, fd2;
615 char bytes1[4096];
616 char bytes2[4096];
617
David Kilzer5c373822016-05-22 09:58:30 +0800618 if (update_results) {
619 fd1 = open(r1, RD_FLAGS);
620 if (fd1 < 0)
621 return(-1);
622 fd2 = open(r2, WR_FLAGS, 0644);
623 if (fd2 < 0) {
624 close(fd1);
625 return(-1);
626 }
627 do {
628 res1 = read(fd1, bytes1, 4096);
629 if (res1 <= 0)
630 break;
631 res2 = write(fd2, bytes1, res1);
632 if (res2 <= 0 || res2 != res1)
633 break;
634 } while (1);
635 close(fd2);
636 close(fd1);
637 return(res1 != 0);
638 }
639
William M. Brackca15a542005-07-06 20:41:33 +0000640 fd1 = open(r1, RD_FLAGS);
641 if (fd1 < 0)
642 return(-1);
643 fd2 = open(r2, RD_FLAGS);
644 if (fd2 < 0) {
645 close(fd1);
646 return(-1);
647 }
648 while (1) {
649 res1 = read(fd1, bytes1, 4096);
650 res2 = read(fd2, bytes2, 4096);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000651 if ((res1 != res2) || (res1 < 0)) {
William M. Brackca15a542005-07-06 20:41:33 +0000652 close(fd1);
653 close(fd2);
654 return(1);
655 }
656 if (res1 == 0)
657 break;
658 if (memcmp(bytes1, bytes2, res1) != 0) {
659 close(fd1);
660 close(fd2);
661 return(1);
662 }
663 }
664 close(fd1);
665 close(fd2);
666 return(0);
667}
668
669static int compareFileMem(const char *filename, const char *mem, int size) {
670 int res;
671 int fd;
672 char bytes[4096];
673 int idx = 0;
674 struct stat info;
675
David Kilzer5c373822016-05-22 09:58:30 +0800676 if (update_results) {
677 fd = open(filename, WR_FLAGS, 0644);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800678 if (fd < 0) {
679 fprintf(stderr, "failed to open %s for writing", filename);
David Kilzer5c373822016-05-22 09:58:30 +0800680 return(-1);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800681 }
David Kilzer5c373822016-05-22 09:58:30 +0800682 res = write(fd, mem, size);
683 close(fd);
684 return(res != size);
685 }
686
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800687 if (stat(filename, &info) < 0) {
688 fprintf(stderr, "failed to stat %s\n", filename);
William M. Brackca15a542005-07-06 20:41:33 +0000689 return(-1);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800690 }
691 if (info.st_size != size) {
692 fprintf(stderr, "file %s is %ld bytes, result is %d bytes\n",
Nick Wellnhoferc2545cb2016-08-22 11:44:18 +0200693 filename, (long) info.st_size, size);
William M. Brackca15a542005-07-06 20:41:33 +0000694 return(-1);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800695 }
William M. Brackca15a542005-07-06 20:41:33 +0000696 fd = open(filename, RD_FLAGS);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800697 if (fd < 0) {
698 fprintf(stderr, "failed to open %s for reading", filename);
William M. Brackca15a542005-07-06 20:41:33 +0000699 return(-1);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800700 }
William M. Brackca15a542005-07-06 20:41:33 +0000701 while (idx < size) {
702 res = read(fd, bytes, 4096);
703 if (res <= 0)
704 break;
Daniel Veillardaa6de472008-08-25 14:53:31 +0000705 if (res + idx > size)
William M. Brackca15a542005-07-06 20:41:33 +0000706 break;
707 if (memcmp(bytes, &mem[idx], res) != 0) {
708 int ix;
709 for (ix=0; ix<res; ix++)
710 if (bytes[ix] != mem[idx+ix])
711 break;
712 fprintf(stderr,"Compare error at position %d\n", idx+ix);
713 close(fd);
714 return(1);
715 }
716 idx += res;
717 }
718 close(fd);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800719 if (idx != size) {
720 fprintf(stderr,"Compare error index %d, size %d\n", idx, size);
721 }
William M. Brackca15a542005-07-06 20:41:33 +0000722 return(idx != size);
723}
724
725static int loadMem(const char *filename, const char **mem, int *size) {
726 int fd, res;
727 struct stat info;
728 char *base;
729 int siz = 0;
Daniel Veillardaa6de472008-08-25 14:53:31 +0000730 if (stat(filename, &info) < 0)
William M. Brackca15a542005-07-06 20:41:33 +0000731 return(-1);
732 base = malloc(info.st_size + 1);
733 if (base == NULL)
734 return(-1);
735 if ((fd = open(filename, RD_FLAGS)) < 0) {
736 free(base);
737 return(-1);
738 }
739 while ((res = read(fd, &base[siz], info.st_size - siz)) > 0) {
740 siz += res;
741 }
742 close(fd);
743#if !defined(_WIN32)
744 if (siz != info.st_size) {
745 free(base);
746 return(-1);
747 }
748#endif
749 base[siz] = 0;
750 *mem = base;
751 *size = siz;
752 return(0);
753}
754
755static int unloadMem(const char *mem) {
756 free((char *)mem);
757 return(0);
758}
759
760/************************************************************************
761 * *
762 * Tests implementations *
763 * *
764 ************************************************************************/
765
766/************************************************************************
767 * *
768 * Parse to SAX based tests *
769 * *
770 ************************************************************************/
771
Daniel Veillard24505b02005-07-28 23:49:35 +0000772static FILE *SAXdebug = NULL;
William M. Brackca15a542005-07-06 20:41:33 +0000773
774/*
775 * empty SAX block
776 */
Daniel Veillard24505b02005-07-28 23:49:35 +0000777static xmlSAXHandler emptySAXHandlerStruct = {
William M. Brackca15a542005-07-06 20:41:33 +0000778 NULL, /* internalSubset */
779 NULL, /* isStandalone */
780 NULL, /* hasInternalSubset */
781 NULL, /* hasExternalSubset */
782 NULL, /* resolveEntity */
783 NULL, /* getEntity */
784 NULL, /* entityDecl */
785 NULL, /* notationDecl */
786 NULL, /* attributeDecl */
787 NULL, /* elementDecl */
788 NULL, /* unparsedEntityDecl */
789 NULL, /* setDocumentLocator */
790 NULL, /* startDocument */
791 NULL, /* endDocument */
792 NULL, /* startElement */
793 NULL, /* endElement */
794 NULL, /* reference */
795 NULL, /* characters */
796 NULL, /* ignorableWhitespace */
797 NULL, /* processingInstruction */
798 NULL, /* comment */
799 NULL, /* xmlParserWarning */
800 NULL, /* xmlParserError */
801 NULL, /* xmlParserError */
802 NULL, /* getParameterEntity */
803 NULL, /* cdataBlock; */
804 NULL, /* externalSubset; */
805 1,
806 NULL,
807 NULL, /* startElementNs */
808 NULL, /* endElementNs */
809 NULL /* xmlStructuredErrorFunc */
810};
811
812static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct;
Daniel Veillard24505b02005-07-28 23:49:35 +0000813static int callbacks = 0;
814static int quiet = 0;
William M. Brackca15a542005-07-06 20:41:33 +0000815
816/**
817 * isStandaloneDebug:
818 * @ctxt: An XML parser context
819 *
820 * Is this document tagged standalone ?
821 *
822 * Returns 1 if true
823 */
824static int
825isStandaloneDebug(void *ctx ATTRIBUTE_UNUSED)
826{
827 callbacks++;
828 if (quiet)
829 return(0);
830 fprintf(SAXdebug, "SAX.isStandalone()\n");
831 return(0);
832}
833
834/**
835 * hasInternalSubsetDebug:
836 * @ctxt: An XML parser context
837 *
838 * Does this document has an internal subset
839 *
840 * Returns 1 if true
841 */
842static int
843hasInternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
844{
845 callbacks++;
846 if (quiet)
847 return(0);
848 fprintf(SAXdebug, "SAX.hasInternalSubset()\n");
849 return(0);
850}
851
852/**
853 * hasExternalSubsetDebug:
854 * @ctxt: An XML parser context
855 *
856 * Does this document has an external subset
857 *
858 * Returns 1 if true
859 */
860static int
861hasExternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
862{
863 callbacks++;
864 if (quiet)
865 return(0);
866 fprintf(SAXdebug, "SAX.hasExternalSubset()\n");
867 return(0);
868}
869
870/**
871 * internalSubsetDebug:
872 * @ctxt: An XML parser context
873 *
874 * Does this document has an internal subset
875 */
876static void
877internalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
878 const xmlChar *ExternalID, const xmlChar *SystemID)
879{
880 callbacks++;
881 if (quiet)
882 return;
883 fprintf(SAXdebug, "SAX.internalSubset(%s,", name);
884 if (ExternalID == NULL)
885 fprintf(SAXdebug, " ,");
886 else
887 fprintf(SAXdebug, " %s,", ExternalID);
888 if (SystemID == NULL)
889 fprintf(SAXdebug, " )\n");
890 else
891 fprintf(SAXdebug, " %s)\n", SystemID);
892}
893
894/**
895 * externalSubsetDebug:
896 * @ctxt: An XML parser context
897 *
898 * Does this document has an external subset
899 */
900static void
901externalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
902 const xmlChar *ExternalID, const xmlChar *SystemID)
903{
904 callbacks++;
905 if (quiet)
906 return;
907 fprintf(SAXdebug, "SAX.externalSubset(%s,", name);
908 if (ExternalID == NULL)
909 fprintf(SAXdebug, " ,");
910 else
911 fprintf(SAXdebug, " %s,", ExternalID);
912 if (SystemID == NULL)
913 fprintf(SAXdebug, " )\n");
914 else
915 fprintf(SAXdebug, " %s)\n", SystemID);
916}
917
918/**
919 * resolveEntityDebug:
920 * @ctxt: An XML parser context
921 * @publicId: The public ID of the entity
922 * @systemId: The system ID of the entity
923 *
924 * Special entity resolver, better left to the parser, it has
925 * more context than the application layer.
926 * The default behaviour is to NOT resolve the entities, in that case
927 * the ENTITY_REF nodes are built in the structure (and the parameter
928 * values).
929 *
930 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
931 */
932static xmlParserInputPtr
933resolveEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *publicId, const xmlChar *systemId)
934{
935 callbacks++;
936 if (quiet)
937 return(NULL);
938 /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
939
Daniel Veillardaa6de472008-08-25 14:53:31 +0000940
William M. Brackca15a542005-07-06 20:41:33 +0000941 fprintf(SAXdebug, "SAX.resolveEntity(");
942 if (publicId != NULL)
943 fprintf(SAXdebug, "%s", (char *)publicId);
944 else
945 fprintf(SAXdebug, " ");
946 if (systemId != NULL)
947 fprintf(SAXdebug, ", %s)\n", (char *)systemId);
948 else
949 fprintf(SAXdebug, ", )\n");
950/*********
951 if (systemId != NULL) {
952 return(xmlNewInputFromFile(ctxt, (char *) systemId));
953 }
954 *********/
955 return(NULL);
956}
957
958/**
959 * getEntityDebug:
960 * @ctxt: An XML parser context
961 * @name: The entity name
962 *
963 * Get an entity by name
964 *
965 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
966 */
967static xmlEntityPtr
968getEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
969{
970 callbacks++;
971 if (quiet)
972 return(NULL);
973 fprintf(SAXdebug, "SAX.getEntity(%s)\n", name);
974 return(NULL);
975}
976
977/**
978 * getParameterEntityDebug:
979 * @ctxt: An XML parser context
980 * @name: The entity name
981 *
982 * Get a parameter entity by name
983 *
984 * Returns the xmlParserInputPtr
985 */
986static xmlEntityPtr
987getParameterEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
988{
989 callbacks++;
990 if (quiet)
991 return(NULL);
992 fprintf(SAXdebug, "SAX.getParameterEntity(%s)\n", name);
993 return(NULL);
994}
995
996
997/**
998 * entityDeclDebug:
999 * @ctxt: An XML parser context
Daniel Veillardaa6de472008-08-25 14:53:31 +00001000 * @name: the entity name
1001 * @type: the entity type
William M. Brackca15a542005-07-06 20:41:33 +00001002 * @publicId: The public ID of the entity
1003 * @systemId: The system ID of the entity
1004 * @content: the entity value (without processing).
1005 *
1006 * An entity definition has been parsed
1007 */
1008static void
1009entityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
1010 const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
1011{
1012const xmlChar *nullstr = BAD_CAST "(null)";
1013 /* not all libraries handle printing null pointers nicely */
1014 if (publicId == NULL)
1015 publicId = nullstr;
1016 if (systemId == NULL)
1017 systemId = nullstr;
1018 if (content == NULL)
1019 content = (xmlChar *)nullstr;
1020 callbacks++;
1021 if (quiet)
1022 return;
1023 fprintf(SAXdebug, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
1024 name, type, publicId, systemId, content);
1025}
1026
1027/**
1028 * attributeDeclDebug:
1029 * @ctxt: An XML parser context
Daniel Veillardaa6de472008-08-25 14:53:31 +00001030 * @name: the attribute name
1031 * @type: the attribute type
William M. Brackca15a542005-07-06 20:41:33 +00001032 *
1033 * An attribute definition has been parsed
1034 */
1035static void
1036attributeDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar * elem,
1037 const xmlChar * name, int type, int def,
1038 const xmlChar * defaultValue, xmlEnumerationPtr tree)
1039{
1040 callbacks++;
1041 if (quiet)
1042 return;
1043 if (defaultValue == NULL)
1044 fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, NULL, ...)\n",
1045 elem, name, type, def);
1046 else
1047 fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
1048 elem, name, type, def, defaultValue);
1049 xmlFreeEnumeration(tree);
1050}
1051
1052/**
1053 * elementDeclDebug:
1054 * @ctxt: An XML parser context
Daniel Veillardaa6de472008-08-25 14:53:31 +00001055 * @name: the element name
1056 * @type: the element type
William M. Brackca15a542005-07-06 20:41:33 +00001057 * @content: the element value (without processing).
1058 *
1059 * An element definition has been parsed
1060 */
1061static void
1062elementDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
1063 xmlElementContentPtr content ATTRIBUTE_UNUSED)
1064{
1065 callbacks++;
1066 if (quiet)
1067 return;
1068 fprintf(SAXdebug, "SAX.elementDecl(%s, %d, ...)\n",
1069 name, type);
1070}
1071
1072/**
1073 * notationDeclDebug:
1074 * @ctxt: An XML parser context
1075 * @name: The name of the notation
1076 * @publicId: The public ID of the entity
1077 * @systemId: The system ID of the entity
1078 *
1079 * What to do when a notation declaration has been parsed.
1080 */
1081static void
1082notationDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
1083 const xmlChar *publicId, const xmlChar *systemId)
1084{
1085 callbacks++;
1086 if (quiet)
1087 return;
1088 fprintf(SAXdebug, "SAX.notationDecl(%s, %s, %s)\n",
1089 (char *) name, (char *) publicId, (char *) systemId);
1090}
1091
1092/**
1093 * unparsedEntityDeclDebug:
1094 * @ctxt: An XML parser context
1095 * @name: The name of the entity
1096 * @publicId: The public ID of the entity
1097 * @systemId: The system ID of the entity
1098 * @notationName: the name of the notation
1099 *
1100 * What to do when an unparsed entity declaration is parsed
1101 */
1102static void
1103unparsedEntityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
1104 const xmlChar *publicId, const xmlChar *systemId,
1105 const xmlChar *notationName)
1106{
1107const xmlChar *nullstr = BAD_CAST "(null)";
1108
1109 if (publicId == NULL)
1110 publicId = nullstr;
1111 if (systemId == NULL)
1112 systemId = nullstr;
1113 if (notationName == NULL)
1114 notationName = nullstr;
1115 callbacks++;
1116 if (quiet)
1117 return;
1118 fprintf(SAXdebug, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
1119 (char *) name, (char *) publicId, (char *) systemId,
1120 (char *) notationName);
1121}
1122
1123/**
1124 * setDocumentLocatorDebug:
1125 * @ctxt: An XML parser context
1126 * @loc: A SAX Locator
1127 *
1128 * Receive the document locator at startup, actually xmlDefaultSAXLocator
1129 * Everything is available on the context, so this is useless in our case.
1130 */
1131static void
1132setDocumentLocatorDebug(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
1133{
1134 callbacks++;
1135 if (quiet)
1136 return;
1137 fprintf(SAXdebug, "SAX.setDocumentLocator()\n");
1138}
1139
1140/**
1141 * startDocumentDebug:
1142 * @ctxt: An XML parser context
1143 *
1144 * called when the document start being processed.
1145 */
1146static void
1147startDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
1148{
1149 callbacks++;
1150 if (quiet)
1151 return;
1152 fprintf(SAXdebug, "SAX.startDocument()\n");
1153}
1154
1155/**
1156 * endDocumentDebug:
1157 * @ctxt: An XML parser context
1158 *
1159 * called when the document end has been detected.
1160 */
1161static void
1162endDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
1163{
1164 callbacks++;
1165 if (quiet)
1166 return;
1167 fprintf(SAXdebug, "SAX.endDocument()\n");
1168}
1169
1170/**
1171 * startElementDebug:
1172 * @ctxt: An XML parser context
1173 * @name: The element name
1174 *
1175 * called when an opening tag has been processed.
1176 */
1177static void
1178startElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
1179{
1180 int i;
1181
1182 callbacks++;
1183 if (quiet)
1184 return;
1185 fprintf(SAXdebug, "SAX.startElement(%s", (char *) name);
1186 if (atts != NULL) {
1187 for (i = 0;(atts[i] != NULL);i++) {
1188 fprintf(SAXdebug, ", %s='", atts[i++]);
1189 if (atts[i] != NULL)
1190 fprintf(SAXdebug, "%s'", atts[i]);
1191 }
1192 }
1193 fprintf(SAXdebug, ")\n");
1194}
1195
1196/**
1197 * endElementDebug:
1198 * @ctxt: An XML parser context
1199 * @name: The element name
1200 *
1201 * called when the end of an element has been detected.
1202 */
1203static void
1204endElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
1205{
1206 callbacks++;
1207 if (quiet)
1208 return;
1209 fprintf(SAXdebug, "SAX.endElement(%s)\n", (char *) name);
1210}
1211
1212/**
1213 * charactersDebug:
1214 * @ctxt: An XML parser context
1215 * @ch: a xmlChar string
1216 * @len: the number of xmlChar
1217 *
1218 * receiving some chars from the parser.
1219 * Question: how much at a time ???
1220 */
1221static void
1222charactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1223{
1224 char output[40];
1225 int i;
1226
1227 callbacks++;
1228 if (quiet)
1229 return;
1230 for (i = 0;(i<len) && (i < 30);i++)
1231 output[i] = ch[i];
1232 output[i] = 0;
1233
1234 fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len);
1235}
1236
1237/**
1238 * referenceDebug:
1239 * @ctxt: An XML parser context
1240 * @name: The entity name
1241 *
Daniel Veillardaa6de472008-08-25 14:53:31 +00001242 * called when an entity reference is detected.
William M. Brackca15a542005-07-06 20:41:33 +00001243 */
1244static void
1245referenceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
1246{
1247 callbacks++;
1248 if (quiet)
1249 return;
1250 fprintf(SAXdebug, "SAX.reference(%s)\n", name);
1251}
1252
1253/**
1254 * ignorableWhitespaceDebug:
1255 * @ctxt: An XML parser context
1256 * @ch: a xmlChar string
1257 * @start: the first char in the string
1258 * @len: the number of xmlChar
1259 *
1260 * receiving some ignorable whitespaces from the parser.
1261 * Question: how much at a time ???
1262 */
1263static void
1264ignorableWhitespaceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1265{
1266 char output[40];
1267 int i;
1268
1269 callbacks++;
1270 if (quiet)
1271 return;
1272 for (i = 0;(i<len) && (i < 30);i++)
1273 output[i] = ch[i];
1274 output[i] = 0;
1275 fprintf(SAXdebug, "SAX.ignorableWhitespace(%s, %d)\n", output, len);
1276}
1277
1278/**
1279 * processingInstructionDebug:
1280 * @ctxt: An XML parser context
1281 * @target: the target name
1282 * @data: the PI data's
1283 * @len: the number of xmlChar
1284 *
1285 * A processing instruction has been parsed.
1286 */
1287static void
1288processingInstructionDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *target,
1289 const xmlChar *data)
1290{
1291 callbacks++;
1292 if (quiet)
1293 return;
1294 if (data != NULL)
1295 fprintf(SAXdebug, "SAX.processingInstruction(%s, %s)\n",
1296 (char *) target, (char *) data);
1297 else
1298 fprintf(SAXdebug, "SAX.processingInstruction(%s, NULL)\n",
1299 (char *) target);
1300}
1301
1302/**
1303 * cdataBlockDebug:
1304 * @ctx: the user data (XML parser context)
1305 * @value: The pcdata content
1306 * @len: the block length
1307 *
1308 * called when a pcdata block has been parsed
1309 */
1310static void
1311cdataBlockDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value, int len)
1312{
1313 callbacks++;
1314 if (quiet)
1315 return;
1316 fprintf(SAXdebug, "SAX.pcdata(%.20s, %d)\n",
1317 (char *) value, len);
1318}
1319
1320/**
1321 * commentDebug:
1322 * @ctxt: An XML parser context
1323 * @value: the comment content
1324 *
1325 * A comment has been parsed.
1326 */
1327static void
1328commentDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value)
1329{
1330 callbacks++;
1331 if (quiet)
1332 return;
1333 fprintf(SAXdebug, "SAX.comment(%s)\n", value);
1334}
1335
1336/**
1337 * warningDebug:
1338 * @ctxt: An XML parser context
1339 * @msg: the message to display/transmit
1340 * @...: extra parameters for the message display
1341 *
1342 * Display and format a warning messages, gives file, line, position and
1343 * extra parameters.
1344 */
Daniel Veillardffa3c742005-07-21 13:24:09 +00001345static void XMLCDECL
William M. Brackca15a542005-07-06 20:41:33 +00001346warningDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1347{
1348 va_list args;
1349
1350 callbacks++;
1351 if (quiet)
1352 return;
1353 va_start(args, msg);
1354 fprintf(SAXdebug, "SAX.warning: ");
1355 vfprintf(SAXdebug, msg, args);
1356 va_end(args);
1357}
1358
1359/**
1360 * errorDebug:
1361 * @ctxt: An XML parser context
1362 * @msg: the message to display/transmit
1363 * @...: extra parameters for the message display
1364 *
1365 * Display and format a error messages, gives file, line, position and
1366 * extra parameters.
1367 */
Daniel Veillardffa3c742005-07-21 13:24:09 +00001368static void XMLCDECL
William M. Brackca15a542005-07-06 20:41:33 +00001369errorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1370{
1371 va_list args;
1372
1373 callbacks++;
1374 if (quiet)
1375 return;
1376 va_start(args, msg);
1377 fprintf(SAXdebug, "SAX.error: ");
1378 vfprintf(SAXdebug, msg, args);
1379 va_end(args);
1380}
1381
1382/**
1383 * fatalErrorDebug:
1384 * @ctxt: An XML parser context
1385 * @msg: the message to display/transmit
1386 * @...: extra parameters for the message display
1387 *
1388 * Display and format a fatalError messages, gives file, line, position and
1389 * extra parameters.
1390 */
Daniel Veillardffa3c742005-07-21 13:24:09 +00001391static void XMLCDECL
William M. Brackca15a542005-07-06 20:41:33 +00001392fatalErrorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1393{
1394 va_list args;
1395
1396 callbacks++;
1397 if (quiet)
1398 return;
1399 va_start(args, msg);
1400 fprintf(SAXdebug, "SAX.fatalError: ");
1401 vfprintf(SAXdebug, msg, args);
1402 va_end(args);
1403}
1404
Daniel Veillard24505b02005-07-28 23:49:35 +00001405static xmlSAXHandler debugSAXHandlerStruct = {
William M. Brackca15a542005-07-06 20:41:33 +00001406 internalSubsetDebug,
1407 isStandaloneDebug,
1408 hasInternalSubsetDebug,
1409 hasExternalSubsetDebug,
1410 resolveEntityDebug,
1411 getEntityDebug,
1412 entityDeclDebug,
1413 notationDeclDebug,
1414 attributeDeclDebug,
1415 elementDeclDebug,
1416 unparsedEntityDeclDebug,
1417 setDocumentLocatorDebug,
1418 startDocumentDebug,
1419 endDocumentDebug,
1420 startElementDebug,
1421 endElementDebug,
1422 referenceDebug,
1423 charactersDebug,
1424 ignorableWhitespaceDebug,
1425 processingInstructionDebug,
1426 commentDebug,
1427 warningDebug,
1428 errorDebug,
1429 fatalErrorDebug,
1430 getParameterEntityDebug,
1431 cdataBlockDebug,
1432 externalSubsetDebug,
1433 1,
1434 NULL,
1435 NULL,
1436 NULL,
1437 NULL
1438};
1439
Daniel Veillard24505b02005-07-28 23:49:35 +00001440static xmlSAXHandlerPtr debugSAXHandler = &debugSAXHandlerStruct;
William M. Brackca15a542005-07-06 20:41:33 +00001441
1442/*
1443 * SAX2 specific callbacks
1444 */
1445/**
1446 * startElementNsDebug:
1447 * @ctxt: An XML parser context
1448 * @name: The element name
1449 *
1450 * called when an opening tag has been processed.
1451 */
1452static void
1453startElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
1454 const xmlChar *localname,
1455 const xmlChar *prefix,
1456 const xmlChar *URI,
1457 int nb_namespaces,
1458 const xmlChar **namespaces,
1459 int nb_attributes,
1460 int nb_defaulted,
1461 const xmlChar **attributes)
1462{
1463 int i;
1464
1465 callbacks++;
1466 if (quiet)
1467 return;
1468 fprintf(SAXdebug, "SAX.startElementNs(%s", (char *) localname);
1469 if (prefix == NULL)
1470 fprintf(SAXdebug, ", NULL");
1471 else
1472 fprintf(SAXdebug, ", %s", (char *) prefix);
1473 if (URI == NULL)
1474 fprintf(SAXdebug, ", NULL");
1475 else
1476 fprintf(SAXdebug, ", '%s'", (char *) URI);
1477 fprintf(SAXdebug, ", %d", nb_namespaces);
Daniel Veillardaa6de472008-08-25 14:53:31 +00001478
William M. Brackca15a542005-07-06 20:41:33 +00001479 if (namespaces != NULL) {
1480 for (i = 0;i < nb_namespaces * 2;i++) {
1481 fprintf(SAXdebug, ", xmlns");
1482 if (namespaces[i] != NULL)
1483 fprintf(SAXdebug, ":%s", namespaces[i]);
1484 i++;
1485 fprintf(SAXdebug, "='%s'", namespaces[i]);
1486 }
1487 }
1488 fprintf(SAXdebug, ", %d, %d", nb_attributes, nb_defaulted);
1489 if (attributes != NULL) {
1490 for (i = 0;i < nb_attributes * 5;i += 5) {
1491 if (attributes[i + 1] != NULL)
1492 fprintf(SAXdebug, ", %s:%s='", attributes[i + 1], attributes[i]);
1493 else
1494 fprintf(SAXdebug, ", %s='", attributes[i]);
1495 fprintf(SAXdebug, "%.4s...', %d", attributes[i + 3],
1496 (int)(attributes[i + 4] - attributes[i + 3]));
1497 }
1498 }
1499 fprintf(SAXdebug, ")\n");
1500}
1501
1502/**
1503 * endElementDebug:
1504 * @ctxt: An XML parser context
1505 * @name: The element name
1506 *
1507 * called when the end of an element has been detected.
1508 */
1509static void
1510endElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
1511 const xmlChar *localname,
1512 const xmlChar *prefix,
1513 const xmlChar *URI)
1514{
1515 callbacks++;
1516 if (quiet)
1517 return;
1518 fprintf(SAXdebug, "SAX.endElementNs(%s", (char *) localname);
1519 if (prefix == NULL)
1520 fprintf(SAXdebug, ", NULL");
1521 else
1522 fprintf(SAXdebug, ", %s", (char *) prefix);
1523 if (URI == NULL)
1524 fprintf(SAXdebug, ", NULL)\n");
1525 else
1526 fprintf(SAXdebug, ", '%s')\n", (char *) URI);
1527}
1528
Daniel Veillard24505b02005-07-28 23:49:35 +00001529static xmlSAXHandler debugSAX2HandlerStruct = {
William M. Brackca15a542005-07-06 20:41:33 +00001530 internalSubsetDebug,
1531 isStandaloneDebug,
1532 hasInternalSubsetDebug,
1533 hasExternalSubsetDebug,
1534 resolveEntityDebug,
1535 getEntityDebug,
1536 entityDeclDebug,
1537 notationDeclDebug,
1538 attributeDeclDebug,
1539 elementDeclDebug,
1540 unparsedEntityDeclDebug,
1541 setDocumentLocatorDebug,
1542 startDocumentDebug,
1543 endDocumentDebug,
1544 NULL,
1545 NULL,
1546 referenceDebug,
1547 charactersDebug,
1548 ignorableWhitespaceDebug,
1549 processingInstructionDebug,
1550 commentDebug,
1551 warningDebug,
1552 errorDebug,
1553 fatalErrorDebug,
1554 getParameterEntityDebug,
1555 cdataBlockDebug,
1556 externalSubsetDebug,
1557 XML_SAX2_MAGIC,
1558 NULL,
1559 startElementNsDebug,
1560 endElementNsDebug,
1561 NULL
1562};
1563
Daniel Veillard24505b02005-07-28 23:49:35 +00001564static xmlSAXHandlerPtr debugSAX2Handler = &debugSAX2HandlerStruct;
William M. Brackca15a542005-07-06 20:41:33 +00001565
1566#ifdef LIBXML_HTML_ENABLED
1567/**
1568 * htmlstartElementDebug:
1569 * @ctxt: An XML parser context
1570 * @name: The element name
1571 *
1572 * called when an opening tag has been processed.
1573 */
1574static void
1575htmlstartElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
1576{
1577 int i;
1578
1579 fprintf(SAXdebug, "SAX.startElement(%s", (char *) name);
1580 if (atts != NULL) {
1581 for (i = 0;(atts[i] != NULL);i++) {
1582 fprintf(SAXdebug, ", %s", atts[i++]);
1583 if (atts[i] != NULL) {
1584 unsigned char output[40];
1585 const unsigned char *att = atts[i];
1586 int outlen, attlen;
1587 fprintf(SAXdebug, "='");
1588 while ((attlen = strlen((char*)att)) > 0) {
1589 outlen = sizeof output - 1;
1590 htmlEncodeEntities(output, &outlen, att, &attlen, '\'');
1591 output[outlen] = 0;
1592 fprintf(SAXdebug, "%s", (char *) output);
1593 att += attlen;
1594 }
1595 fprintf(SAXdebug, "'");
1596 }
1597 }
1598 }
1599 fprintf(SAXdebug, ")\n");
1600}
1601
1602/**
1603 * htmlcharactersDebug:
1604 * @ctxt: An XML parser context
1605 * @ch: a xmlChar string
1606 * @len: the number of xmlChar
1607 *
1608 * receiving some chars from the parser.
1609 * Question: how much at a time ???
1610 */
1611static void
1612htmlcharactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1613{
1614 unsigned char output[40];
1615 int inlen = len, outlen = 30;
1616
1617 htmlEncodeEntities(output, &outlen, ch, &inlen, 0);
1618 output[outlen] = 0;
1619
1620 fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len);
1621}
1622
1623/**
1624 * htmlcdataDebug:
1625 * @ctxt: An XML parser context
1626 * @ch: a xmlChar string
1627 * @len: the number of xmlChar
1628 *
1629 * receiving some cdata chars from the parser.
1630 * Question: how much at a time ???
1631 */
1632static void
1633htmlcdataDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1634{
1635 unsigned char output[40];
1636 int inlen = len, outlen = 30;
1637
1638 htmlEncodeEntities(output, &outlen, ch, &inlen, 0);
1639 output[outlen] = 0;
1640
1641 fprintf(SAXdebug, "SAX.cdata(%s, %d)\n", output, len);
1642}
1643
Daniel Veillard24505b02005-07-28 23:49:35 +00001644static xmlSAXHandler debugHTMLSAXHandlerStruct = {
William M. Brackca15a542005-07-06 20:41:33 +00001645 internalSubsetDebug,
1646 isStandaloneDebug,
1647 hasInternalSubsetDebug,
1648 hasExternalSubsetDebug,
1649 resolveEntityDebug,
1650 getEntityDebug,
1651 entityDeclDebug,
1652 notationDeclDebug,
1653 attributeDeclDebug,
1654 elementDeclDebug,
1655 unparsedEntityDeclDebug,
1656 setDocumentLocatorDebug,
1657 startDocumentDebug,
1658 endDocumentDebug,
1659 htmlstartElementDebug,
1660 endElementDebug,
1661 referenceDebug,
1662 htmlcharactersDebug,
1663 ignorableWhitespaceDebug,
1664 processingInstructionDebug,
1665 commentDebug,
1666 warningDebug,
1667 errorDebug,
1668 fatalErrorDebug,
1669 getParameterEntityDebug,
1670 htmlcdataDebug,
1671 externalSubsetDebug,
1672 1,
1673 NULL,
1674 NULL,
1675 NULL,
1676 NULL
1677};
1678
Daniel Veillard24505b02005-07-28 23:49:35 +00001679static xmlSAXHandlerPtr debugHTMLSAXHandler = &debugHTMLSAXHandlerStruct;
William M. Brackca15a542005-07-06 20:41:33 +00001680#endif /* LIBXML_HTML_ENABLED */
1681
William M. Brackca15a542005-07-06 20:41:33 +00001682/**
1683 * saxParseTest:
1684 * @filename: the file to parse
1685 * @result: the file with expected result
1686 * @err: the file with error messages
1687 *
1688 * Parse a file using the SAX API and check for errors.
1689 *
1690 * Returns 0 in case of success, an error code otherwise
1691 */
1692static int
1693saxParseTest(const char *filename, const char *result,
1694 const char *err ATTRIBUTE_UNUSED,
1695 int options) {
1696 int ret;
1697 char *temp;
1698
1699 nb_tests++;
1700 temp = resultFilename(filename, "", ".res");
1701 if (temp == NULL) {
1702 fprintf(stderr, "out of memory\n");
1703 fatalError();
1704 }
1705 SAXdebug = fopen(temp, "wb");
1706 if (SAXdebug == NULL) {
1707 fprintf(stderr, "Failed to write to %s\n", temp);
1708 free(temp);
1709 return(-1);
1710 }
1711
1712 /* for SAX we really want the callbacks though the context handlers */
1713 xmlSetStructuredErrorFunc(NULL, NULL);
1714 xmlSetGenericErrorFunc(NULL, testErrorHandler);
1715
1716#ifdef LIBXML_HTML_ENABLED
1717 if (options & XML_PARSE_HTML) {
1718 htmlSAXParseFile(filename, NULL, emptySAXHandler, NULL);
1719 ret = 0;
1720 } else
1721#endif
Nick Wellnhoferdbaab1f2017-06-16 21:38:57 +02001722 {
1723 xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename);
1724 memcpy(ctxt->sax, emptySAXHandler, sizeof(xmlSAXHandler));
1725 xmlCtxtUseOptions(ctxt, options);
1726 xmlParseDocument(ctxt);
1727 ret = ctxt->wellFormed ? 0 : ctxt->errNo;
1728 xmlFreeDoc(ctxt->myDoc);
1729 xmlFreeParserCtxt(ctxt);
1730 }
William M. Brackca15a542005-07-06 20:41:33 +00001731 if (ret == XML_WAR_UNDECLARED_ENTITY) {
1732 fprintf(SAXdebug, "xmlSAXUserParseFile returned error %d\n", ret);
1733 ret = 0;
1734 }
1735 if (ret != 0) {
1736 fprintf(stderr, "Failed to parse %s\n", filename);
Philip Withnall5777ae72014-06-20 21:15:16 +01001737 ret = 1;
1738 goto done;
William M. Brackca15a542005-07-06 20:41:33 +00001739 }
1740#ifdef LIBXML_HTML_ENABLED
1741 if (options & XML_PARSE_HTML) {
1742 htmlSAXParseFile(filename, NULL, debugHTMLSAXHandler, NULL);
1743 ret = 0;
1744 } else
1745#endif
Nick Wellnhoferdbaab1f2017-06-16 21:38:57 +02001746 {
1747 xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename);
1748 if (options & XML_PARSE_SAX1) {
1749 memcpy(ctxt->sax, debugSAXHandler, sizeof(xmlSAXHandler));
1750 options -= XML_PARSE_SAX1;
1751 } else {
1752 memcpy(ctxt->sax, debugSAX2Handler, sizeof(xmlSAXHandler));
1753 }
1754 xmlCtxtUseOptions(ctxt, options);
1755 xmlParseDocument(ctxt);
1756 ret = ctxt->wellFormed ? 0 : ctxt->errNo;
1757 xmlFreeDoc(ctxt->myDoc);
1758 xmlFreeParserCtxt(ctxt);
William M. Brackca15a542005-07-06 20:41:33 +00001759 }
1760 if (ret == XML_WAR_UNDECLARED_ENTITY) {
1761 fprintf(SAXdebug, "xmlSAXUserParseFile returned error %d\n", ret);
1762 ret = 0;
1763 }
1764 fclose(SAXdebug);
1765 if (compareFiles(temp, result)) {
1766 fprintf(stderr, "Got a difference for %s\n", filename);
1767 ret = 1;
Daniel Veillard13cee4e2009-09-05 14:52:55 +02001768 }
Philip Withnall5777ae72014-06-20 21:15:16 +01001769
1770done:
Daniel Veillard13cee4e2009-09-05 14:52:55 +02001771 if (temp != NULL) {
1772 unlink(temp);
1773 free(temp);
1774 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00001775
William M. Brackca15a542005-07-06 20:41:33 +00001776 /* switch back to structured error handling */
1777 xmlSetGenericErrorFunc(NULL, NULL);
1778 xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
1779
1780 return(ret);
1781}
William M. Brackca15a542005-07-06 20:41:33 +00001782
1783/************************************************************************
1784 * *
1785 * Parse to tree based tests *
1786 * *
1787 ************************************************************************/
1788/**
1789 * oldParseTest:
1790 * @filename: the file to parse
1791 * @result: the file with expected result
1792 * @err: the file with error messages: unused
1793 *
1794 * Parse a file using the old xmlParseFile API, then serialize back
1795 * reparse the result and serialize again, then check for deviation
1796 * in serialization.
1797 *
1798 * Returns 0 in case of success, an error code otherwise
1799 */
1800static int
1801oldParseTest(const char *filename, const char *result,
1802 const char *err ATTRIBUTE_UNUSED,
1803 int options ATTRIBUTE_UNUSED) {
1804 xmlDocPtr doc;
1805 char *temp;
1806 int res = 0;
1807
1808 nb_tests++;
1809 /*
1810 * base of the test, parse with the old API
1811 */
1812#ifdef LIBXML_SAX1_ENABLED
1813 doc = xmlParseFile(filename);
1814#else
1815 doc = xmlReadFile(filename, NULL, 0);
1816#endif
1817 if (doc == NULL)
1818 return(1);
1819 temp = resultFilename(filename, "", ".res");
1820 if (temp == NULL) {
1821 fprintf(stderr, "out of memory\n");
1822 fatalError();
1823 }
1824 xmlSaveFile(temp, doc);
1825 if (compareFiles(temp, result)) {
1826 res = 1;
1827 }
1828 xmlFreeDoc(doc);
1829
1830 /*
1831 * Parse the saved result to make sure the round trip is okay
1832 */
1833#ifdef LIBXML_SAX1_ENABLED
1834 doc = xmlParseFile(temp);
1835#else
1836 doc = xmlReadFile(temp, NULL, 0);
1837#endif
1838 if (doc == NULL)
1839 return(1);
1840 xmlSaveFile(temp, doc);
1841 if (compareFiles(temp, result)) {
1842 res = 1;
1843 }
1844 xmlFreeDoc(doc);
1845
Daniel Veillard13cee4e2009-09-05 14:52:55 +02001846 if (temp != NULL) {
1847 unlink(temp);
1848 free(temp);
1849 }
William M. Brackca15a542005-07-06 20:41:33 +00001850 return(res);
1851}
1852
1853#ifdef LIBXML_PUSH_ENABLED
1854/**
1855 * pushParseTest:
1856 * @filename: the file to parse
1857 * @result: the file with expected result
1858 * @err: the file with error messages: unused
1859 *
1860 * Parse a file using the Push API, then serialize back
1861 * to check for content.
1862 *
1863 * Returns 0 in case of success, an error code otherwise
1864 */
1865static int
1866pushParseTest(const char *filename, const char *result,
1867 const char *err ATTRIBUTE_UNUSED,
1868 int options) {
1869 xmlParserCtxtPtr ctxt;
1870 xmlDocPtr doc;
1871 const char *base;
1872 int size, res;
1873 int cur = 0;
David Kilzer85c112a2017-06-12 18:26:11 +02001874 int chunkSize = 4;
William M. Brackca15a542005-07-06 20:41:33 +00001875
1876 nb_tests++;
1877 /*
1878 * load the document in memory and work from there.
1879 */
1880 if (loadMem(filename, &base, &size) != 0) {
1881 fprintf(stderr, "Failed to load %s\n", filename);
1882 return(-1);
1883 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00001884
David Kilzer85c112a2017-06-12 18:26:11 +02001885 if (chunkSize > size)
1886 chunkSize = size;
1887
William M. Brackca15a542005-07-06 20:41:33 +00001888#ifdef LIBXML_HTML_ENABLED
1889 if (options & XML_PARSE_HTML)
David Kilzer85c112a2017-06-12 18:26:11 +02001890 ctxt = htmlCreatePushParserCtxt(NULL, NULL, base + cur, chunkSize, filename,
William M. Brackca15a542005-07-06 20:41:33 +00001891 XML_CHAR_ENCODING_NONE);
1892 else
1893#endif
David Kilzer85c112a2017-06-12 18:26:11 +02001894 ctxt = xmlCreatePushParserCtxt(NULL, NULL, base + cur, chunkSize, filename);
William M. Brackca15a542005-07-06 20:41:33 +00001895 xmlCtxtUseOptions(ctxt, options);
David Kilzer85c112a2017-06-12 18:26:11 +02001896 cur += chunkSize;
1897 chunkSize = 1024;
Pranjal Jumdea820dbe2016-03-01 11:34:04 -08001898 do {
David Kilzer85c112a2017-06-12 18:26:11 +02001899 if (cur + chunkSize >= size) {
William M. Brackca15a542005-07-06 20:41:33 +00001900#ifdef LIBXML_HTML_ENABLED
1901 if (options & XML_PARSE_HTML)
1902 htmlParseChunk(ctxt, base + cur, size - cur, 1);
1903 else
1904#endif
1905 xmlParseChunk(ctxt, base + cur, size - cur, 1);
1906 break;
1907 } else {
1908#ifdef LIBXML_HTML_ENABLED
1909 if (options & XML_PARSE_HTML)
David Kilzer85c112a2017-06-12 18:26:11 +02001910 htmlParseChunk(ctxt, base + cur, chunkSize, 0);
William M. Brackca15a542005-07-06 20:41:33 +00001911 else
1912#endif
David Kilzer85c112a2017-06-12 18:26:11 +02001913 xmlParseChunk(ctxt, base + cur, chunkSize, 0);
1914 cur += chunkSize;
William M. Brackca15a542005-07-06 20:41:33 +00001915 }
Pranjal Jumdea820dbe2016-03-01 11:34:04 -08001916 } while (cur < size);
William M. Brackca15a542005-07-06 20:41:33 +00001917 doc = ctxt->myDoc;
1918#ifdef LIBXML_HTML_ENABLED
1919 if (options & XML_PARSE_HTML)
1920 res = 1;
1921 else
1922#endif
1923 res = ctxt->wellFormed;
1924 xmlFreeParserCtxt(ctxt);
1925 free((char *)base);
1926 if (!res) {
1927 xmlFreeDoc(doc);
1928 fprintf(stderr, "Failed to parse %s\n", filename);
1929 return(-1);
1930 }
1931#ifdef LIBXML_HTML_ENABLED
1932 if (options & XML_PARSE_HTML)
1933 htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1934 else
1935#endif
1936 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1937 xmlFreeDoc(doc);
1938 res = compareFileMem(result, base, size);
1939 if ((base == NULL) || (res != 0)) {
1940 if (base != NULL)
1941 xmlFree((char *)base);
Daniel Veillard9f2416c2016-05-22 11:14:45 +08001942 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00001943 return(-1);
1944 }
1945 xmlFree((char *)base);
1946 if (err != NULL) {
1947 res = compareFileMem(err, testErrors, testErrorsSize);
1948 if (res != 0) {
1949 fprintf(stderr, "Error for %s failed\n", filename);
1950 return(-1);
1951 }
1952 }
1953 return(0);
1954}
1955#endif
1956
1957/**
1958 * memParseTest:
1959 * @filename: the file to parse
1960 * @result: the file with expected result
1961 * @err: the file with error messages: unused
1962 *
1963 * Parse a file using the old xmlReadMemory API, then serialize back
1964 * reparse the result and serialize again, then check for deviation
1965 * in serialization.
1966 *
1967 * Returns 0 in case of success, an error code otherwise
1968 */
1969static int
1970memParseTest(const char *filename, const char *result,
1971 const char *err ATTRIBUTE_UNUSED,
1972 int options ATTRIBUTE_UNUSED) {
1973 xmlDocPtr doc;
1974 const char *base;
1975 int size, res;
1976
1977 nb_tests++;
1978 /*
1979 * load and parse the memory
1980 */
1981 if (loadMem(filename, &base, &size) != 0) {
1982 fprintf(stderr, "Failed to load %s\n", filename);
1983 return(-1);
1984 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00001985
William M. Brackca15a542005-07-06 20:41:33 +00001986 doc = xmlReadMemory(base, size, filename, NULL, 0);
1987 unloadMem(base);
1988 if (doc == NULL) {
1989 return(1);
1990 }
1991 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1992 xmlFreeDoc(doc);
1993 res = compareFileMem(result, base, size);
1994 if ((base == NULL) || (res != 0)) {
1995 if (base != NULL)
1996 xmlFree((char *)base);
Daniel Veillard9f2416c2016-05-22 11:14:45 +08001997 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00001998 return(-1);
1999 }
2000 xmlFree((char *)base);
2001 return(0);
2002}
2003
2004/**
2005 * noentParseTest:
2006 * @filename: the file to parse
2007 * @result: the file with expected result
2008 * @err: the file with error messages: unused
2009 *
2010 * Parse a file with entity resolution, then serialize back
2011 * reparse the result and serialize again, then check for deviation
2012 * in serialization.
2013 *
2014 * Returns 0 in case of success, an error code otherwise
2015 */
2016static int
2017noentParseTest(const char *filename, const char *result,
2018 const char *err ATTRIBUTE_UNUSED,
2019 int options) {
2020 xmlDocPtr doc;
2021 char *temp;
2022 int res = 0;
2023
2024 nb_tests++;
2025 /*
2026 * base of the test, parse with the old API
2027 */
2028 doc = xmlReadFile(filename, NULL, options);
2029 if (doc == NULL)
2030 return(1);
2031 temp = resultFilename(filename, "", ".res");
2032 if (temp == NULL) {
2033 fprintf(stderr, "Out of memory\n");
2034 fatalError();
2035 }
2036 xmlSaveFile(temp, doc);
2037 if (compareFiles(temp, result)) {
2038 res = 1;
2039 }
2040 xmlFreeDoc(doc);
2041
2042 /*
2043 * Parse the saved result to make sure the round trip is okay
2044 */
2045 doc = xmlReadFile(filename, NULL, options);
2046 if (doc == NULL)
2047 return(1);
2048 xmlSaveFile(temp, doc);
2049 if (compareFiles(temp, result)) {
2050 res = 1;
2051 }
2052 xmlFreeDoc(doc);
2053
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002054 if (temp != NULL) {
2055 unlink(temp);
2056 free(temp);
2057 }
William M. Brackca15a542005-07-06 20:41:33 +00002058 return(res);
2059}
2060
2061/**
2062 * errParseTest:
2063 * @filename: the file to parse
2064 * @result: the file with expected result
2065 * @err: the file with error messages
2066 *
2067 * Parse a file using the xmlReadFile API and check for errors.
2068 *
2069 * Returns 0 in case of success, an error code otherwise
2070 */
2071static int
2072errParseTest(const char *filename, const char *result, const char *err,
2073 int options) {
2074 xmlDocPtr doc;
2075 const char *base = NULL;
2076 int size, res = 0;
2077
2078 nb_tests++;
2079#ifdef LIBXML_HTML_ENABLED
2080 if (options & XML_PARSE_HTML) {
2081 doc = htmlReadFile(filename, NULL, options);
2082 } else
2083#endif
2084#ifdef LIBXML_XINCLUDE_ENABLED
2085 if (options & XML_PARSE_XINCLUDE) {
2086 doc = xmlReadFile(filename, NULL, options);
2087 xmlXIncludeProcessFlags(doc, options);
2088 } else
2089#endif
2090 {
2091 xmlGetWarningsDefaultValue = 1;
2092 doc = xmlReadFile(filename, NULL, options);
2093 }
2094 xmlGetWarningsDefaultValue = 0;
2095 if (result) {
2096 if (doc == NULL) {
2097 base = "";
2098 size = 0;
2099 } else {
2100#ifdef LIBXML_HTML_ENABLED
2101 if (options & XML_PARSE_HTML) {
2102 htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2103 } else
2104#endif
2105 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2106 }
2107 res = compareFileMem(result, base, size);
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002108 if (res != 0) {
2109 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
2110 return(-1);
2111 }
William M. Brackca15a542005-07-06 20:41:33 +00002112 }
2113 if (doc != NULL) {
2114 if (base != NULL)
2115 xmlFree((char *)base);
2116 xmlFreeDoc(doc);
2117 }
William M. Brackca15a542005-07-06 20:41:33 +00002118 if (err != NULL) {
2119 res = compareFileMem(err, testErrors, testErrorsSize);
2120 if (res != 0) {
2121 fprintf(stderr, "Error for %s failed\n", filename);
2122 return(-1);
2123 }
2124 } else if (options & XML_PARSE_DTDVALID) {
2125 if (testErrorsSize != 0)
2126 fprintf(stderr, "Validation for %s failed\n", filename);
2127 }
2128
2129 return(0);
2130}
2131
2132#ifdef LIBXML_READER_ENABLED
2133/************************************************************************
2134 * *
2135 * Reader based tests *
2136 * *
2137 ************************************************************************/
2138
2139static void processNode(FILE *out, xmlTextReaderPtr reader) {
2140 const xmlChar *name, *value;
2141 int type, empty;
2142
2143 type = xmlTextReaderNodeType(reader);
2144 empty = xmlTextReaderIsEmptyElement(reader);
2145
2146 name = xmlTextReaderConstName(reader);
2147 if (name == NULL)
2148 name = BAD_CAST "--";
2149
2150 value = xmlTextReaderConstValue(reader);
2151
Daniel Veillardaa6de472008-08-25 14:53:31 +00002152
2153 fprintf(out, "%d %d %s %d %d",
William M. Brackca15a542005-07-06 20:41:33 +00002154 xmlTextReaderDepth(reader),
2155 type,
2156 name,
2157 empty,
2158 xmlTextReaderHasValue(reader));
2159 if (value == NULL)
2160 fprintf(out, "\n");
2161 else {
2162 fprintf(out, " %s\n", value);
2163 }
2164}
2165static int
2166streamProcessTest(const char *filename, const char *result, const char *err,
Nick Wellnhofer81c01ee2017-06-17 14:12:53 +02002167 xmlTextReaderPtr reader, const char *rng,
2168 int options ATTRIBUTE_UNUSED) {
William M. Brackca15a542005-07-06 20:41:33 +00002169 int ret;
2170 char *temp = NULL;
2171 FILE *t = NULL;
2172
2173 if (reader == NULL)
2174 return(-1);
2175
2176 nb_tests++;
2177 if (result != NULL) {
2178 temp = resultFilename(filename, "", ".res");
2179 if (temp == NULL) {
2180 fprintf(stderr, "Out of memory\n");
2181 fatalError();
2182 }
2183 t = fopen(temp, "wb");
2184 if (t == NULL) {
2185 fprintf(stderr, "Can't open temp file %s\n", temp);
2186 free(temp);
2187 return(-1);
2188 }
2189 }
2190#ifdef LIBXML_SCHEMAS_ENABLED
2191 if (rng != NULL) {
2192 ret = xmlTextReaderRelaxNGValidate(reader, rng);
2193 if (ret < 0) {
2194 testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n",
2195 rng);
2196 fclose(t);
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002197 if (temp != NULL) {
2198 unlink(temp);
2199 free(temp);
2200 }
William M. Brackca15a542005-07-06 20:41:33 +00002201 return(0);
2202 }
2203 }
2204#endif
2205 xmlGetWarningsDefaultValue = 1;
2206 ret = xmlTextReaderRead(reader);
2207 while (ret == 1) {
2208 if ((t != NULL) && (rng == NULL))
2209 processNode(t, reader);
2210 ret = xmlTextReaderRead(reader);
2211 }
2212 if (ret != 0) {
2213 testErrorHandler(NULL, "%s : failed to parse\n", filename);
2214 }
2215 if (rng != NULL) {
2216 if (xmlTextReaderIsValid(reader) != 1) {
2217 testErrorHandler(NULL, "%s fails to validate\n", filename);
2218 } else {
2219 testErrorHandler(NULL, "%s validates\n", filename);
2220 }
2221 }
2222 xmlGetWarningsDefaultValue = 0;
2223 if (t != NULL) {
2224 fclose(t);
2225 ret = compareFiles(temp, result);
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002226 if (temp != NULL) {
2227 unlink(temp);
2228 free(temp);
2229 }
William M. Brackca15a542005-07-06 20:41:33 +00002230 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002231 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002232 return(-1);
2233 }
2234 }
2235 if (err != NULL) {
2236 ret = compareFileMem(err, testErrors, testErrorsSize);
2237 if (ret != 0) {
2238 fprintf(stderr, "Error for %s failed\n", filename);
2239 printf("%s", testErrors);
2240 return(-1);
2241 }
2242 }
2243
2244 return(0);
2245}
2246
2247/**
2248 * streamParseTest:
2249 * @filename: the file to parse
2250 * @result: the file with expected result
2251 * @err: the file with error messages
2252 *
2253 * Parse a file using the reader API and check for errors.
2254 *
2255 * Returns 0 in case of success, an error code otherwise
2256 */
2257static int
2258streamParseTest(const char *filename, const char *result, const char *err,
2259 int options) {
2260 xmlTextReaderPtr reader;
2261 int ret;
2262
2263 reader = xmlReaderForFile(filename, NULL, options);
Daniel Veillarda7982ce2012-10-25 15:39:39 +08002264 ret = streamProcessTest(filename, result, err, reader, NULL, options);
William M. Brackca15a542005-07-06 20:41:33 +00002265 xmlFreeTextReader(reader);
2266 return(ret);
2267}
2268
2269/**
2270 * walkerParseTest:
2271 * @filename: the file to parse
2272 * @result: the file with expected result
2273 * @err: the file with error messages
2274 *
2275 * Parse a file using the walker, i.e. a reader built from a atree.
2276 *
2277 * Returns 0 in case of success, an error code otherwise
2278 */
2279static int
2280walkerParseTest(const char *filename, const char *result, const char *err,
2281 int options) {
2282 xmlDocPtr doc;
2283 xmlTextReaderPtr reader;
2284 int ret;
2285
2286 doc = xmlReadFile(filename, NULL, options);
2287 if (doc == NULL) {
2288 fprintf(stderr, "Failed to parse %s\n", filename);
2289 return(-1);
2290 }
2291 reader = xmlReaderWalker(doc);
Daniel Veillarda7982ce2012-10-25 15:39:39 +08002292 ret = streamProcessTest(filename, result, err, reader, NULL, options);
William M. Brackca15a542005-07-06 20:41:33 +00002293 xmlFreeTextReader(reader);
2294 xmlFreeDoc(doc);
2295 return(ret);
2296}
2297
2298/**
2299 * streamMemParseTest:
2300 * @filename: the file to parse
2301 * @result: the file with expected result
2302 * @err: the file with error messages
2303 *
2304 * Parse a file using the reader API from memory and check for errors.
2305 *
2306 * Returns 0 in case of success, an error code otherwise
2307 */
2308static int
2309streamMemParseTest(const char *filename, const char *result, const char *err,
2310 int options) {
2311 xmlTextReaderPtr reader;
2312 int ret;
2313 const char *base;
2314 int size;
2315
2316 /*
2317 * load and parse the memory
2318 */
2319 if (loadMem(filename, &base, &size) != 0) {
2320 fprintf(stderr, "Failed to load %s\n", filename);
2321 return(-1);
2322 }
2323 reader = xmlReaderForMemory(base, size, filename, NULL, options);
Daniel Veillarda7982ce2012-10-25 15:39:39 +08002324 ret = streamProcessTest(filename, result, err, reader, NULL, options);
William M. Brackca15a542005-07-06 20:41:33 +00002325 free((char *)base);
2326 xmlFreeTextReader(reader);
2327 return(ret);
2328}
2329#endif
2330
2331#ifdef LIBXML_XPATH_ENABLED
2332#ifdef LIBXML_DEBUG_ENABLED
2333/************************************************************************
2334 * *
2335 * XPath and XPointer based tests *
2336 * *
2337 ************************************************************************/
2338
Daniel Veillard24505b02005-07-28 23:49:35 +00002339static FILE *xpathOutput;
2340static xmlDocPtr xpathDocument;
William M. Brackca15a542005-07-06 20:41:33 +00002341
2342static void
Nick Wellnhofer1fc55ca2016-06-25 12:35:09 +02002343ignoreGenericError(void *ctx ATTRIBUTE_UNUSED,
2344 const char *msg ATTRIBUTE_UNUSED, ...) {
2345}
2346
2347static void
William M. Brackca15a542005-07-06 20:41:33 +00002348testXPath(const char *str, int xptr, int expr) {
Nick Wellnhofer1fc55ca2016-06-25 12:35:09 +02002349 xmlGenericErrorFunc handler = ignoreGenericError;
William M. Brackca15a542005-07-06 20:41:33 +00002350 xmlXPathObjectPtr res;
2351 xmlXPathContextPtr ctxt;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002352
Nick Wellnhofer1fc55ca2016-06-25 12:35:09 +02002353 /* Don't print generic errors to stderr. */
2354 initGenericErrorDefaultFunc(&handler);
2355
William M. Brackca15a542005-07-06 20:41:33 +00002356 nb_tests++;
2357#if defined(LIBXML_XPTR_ENABLED)
2358 if (xptr) {
2359 ctxt = xmlXPtrNewContext(xpathDocument, NULL, NULL);
2360 res = xmlXPtrEval(BAD_CAST str, ctxt);
2361 } else {
2362#endif
2363 ctxt = xmlXPathNewContext(xpathDocument);
2364 ctxt->node = xmlDocGetRootElement(xpathDocument);
2365 if (expr)
2366 res = xmlXPathEvalExpression(BAD_CAST str, ctxt);
2367 else {
2368 /* res = xmlXPathEval(BAD_CAST str, ctxt); */
2369 xmlXPathCompExprPtr comp;
2370
2371 comp = xmlXPathCompile(BAD_CAST str);
2372 if (comp != NULL) {
2373 res = xmlXPathCompiledEval(comp, ctxt);
2374 xmlXPathFreeCompExpr(comp);
2375 } else
2376 res = NULL;
2377 }
2378#if defined(LIBXML_XPTR_ENABLED)
2379 }
2380#endif
2381 xmlXPathDebugDumpObject(xpathOutput, res, 0);
2382 xmlXPathFreeObject(res);
2383 xmlXPathFreeContext(ctxt);
Nick Wellnhofer1fc55ca2016-06-25 12:35:09 +02002384
2385 /* Reset generic error handler. */
2386 initGenericErrorDefaultFunc(NULL);
William M. Brackca15a542005-07-06 20:41:33 +00002387}
2388
2389/**
2390 * xpathExprTest:
2391 * @filename: the file to parse
2392 * @result: the file with expected result
2393 * @err: the file with error messages
2394 *
2395 * Parse a file containing XPath standalone expressions and evaluate them
2396 *
2397 * Returns 0 in case of success, an error code otherwise
2398 */
2399static int
2400xpathCommonTest(const char *filename, const char *result,
2401 int xptr, int expr) {
2402 FILE *input;
2403 char expression[5000];
2404 int len, ret = 0;
2405 char *temp;
2406
2407 temp = resultFilename(filename, "", ".res");
2408 if (temp == NULL) {
2409 fprintf(stderr, "Out of memory\n");
2410 fatalError();
2411 }
2412 xpathOutput = fopen(temp, "wb");
2413 if (xpathOutput == NULL) {
2414 fprintf(stderr, "failed to open output file %s\n", temp);
2415 free(temp);
2416 return(-1);
2417 }
2418
2419 input = fopen(filename, "rb");
2420 if (input == NULL) {
2421 xmlGenericError(xmlGenericErrorContext,
2422 "Cannot open %s for reading\n", filename);
2423 free(temp);
2424 return(-1);
2425 }
2426 while (fgets(expression, 4500, input) != NULL) {
2427 len = strlen(expression);
2428 len--;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002429 while ((len >= 0) &&
William M. Brackca15a542005-07-06 20:41:33 +00002430 ((expression[len] == '\n') || (expression[len] == '\t') ||
2431 (expression[len] == '\r') || (expression[len] == ' '))) len--;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002432 expression[len + 1] = 0;
William M. Brackca15a542005-07-06 20:41:33 +00002433 if (len >= 0) {
2434 fprintf(xpathOutput,
2435 "\n========================\nExpression: %s\n",
2436 expression) ;
2437 testXPath(expression, xptr, expr);
2438 }
2439 }
2440
2441 fclose(input);
2442 fclose(xpathOutput);
2443 if (result != NULL) {
2444 ret = compareFiles(temp, result);
2445 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002446 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002447 }
2448 }
2449
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002450 if (temp != NULL) {
2451 unlink(temp);
2452 free(temp);
2453 }
William M. Brackca15a542005-07-06 20:41:33 +00002454 return(ret);
2455}
2456
2457/**
2458 * xpathExprTest:
2459 * @filename: the file to parse
2460 * @result: the file with expected result
2461 * @err: the file with error messages
2462 *
2463 * Parse a file containing XPath standalone expressions and evaluate them
2464 *
2465 * Returns 0 in case of success, an error code otherwise
2466 */
2467static int
2468xpathExprTest(const char *filename, const char *result,
2469 const char *err ATTRIBUTE_UNUSED,
2470 int options ATTRIBUTE_UNUSED) {
2471 return(xpathCommonTest(filename, result, 0, 1));
2472}
2473
2474/**
2475 * xpathDocTest:
2476 * @filename: the file to parse
2477 * @result: the file with expected result
2478 * @err: the file with error messages
2479 *
2480 * Parse a file containing XPath expressions and evaluate them against
2481 * a set of corresponding documents.
2482 *
2483 * Returns 0 in case of success, an error code otherwise
2484 */
2485static int
2486xpathDocTest(const char *filename,
2487 const char *resul ATTRIBUTE_UNUSED,
2488 const char *err ATTRIBUTE_UNUSED,
2489 int options) {
2490
2491 char pattern[500];
2492 char result[500];
2493 glob_t globbuf;
2494 size_t i;
2495 int ret = 0, res;
2496
2497 xpathDocument = xmlReadFile(filename, NULL,
2498 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2499 if (xpathDocument == NULL) {
2500 fprintf(stderr, "Failed to load %s\n", filename);
2501 return(-1);
2502 }
2503
2504 snprintf(pattern, 499, "./test/XPath/tests/%s*", baseFilename(filename));
2505 pattern[499] = 0;
2506 globbuf.gl_offs = 0;
2507 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2508 for (i = 0;i < globbuf.gl_pathc;i++) {
2509 snprintf(result, 499, "result/XPath/tests/%s",
2510 baseFilename(globbuf.gl_pathv[i]));
2511 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 0, 0);
2512 if (res != 0)
2513 ret = res;
2514 }
2515 globfree(&globbuf);
2516
2517 xmlFreeDoc(xpathDocument);
2518 return(ret);
2519}
2520
2521#ifdef LIBXML_XPTR_ENABLED
2522/**
2523 * xptrDocTest:
2524 * @filename: the file to parse
2525 * @result: the file with expected result
2526 * @err: the file with error messages
2527 *
2528 * Parse a file containing XPath expressions and evaluate them against
2529 * a set of corresponding documents.
2530 *
2531 * Returns 0 in case of success, an error code otherwise
2532 */
2533static int
2534xptrDocTest(const char *filename,
2535 const char *resul ATTRIBUTE_UNUSED,
2536 const char *err ATTRIBUTE_UNUSED,
2537 int options) {
2538
2539 char pattern[500];
2540 char result[500];
2541 glob_t globbuf;
2542 size_t i;
2543 int ret = 0, res;
2544
2545 xpathDocument = xmlReadFile(filename, NULL,
2546 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2547 if (xpathDocument == NULL) {
2548 fprintf(stderr, "Failed to load %s\n", filename);
2549 return(-1);
2550 }
2551
2552 snprintf(pattern, 499, "./test/XPath/xptr/%s*", baseFilename(filename));
2553 pattern[499] = 0;
2554 globbuf.gl_offs = 0;
2555 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2556 for (i = 0;i < globbuf.gl_pathc;i++) {
2557 snprintf(result, 499, "result/XPath/xptr/%s",
2558 baseFilename(globbuf.gl_pathv[i]));
2559 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 1, 0);
2560 if (res != 0)
2561 ret = res;
2562 }
2563 globfree(&globbuf);
2564
2565 xmlFreeDoc(xpathDocument);
2566 return(ret);
2567}
2568#endif /* LIBXML_XPTR_ENABLED */
2569
2570/**
2571 * xmlidDocTest:
2572 * @filename: the file to parse
2573 * @result: the file with expected result
2574 * @err: the file with error messages
2575 *
2576 * Parse a file containing xml:id and check for errors and verify
2577 * that XPath queries will work on them as expected.
2578 *
2579 * Returns 0 in case of success, an error code otherwise
2580 */
2581static int
2582xmlidDocTest(const char *filename,
2583 const char *result,
2584 const char *err,
2585 int options) {
2586
2587 int res = 0;
2588 int ret = 0;
2589 char *temp;
2590
2591 xpathDocument = xmlReadFile(filename, NULL,
2592 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2593 if (xpathDocument == NULL) {
2594 fprintf(stderr, "Failed to load %s\n", filename);
2595 return(-1);
2596 }
2597
2598 temp = resultFilename(filename, "", ".res");
2599 if (temp == NULL) {
2600 fprintf(stderr, "Out of memory\n");
2601 fatalError();
2602 }
2603 xpathOutput = fopen(temp, "wb");
2604 if (xpathOutput == NULL) {
2605 fprintf(stderr, "failed to open output file %s\n", temp);
2606 xmlFreeDoc(xpathDocument);
2607 free(temp);
2608 return(-1);
2609 }
2610
2611 testXPath("id('bar')", 0, 0);
2612
2613 fclose(xpathOutput);
2614 if (result != NULL) {
2615 ret = compareFiles(temp, result);
2616 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002617 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002618 res = 1;
2619 }
2620 }
2621
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002622 if (temp != NULL) {
2623 unlink(temp);
2624 free(temp);
2625 }
William M. Brackca15a542005-07-06 20:41:33 +00002626 xmlFreeDoc(xpathDocument);
2627
2628 if (err != NULL) {
2629 ret = compareFileMem(err, testErrors, testErrorsSize);
2630 if (ret != 0) {
2631 fprintf(stderr, "Error for %s failed\n", filename);
2632 res = 1;
2633 }
2634 }
2635 return(res);
2636}
2637
2638#endif /* LIBXML_DEBUG_ENABLED */
2639#endif /* XPATH */
2640/************************************************************************
2641 * *
2642 * URI based tests *
2643 * *
2644 ************************************************************************/
2645
2646static void
2647handleURI(const char *str, const char *base, FILE *o) {
2648 int ret;
2649 xmlURIPtr uri;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002650 xmlChar *res = NULL;
William M. Brackca15a542005-07-06 20:41:33 +00002651
2652 uri = xmlCreateURI();
2653
2654 if (base == NULL) {
2655 ret = xmlParseURIReference(uri, str);
2656 if (ret != 0)
2657 fprintf(o, "%s : error %d\n", str, ret);
2658 else {
2659 xmlNormalizeURIPath(uri->path);
2660 xmlPrintURI(o, uri);
2661 fprintf(o, "\n");
2662 }
2663 } else {
2664 res = xmlBuildURI((xmlChar *)str, (xmlChar *) base);
2665 if (res != NULL) {
2666 fprintf(o, "%s\n", (char *) res);
2667 }
2668 else
2669 fprintf(o, "::ERROR::\n");
2670 }
2671 if (res != NULL)
2672 xmlFree(res);
William M. Brackca15a542005-07-06 20:41:33 +00002673 xmlFreeURI(uri);
2674}
2675
2676/**
2677 * uriCommonTest:
2678 * @filename: the file to parse
2679 * @result: the file with expected result
2680 * @err: the file with error messages
2681 *
2682 * Parse a file containing URI and check for errors
2683 *
2684 * Returns 0 in case of success, an error code otherwise
2685 */
2686static int
2687uriCommonTest(const char *filename,
2688 const char *result,
2689 const char *err,
2690 const char *base) {
2691 char *temp;
2692 FILE *o, *f;
2693 char str[1024];
2694 int res = 0, i, ret;
2695
2696 temp = resultFilename(filename, "", ".res");
2697 if (temp == NULL) {
2698 fprintf(stderr, "Out of memory\n");
2699 fatalError();
2700 }
2701 o = fopen(temp, "wb");
2702 if (o == NULL) {
2703 fprintf(stderr, "failed to open output file %s\n", temp);
2704 free(temp);
2705 return(-1);
2706 }
2707 f = fopen(filename, "rb");
2708 if (f == NULL) {
2709 fprintf(stderr, "failed to open input file %s\n", filename);
2710 fclose(o);
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002711 if (temp != NULL) {
2712 unlink(temp);
2713 free(temp);
2714 }
William M. Brackca15a542005-07-06 20:41:33 +00002715 return(-1);
2716 }
2717
2718 while (1) {
2719 /*
2720 * read one line in string buffer.
2721 */
2722 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
2723 break;
2724
2725 /*
2726 * remove the ending spaces
2727 */
2728 i = strlen(str);
2729 while ((i > 0) &&
2730 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
2731 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
2732 i--;
2733 str[i] = 0;
2734 }
2735 nb_tests++;
2736 handleURI(str, base, o);
2737 }
2738
2739 fclose(f);
2740 fclose(o);
2741
2742 if (result != NULL) {
2743 ret = compareFiles(temp, result);
2744 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002745 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002746 res = 1;
2747 }
2748 }
2749 if (err != NULL) {
2750 ret = compareFileMem(err, testErrors, testErrorsSize);
2751 if (ret != 0) {
2752 fprintf(stderr, "Error for %s failed\n", filename);
2753 res = 1;
2754 }
2755 }
2756
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002757 if (temp != NULL) {
2758 unlink(temp);
2759 free(temp);
2760 }
William M. Brackca15a542005-07-06 20:41:33 +00002761 return(res);
2762}
2763
2764/**
2765 * uriParseTest:
2766 * @filename: the file to parse
2767 * @result: the file with expected result
2768 * @err: the file with error messages
2769 *
2770 * Parse a file containing URI and check for errors
2771 *
2772 * Returns 0 in case of success, an error code otherwise
2773 */
2774static int
2775uriParseTest(const char *filename,
2776 const char *result,
2777 const char *err,
2778 int options ATTRIBUTE_UNUSED) {
2779 return(uriCommonTest(filename, result, err, NULL));
2780}
2781
2782/**
2783 * uriBaseTest:
2784 * @filename: the file to parse
2785 * @result: the file with expected result
2786 * @err: the file with error messages
2787 *
2788 * Parse a file containing URI, compose them against a fixed base and
2789 * check for errors
2790 *
2791 * Returns 0 in case of success, an error code otherwise
2792 */
2793static int
2794uriBaseTest(const char *filename,
2795 const char *result,
2796 const char *err,
2797 int options ATTRIBUTE_UNUSED) {
2798 return(uriCommonTest(filename, result, err,
2799 "http://foo.com/path/to/index.html?orig#help"));
2800}
2801
Daniel Veillard336a8e12005-08-07 10:46:19 +00002802static int urip_success = 1;
2803static int urip_current = 0;
2804static const char *urip_testURLs[] = {
2805 "urip://example.com/a b.html",
2806 "urip://example.com/a%20b.html",
2807 "file:///path/to/a b.html",
2808 "file:///path/to/a%20b.html",
2809 "/path/to/a b.html",
2810 "/path/to/a%20b.html",
Daniel Veillardff7227f2012-08-20 20:58:24 +08002811 "urip://example.com/r" "\xe9" "sum" "\xe9" ".html",
Daniel Veillard336a8e12005-08-07 10:46:19 +00002812 "urip://example.com/test?a=1&b=2%263&c=4#foo",
2813 NULL
2814};
2815static const char *urip_rcvsURLs[] = {
2816 /* it is an URI the strings must be escaped */
2817 "urip://example.com/a%20b.html",
2818 /* check that % escaping is not broken */
2819 "urip://example.com/a%20b.html",
2820 /* it's an URI path the strings must be escaped */
2821 "file:///path/to/a%20b.html",
2822 /* check that % escaping is not broken */
2823 "file:///path/to/a%20b.html",
2824 /* this is not an URI, this is a path, so this should not be escaped */
2825 "/path/to/a b.html",
2826 /* check that paths with % are not broken */
2827 "/path/to/a%20b.html",
2828 /* out of context the encoding can't be guessed byte by byte conversion */
2829 "urip://example.com/r%E9sum%E9.html",
2830 /* verify we don't destroy URIs especially the query part */
2831 "urip://example.com/test?a=1&b=2%263&c=4#foo",
2832 NULL
2833};
2834static const char *urip_res = "<list/>";
2835static const char *urip_cur = NULL;
2836static int urip_rlen;
2837
2838/**
2839 * uripMatch:
2840 * @URI: an URI to test
2841 *
2842 * Check for an urip: query
2843 *
2844 * Returns 1 if yes and 0 if another Input module should be used
2845 */
2846static int
2847uripMatch(const char * URI) {
2848 if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog")))
2849 return(0);
2850 /* Verify we received the escaped URL */
2851 if (strcmp(urip_rcvsURLs[urip_current], URI))
2852 urip_success = 0;
2853 return(1);
2854}
2855
2856/**
2857 * uripOpen:
2858 * @URI: an URI to test
2859 *
2860 * Return a pointer to the urip: query handler, in this example simply
2861 * the urip_current pointer...
2862 *
2863 * Returns an Input context or NULL in case or error
2864 */
2865static void *
2866uripOpen(const char * URI) {
2867 if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog")))
2868 return(NULL);
2869 /* Verify we received the escaped URL */
2870 if (strcmp(urip_rcvsURLs[urip_current], URI))
2871 urip_success = 0;
2872 urip_cur = urip_res;
2873 urip_rlen = strlen(urip_res);
2874 return((void *) urip_cur);
2875}
2876
2877/**
2878 * uripClose:
2879 * @context: the read context
2880 *
2881 * Close the urip: query handler
2882 *
2883 * Returns 0 or -1 in case of error
2884 */
2885static int
2886uripClose(void * context) {
2887 if (context == NULL) return(-1);
2888 urip_cur = NULL;
2889 urip_rlen = 0;
2890 return(0);
2891}
2892
2893/**
2894 * uripRead:
2895 * @context: the read context
2896 * @buffer: where to store data
2897 * @len: number of bytes to read
2898 *
2899 * Implement an urip: query read.
2900 *
2901 * Returns the number of bytes read or -1 in case of error
2902 */
2903static int
2904uripRead(void * context, char * buffer, int len) {
2905 const char *ptr = (const char *) context;
2906
2907 if ((context == NULL) || (buffer == NULL) || (len < 0))
2908 return(-1);
2909
2910 if (len > urip_rlen) len = urip_rlen;
2911 memcpy(buffer, ptr, len);
2912 urip_rlen -= len;
2913 return(len);
2914}
2915
2916static int
2917urip_checkURL(const char *URL) {
2918 xmlDocPtr doc;
2919
2920 doc = xmlReadFile(URL, NULL, 0);
2921 if (doc == NULL)
2922 return(-1);
2923 xmlFreeDoc(doc);
2924 return(1);
2925}
2926
2927/**
2928 * uriPathTest:
2929 * @filename: ignored
2930 * @result: ignored
2931 * @err: ignored
2932 *
2933 * Run a set of tests to check how Path and URI are handled before
2934 * being passed to the I/O layer
2935 *
2936 * Returns 0 in case of success, an error code otherwise
2937 */
2938static int
2939uriPathTest(const char *filename ATTRIBUTE_UNUSED,
2940 const char *result ATTRIBUTE_UNUSED,
2941 const char *err ATTRIBUTE_UNUSED,
2942 int options ATTRIBUTE_UNUSED) {
2943 int parsed;
2944 int failures = 0;
2945
2946 /*
2947 * register the new I/O handlers
2948 */
2949 if (xmlRegisterInputCallbacks(uripMatch, uripOpen, uripRead, uripClose) < 0)
2950 {
2951 fprintf(stderr, "failed to register HTTP handler\n");
2952 return(-1);
2953 }
2954
2955 for (urip_current = 0;urip_testURLs[urip_current] != NULL;urip_current++) {
2956 urip_success = 1;
2957 parsed = urip_checkURL(urip_testURLs[urip_current]);
2958 if (urip_success != 1) {
2959 fprintf(stderr, "failed the URL passing test for %s",
2960 urip_testURLs[urip_current]);
2961 failures++;
2962 } else if (parsed != 1) {
2963 fprintf(stderr, "failed the parsing test for %s",
2964 urip_testURLs[urip_current]);
2965 failures++;
2966 }
2967 nb_tests++;
2968 }
2969
2970 xmlPopInputCallbacks();
2971 return(failures);
2972}
2973
William M. Brackca15a542005-07-06 20:41:33 +00002974#ifdef LIBXML_SCHEMAS_ENABLED
2975/************************************************************************
2976 * *
2977 * Schemas tests *
2978 * *
2979 ************************************************************************/
2980static int
2981schemasOneTest(const char *sch,
2982 const char *filename,
2983 const char *result,
2984 const char *err,
2985 int options,
2986 xmlSchemaPtr schemas) {
2987 xmlDocPtr doc;
2988 xmlSchemaValidCtxtPtr ctxt;
2989 int ret = 0;
Daniel Veillard381ff362006-06-18 17:31:31 +00002990 int validResult = 0;
William M. Brackca15a542005-07-06 20:41:33 +00002991 char *temp;
2992 FILE *schemasOutput;
2993
2994 doc = xmlReadFile(filename, NULL, options);
2995 if (doc == NULL) {
2996 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
2997 return(-1);
2998 }
2999
3000 temp = resultFilename(result, "", ".res");
3001 if (temp == NULL) {
3002 fprintf(stderr, "Out of memory\n");
3003 fatalError();
3004 }
3005 schemasOutput = fopen(temp, "wb");
3006 if (schemasOutput == NULL) {
3007 fprintf(stderr, "failed to open output file %s\n", temp);
3008 xmlFreeDoc(doc);
3009 free(temp);
3010 return(-1);
3011 }
3012
3013 ctxt = xmlSchemaNewValidCtxt(schemas);
3014 xmlSchemaSetValidErrors(ctxt,
3015 (xmlSchemaValidityErrorFunc) testErrorHandler,
3016 (xmlSchemaValidityWarningFunc) testErrorHandler,
3017 ctxt);
Daniel Veillard381ff362006-06-18 17:31:31 +00003018 validResult = xmlSchemaValidateDoc(ctxt, doc);
3019 if (validResult == 0) {
William M. Brackca15a542005-07-06 20:41:33 +00003020 fprintf(schemasOutput, "%s validates\n", filename);
Daniel Veillard381ff362006-06-18 17:31:31 +00003021 } else if (validResult > 0) {
William M. Brackca15a542005-07-06 20:41:33 +00003022 fprintf(schemasOutput, "%s fails to validate\n", filename);
3023 } else {
3024 fprintf(schemasOutput, "%s validation generated an internal error\n",
3025 filename);
3026 }
3027 fclose(schemasOutput);
3028 if (result) {
3029 if (compareFiles(temp, result)) {
3030 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
3031 ret = 1;
3032 }
3033 }
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003034 if (temp != NULL) {
3035 unlink(temp);
3036 free(temp);
3037 }
William M. Brackca15a542005-07-06 20:41:33 +00003038
Daniel Veillard381ff362006-06-18 17:31:31 +00003039 if ((validResult != 0) && (err != NULL)) {
William M. Brackca15a542005-07-06 20:41:33 +00003040 if (compareFileMem(err, testErrors, testErrorsSize)) {
3041 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
3042 ret = 1;
3043 }
3044 }
3045
William M. Brackca15a542005-07-06 20:41:33 +00003046 xmlSchemaFreeValidCtxt(ctxt);
3047 xmlFreeDoc(doc);
3048 return(ret);
3049}
3050/**
3051 * schemasTest:
3052 * @filename: the schemas file
3053 * @result: the file with expected result
3054 * @err: the file with error messages
3055 *
3056 * Parse a file containing URI, compose them against a fixed base and
3057 * check for errors
3058 *
3059 * Returns 0 in case of success, an error code otherwise
3060 */
3061static int
3062schemasTest(const char *filename,
3063 const char *resul ATTRIBUTE_UNUSED,
3064 const char *errr ATTRIBUTE_UNUSED,
3065 int options) {
3066 const char *base = baseFilename(filename);
3067 const char *base2;
3068 const char *instance;
3069 xmlSchemaParserCtxtPtr ctxt;
3070 xmlSchemaPtr schemas;
3071 int res = 0, len, ret;
3072 char pattern[500];
3073 char prefix[500];
3074 char result[500];
3075 char err[500];
3076 glob_t globbuf;
3077 size_t i;
3078 char count = 0;
3079
3080 /* first compile the schemas if possible */
3081 ctxt = xmlSchemaNewParserCtxt(filename);
3082 xmlSchemaSetParserErrors(ctxt,
3083 (xmlSchemaValidityErrorFunc) testErrorHandler,
3084 (xmlSchemaValidityWarningFunc) testErrorHandler,
3085 ctxt);
3086 schemas = xmlSchemaParse(ctxt);
3087 xmlSchemaFreeParserCtxt(ctxt);
3088
3089 /*
3090 * most of the mess is about the output filenames generated by the Makefile
3091 */
3092 len = strlen(base);
3093 if ((len > 499) || (len < 5)) {
3094 xmlSchemaFree(schemas);
3095 return(-1);
3096 }
3097 len -= 4; /* remove trailing .xsd */
3098 if (base[len - 2] == '_') {
3099 len -= 2; /* remove subtest number */
3100 }
3101 if (base[len - 2] == '_') {
3102 len -= 2; /* remove subtest number */
3103 }
3104 memcpy(prefix, base, len);
3105 prefix[len] = 0;
3106
3107 snprintf(pattern, 499, "./test/schemas/%s_?.xml", prefix);
3108 pattern[499] = 0;
3109
3110 if (base[len] == '_') {
3111 len += 2;
3112 memcpy(prefix, base, len);
3113 prefix[len] = 0;
3114 }
3115
3116 globbuf.gl_offs = 0;
3117 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3118 for (i = 0;i < globbuf.gl_pathc;i++) {
3119 testErrorsSize = 0;
3120 testErrors[0] = 0;
3121 instance = globbuf.gl_pathv[i];
3122 base2 = baseFilename(instance);
3123 len = strlen(base2);
3124 if ((len > 6) && (base2[len - 6] == '_')) {
3125 count = base2[len - 5];
3126 snprintf(result, 499, "result/schemas/%s_%c",
3127 prefix, count);
3128 result[499] = 0;
3129 snprintf(err, 499, "result/schemas/%s_%c.err",
3130 prefix, count);
3131 err[499] = 0;
3132 } else {
3133 fprintf(stderr, "don't know how to process %s\n", instance);
3134 continue;
3135 }
3136 if (schemas == NULL) {
3137 } else {
3138 nb_tests++;
3139 ret = schemasOneTest(filename, instance, result, err,
3140 options, schemas);
Daniel Veillard93e577f2005-11-15 08:50:04 +00003141 if (ret != 0)
3142 res = ret;
William M. Brackca15a542005-07-06 20:41:33 +00003143 }
3144 }
3145 globfree(&globbuf);
3146 xmlSchemaFree(schemas);
3147
3148 return(res);
3149}
3150
3151/************************************************************************
3152 * *
3153 * Schemas tests *
3154 * *
3155 ************************************************************************/
3156static int
3157rngOneTest(const char *sch,
3158 const char *filename,
3159 const char *result,
3160 const char *err,
3161 int options,
3162 xmlRelaxNGPtr schemas) {
3163 xmlDocPtr doc;
3164 xmlRelaxNGValidCtxtPtr ctxt;
3165 int ret = 0;
3166 char *temp;
3167 FILE *schemasOutput;
3168
3169 doc = xmlReadFile(filename, NULL, options);
3170 if (doc == NULL) {
3171 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
3172 return(-1);
3173 }
3174
3175 temp = resultFilename(result, "", ".res");
3176 if (temp == NULL) {
3177 fprintf(stderr, "Out of memory\n");
3178 fatalError();
3179 }
3180 schemasOutput = fopen(temp, "wb");
3181 if (schemasOutput == NULL) {
3182 fprintf(stderr, "failed to open output file %s\n", temp);
3183 xmlFreeDoc(doc);
3184 free(temp);
3185 return(-1);
3186 }
3187
3188 ctxt = xmlRelaxNGNewValidCtxt(schemas);
3189 xmlRelaxNGSetValidErrors(ctxt,
3190 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
3191 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
3192 ctxt);
3193 ret = xmlRelaxNGValidateDoc(ctxt, doc);
3194 if (ret == 0) {
3195 testErrorHandler(NULL, "%s validates\n", filename);
3196 } else if (ret > 0) {
3197 testErrorHandler(NULL, "%s fails to validate\n", filename);
3198 } else {
3199 testErrorHandler(NULL, "%s validation generated an internal error\n",
3200 filename);
3201 }
3202 fclose(schemasOutput);
Daniel Veillard594e5df2009-09-07 14:58:47 +02003203 ret = 0;
William M. Brackca15a542005-07-06 20:41:33 +00003204 if (result) {
3205 if (compareFiles(temp, result)) {
3206 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
3207 ret = 1;
3208 }
3209 }
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003210 if (temp != NULL) {
3211 unlink(temp);
3212 free(temp);
3213 }
William M. Brackca15a542005-07-06 20:41:33 +00003214
3215 if (err != NULL) {
3216 if (compareFileMem(err, testErrors, testErrorsSize)) {
3217 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
3218 ret = 1;
3219 printf("%s", testErrors);
3220 }
3221 }
3222
3223
3224 xmlRelaxNGFreeValidCtxt(ctxt);
3225 xmlFreeDoc(doc);
3226 return(ret);
3227}
3228/**
3229 * rngTest:
3230 * @filename: the schemas file
3231 * @result: the file with expected result
3232 * @err: the file with error messages
3233 *
3234 * Parse an RNG schemas and then apply it to the related .xml
3235 *
3236 * Returns 0 in case of success, an error code otherwise
3237 */
3238static int
3239rngTest(const char *filename,
3240 const char *resul ATTRIBUTE_UNUSED,
3241 const char *errr ATTRIBUTE_UNUSED,
3242 int options) {
3243 const char *base = baseFilename(filename);
3244 const char *base2;
3245 const char *instance;
3246 xmlRelaxNGParserCtxtPtr ctxt;
3247 xmlRelaxNGPtr schemas;
Rob Richardsc9667902010-01-22 08:24:25 -05003248 int res = 0, len, ret = 0;
William M. Brackca15a542005-07-06 20:41:33 +00003249 char pattern[500];
3250 char prefix[500];
3251 char result[500];
3252 char err[500];
3253 glob_t globbuf;
3254 size_t i;
3255 char count = 0;
3256
3257 /* first compile the schemas if possible */
3258 ctxt = xmlRelaxNGNewParserCtxt(filename);
3259 xmlRelaxNGSetParserErrors(ctxt,
3260 (xmlRelaxNGValidityErrorFunc) testErrorHandler,
3261 (xmlRelaxNGValidityWarningFunc) testErrorHandler,
3262 ctxt);
3263 schemas = xmlRelaxNGParse(ctxt);
3264 xmlRelaxNGFreeParserCtxt(ctxt);
3265
3266 /*
3267 * most of the mess is about the output filenames generated by the Makefile
3268 */
3269 len = strlen(base);
3270 if ((len > 499) || (len < 5)) {
3271 xmlRelaxNGFree(schemas);
3272 return(-1);
3273 }
3274 len -= 4; /* remove trailing .rng */
3275 memcpy(prefix, base, len);
3276 prefix[len] = 0;
3277
3278 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
3279 pattern[499] = 0;
3280
3281 globbuf.gl_offs = 0;
3282 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3283 for (i = 0;i < globbuf.gl_pathc;i++) {
3284 testErrorsSize = 0;
3285 testErrors[0] = 0;
3286 instance = globbuf.gl_pathv[i];
3287 base2 = baseFilename(instance);
3288 len = strlen(base2);
3289 if ((len > 6) && (base2[len - 6] == '_')) {
3290 count = base2[len - 5];
3291 snprintf(result, 499, "result/relaxng/%s_%c",
3292 prefix, count);
3293 result[499] = 0;
3294 snprintf(err, 499, "result/relaxng/%s_%c.err",
3295 prefix, count);
3296 err[499] = 0;
3297 } else {
3298 fprintf(stderr, "don't know how to process %s\n", instance);
3299 continue;
3300 }
3301 if (schemas == NULL) {
3302 } else {
3303 nb_tests++;
3304 ret = rngOneTest(filename, instance, result, err,
3305 options, schemas);
3306 if (res != 0)
3307 ret = res;
3308 }
3309 }
3310 globfree(&globbuf);
3311 xmlRelaxNGFree(schemas);
3312
Daniel Veillard594e5df2009-09-07 14:58:47 +02003313 return(ret);
William M. Brackca15a542005-07-06 20:41:33 +00003314}
3315
3316#ifdef LIBXML_READER_ENABLED
3317/**
3318 * rngStreamTest:
3319 * @filename: the schemas file
3320 * @result: the file with expected result
3321 * @err: the file with error messages
3322 *
Daniel Veillardaa6de472008-08-25 14:53:31 +00003323 * Parse a set of files with streaming, applying an RNG schemas
William M. Brackca15a542005-07-06 20:41:33 +00003324 *
3325 * Returns 0 in case of success, an error code otherwise
3326 */
3327static int
3328rngStreamTest(const char *filename,
3329 const char *resul ATTRIBUTE_UNUSED,
3330 const char *errr ATTRIBUTE_UNUSED,
3331 int options) {
3332 const char *base = baseFilename(filename);
3333 const char *base2;
3334 const char *instance;
3335 int res = 0, len, ret;
3336 char pattern[500];
3337 char prefix[500];
3338 char result[500];
3339 char err[500];
3340 glob_t globbuf;
3341 size_t i;
3342 char count = 0;
3343 xmlTextReaderPtr reader;
3344 int disable_err = 0;
3345
3346 /*
3347 * most of the mess is about the output filenames generated by the Makefile
3348 */
3349 len = strlen(base);
3350 if ((len > 499) || (len < 5)) {
3351 fprintf(stderr, "len(base) == %d !\n", len);
3352 return(-1);
3353 }
3354 len -= 4; /* remove trailing .rng */
3355 memcpy(prefix, base, len);
3356 prefix[len] = 0;
3357
3358 /*
3359 * strictly unifying the error messages is nearly impossible this
3360 * hack is also done in the Makefile
3361 */
3362 if ((!strcmp(prefix, "tutor10_1")) || (!strcmp(prefix, "tutor10_2")) ||
Daniel Veillardec18c962009-08-26 18:37:43 +02003363 (!strcmp(prefix, "tutor3_2")) || (!strcmp(prefix, "307377")) ||
3364 (!strcmp(prefix, "tutor8_2")))
William M. Brackca15a542005-07-06 20:41:33 +00003365 disable_err = 1;
3366
3367 snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
3368 pattern[499] = 0;
3369
3370 globbuf.gl_offs = 0;
3371 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3372 for (i = 0;i < globbuf.gl_pathc;i++) {
3373 testErrorsSize = 0;
3374 testErrors[0] = 0;
3375 instance = globbuf.gl_pathv[i];
3376 base2 = baseFilename(instance);
3377 len = strlen(base2);
3378 if ((len > 6) && (base2[len - 6] == '_')) {
3379 count = base2[len - 5];
3380 snprintf(result, 499, "result/relaxng/%s_%c",
3381 prefix, count);
3382 result[499] = 0;
3383 snprintf(err, 499, "result/relaxng/%s_%c.err",
3384 prefix, count);
3385 err[499] = 0;
3386 } else {
3387 fprintf(stderr, "don't know how to process %s\n", instance);
3388 continue;
3389 }
3390 reader = xmlReaderForFile(instance, NULL, options);
3391 if (reader == NULL) {
3392 fprintf(stderr, "Failed to build reder for %s\n", instance);
3393 }
3394 if (disable_err == 1)
Daniel Veillarda7982ce2012-10-25 15:39:39 +08003395 ret = streamProcessTest(instance, result, NULL, reader, filename,
3396 options);
William M. Brackca15a542005-07-06 20:41:33 +00003397 else
Daniel Veillarda7982ce2012-10-25 15:39:39 +08003398 ret = streamProcessTest(instance, result, err, reader, filename,
3399 options);
William M. Brackca15a542005-07-06 20:41:33 +00003400 xmlFreeTextReader(reader);
3401 if (ret != 0) {
3402 fprintf(stderr, "instance %s failed\n", instance);
3403 res = ret;
3404 }
3405 }
3406 globfree(&globbuf);
3407
3408 return(res);
3409}
3410#endif /* READER */
3411
3412#endif
3413
3414#ifdef LIBXML_PATTERN_ENABLED
3415#ifdef LIBXML_READER_ENABLED
3416/************************************************************************
3417 * *
3418 * Patterns tests *
3419 * *
3420 ************************************************************************/
3421static void patternNode(FILE *out, xmlTextReaderPtr reader,
3422 const char *pattern, xmlPatternPtr patternc,
3423 xmlStreamCtxtPtr patstream) {
3424 xmlChar *path = NULL;
3425 int match = -1;
3426 int type, empty;
3427
3428 type = xmlTextReaderNodeType(reader);
3429 empty = xmlTextReaderIsEmptyElement(reader);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003430
William M. Brackca15a542005-07-06 20:41:33 +00003431 if (type == XML_READER_TYPE_ELEMENT) {
3432 /* do the check only on element start */
3433 match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader));
3434
3435 if (match) {
3436 path = xmlGetNodePath(xmlTextReaderCurrentNode(reader));
3437 fprintf(out, "Node %s matches pattern %s\n", path, pattern);
3438 }
3439 }
3440 if (patstream != NULL) {
3441 int ret;
3442
3443 if (type == XML_READER_TYPE_ELEMENT) {
3444 ret = xmlStreamPush(patstream,
3445 xmlTextReaderConstLocalName(reader),
3446 xmlTextReaderConstNamespaceUri(reader));
3447 if (ret < 0) {
3448 fprintf(out, "xmlStreamPush() failure\n");
3449 xmlFreeStreamCtxt(patstream);
3450 patstream = NULL;
3451 } else if (ret != match) {
3452 if (path == NULL) {
3453 path = xmlGetNodePath(
3454 xmlTextReaderCurrentNode(reader));
3455 }
3456 fprintf(out,
3457 "xmlPatternMatch and xmlStreamPush disagree\n");
3458 fprintf(out,
3459 " pattern %s node %s\n",
3460 pattern, path);
3461 }
William M. Brackca15a542005-07-06 20:41:33 +00003462
Daniel Veillardaa6de472008-08-25 14:53:31 +00003463
3464 }
William M. Brackca15a542005-07-06 20:41:33 +00003465 if ((type == XML_READER_TYPE_END_ELEMENT) ||
3466 ((type == XML_READER_TYPE_ELEMENT) && (empty))) {
3467 ret = xmlStreamPop(patstream);
3468 if (ret < 0) {
3469 fprintf(out, "xmlStreamPop() failure\n");
3470 xmlFreeStreamCtxt(patstream);
3471 patstream = NULL;
3472 }
3473 }
3474 }
3475 if (path != NULL)
3476 xmlFree(path);
3477}
3478
3479/**
3480 * patternTest:
3481 * @filename: the schemas file
3482 * @result: the file with expected result
3483 * @err: the file with error messages
3484 *
Daniel Veillardaa6de472008-08-25 14:53:31 +00003485 * Parse a set of files with streaming, applying an RNG schemas
William M. Brackca15a542005-07-06 20:41:33 +00003486 *
3487 * Returns 0 in case of success, an error code otherwise
3488 */
3489static int
3490patternTest(const char *filename,
3491 const char *resul ATTRIBUTE_UNUSED,
3492 const char *err ATTRIBUTE_UNUSED,
3493 int options) {
3494 xmlPatternPtr patternc = NULL;
3495 xmlStreamCtxtPtr patstream = NULL;
3496 FILE *o, *f;
3497 char str[1024];
3498 char xml[500];
3499 char result[500];
3500 int len, i;
3501 int ret = 0, res;
3502 char *temp;
3503 xmlTextReaderPtr reader;
3504 xmlDocPtr doc;
3505
3506 len = strlen(filename);
3507 len -= 4;
3508 memcpy(xml, filename, len);
3509 xml[len] = 0;
3510 snprintf(result, 499, "result/pattern/%s", baseFilename(xml));
3511 result[499] = 0;
3512 memcpy(xml + len, ".xml", 5);
3513
David Kilzer5c373822016-05-22 09:58:30 +08003514 if (!checkTestFile(xml) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00003515 fprintf(stderr, "Missing xml file %s\n", xml);
3516 return(-1);
3517 }
David Kilzer5c373822016-05-22 09:58:30 +08003518 if (!checkTestFile(result) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00003519 fprintf(stderr, "Missing result file %s\n", result);
3520 return(-1);
3521 }
3522 f = fopen(filename, "rb");
3523 if (f == NULL) {
3524 fprintf(stderr, "Failed to open %s\n", filename);
3525 return(-1);
3526 }
3527 temp = resultFilename(filename, "", ".res");
3528 if (temp == NULL) {
3529 fprintf(stderr, "Out of memory\n");
3530 fatalError();
3531 }
3532 o = fopen(temp, "wb");
3533 if (o == NULL) {
3534 fprintf(stderr, "failed to open output file %s\n", temp);
3535 fclose(f);
3536 free(temp);
3537 return(-1);
3538 }
3539 while (1) {
3540 /*
3541 * read one line in string buffer.
3542 */
3543 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
3544 break;
3545
3546 /*
3547 * remove the ending spaces
3548 */
3549 i = strlen(str);
3550 while ((i > 0) &&
3551 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
3552 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
3553 i--;
3554 str[i] = 0;
3555 }
3556 doc = xmlReadFile(xml, NULL, options);
3557 if (doc == NULL) {
3558 fprintf(stderr, "Failed to parse %s\n", xml);
3559 ret = 1;
3560 } else {
3561 xmlNodePtr root;
3562 const xmlChar *namespaces[22];
3563 int j;
3564 xmlNsPtr ns;
3565
3566 root = xmlDocGetRootElement(doc);
3567 for (ns = root->nsDef, j = 0;ns != NULL && j < 20;ns=ns->next) {
3568 namespaces[j++] = ns->href;
3569 namespaces[j++] = ns->prefix;
3570 }
3571 namespaces[j++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003572 namespaces[j] = NULL;
William M. Brackca15a542005-07-06 20:41:33 +00003573
3574 patternc = xmlPatterncompile((const xmlChar *) str, doc->dict,
3575 0, &namespaces[0]);
3576 if (patternc == NULL) {
3577 testErrorHandler(NULL,
3578 "Pattern %s failed to compile\n", str);
3579 xmlFreeDoc(doc);
3580 ret = 1;
3581 continue;
3582 }
3583 patstream = xmlPatternGetStreamCtxt(patternc);
3584 if (patstream != NULL) {
3585 ret = xmlStreamPush(patstream, NULL, NULL);
3586 if (ret < 0) {
3587 fprintf(stderr, "xmlStreamPush() failure\n");
3588 xmlFreeStreamCtxt(patstream);
3589 patstream = NULL;
3590 }
3591 }
3592 nb_tests++;
3593
3594 reader = xmlReaderWalker(doc);
3595 res = xmlTextReaderRead(reader);
3596 while (res == 1) {
3597 patternNode(o, reader, str, patternc, patstream);
3598 res = xmlTextReaderRead(reader);
3599 }
3600 if (res != 0) {
3601 fprintf(o, "%s : failed to parse\n", filename);
3602 }
3603 xmlFreeTextReader(reader);
3604 xmlFreeDoc(doc);
3605 xmlFreeStreamCtxt(patstream);
3606 patstream = NULL;
3607 xmlFreePattern(patternc);
3608
3609 }
3610 }
3611
3612 fclose(f);
3613 fclose(o);
3614
3615 ret = compareFiles(temp, result);
3616 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08003617 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00003618 ret = 1;
3619 }
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003620 if (temp != NULL) {
3621 unlink(temp);
3622 free(temp);
3623 }
William M. Brackca15a542005-07-06 20:41:33 +00003624 return(ret);
3625}
3626#endif /* READER */
3627#endif /* PATTERN */
3628#ifdef LIBXML_C14N_ENABLED
3629/************************************************************************
3630 * *
3631 * Canonicalization tests *
3632 * *
3633 ************************************************************************/
3634static xmlXPathObjectPtr
3635load_xpath_expr (xmlDocPtr parent_doc, const char* filename) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00003636 xmlXPathObjectPtr xpath;
William M. Brackca15a542005-07-06 20:41:33 +00003637 xmlDocPtr doc;
3638 xmlChar *expr;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003639 xmlXPathContextPtr ctx;
William M. Brackca15a542005-07-06 20:41:33 +00003640 xmlNodePtr node;
3641 xmlNsPtr ns;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003642
William M. Brackca15a542005-07-06 20:41:33 +00003643 /*
3644 * load XPath expr as a file
3645 */
3646 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3647 xmlSubstituteEntitiesDefault(1);
3648
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003649 doc = xmlReadFile(filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
William M. Brackca15a542005-07-06 20:41:33 +00003650 if (doc == NULL) {
3651 fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
3652 return(NULL);
3653 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003654
William M. Brackca15a542005-07-06 20:41:33 +00003655 /*
3656 * Check the document is of the right kind
Daniel Veillardaa6de472008-08-25 14:53:31 +00003657 */
William M. Brackca15a542005-07-06 20:41:33 +00003658 if(xmlDocGetRootElement(doc) == NULL) {
3659 fprintf(stderr,"Error: empty document for file \"%s\"\n", filename);
3660 xmlFreeDoc(doc);
3661 return(NULL);
3662 }
3663
3664 node = doc->children;
3665 while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) {
3666 node = node->next;
3667 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003668
3669 if(node == NULL) {
William M. Brackca15a542005-07-06 20:41:33 +00003670 fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename);
3671 xmlFreeDoc(doc);
3672 return(NULL);
3673 }
3674
3675 expr = xmlNodeGetContent(node);
3676 if(expr == NULL) {
3677 fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename);
3678 xmlFreeDoc(doc);
3679 return(NULL);
3680 }
3681
3682 ctx = xmlXPathNewContext(parent_doc);
3683 if(ctx == NULL) {
3684 fprintf(stderr,"Error: unable to create new context\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003685 xmlFree(expr);
3686 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003687 return(NULL);
3688 }
3689
3690 /*
3691 * Register namespaces
3692 */
3693 ns = node->nsDef;
3694 while(ns != NULL) {
3695 if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) {
3696 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 +00003697 xmlFree(expr);
3698 xmlXPathFreeContext(ctx);
3699 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003700 return(NULL);
3701 }
3702 ns = ns->next;
3703 }
3704
Daniel Veillardaa6de472008-08-25 14:53:31 +00003705 /*
William M. Brackca15a542005-07-06 20:41:33 +00003706 * Evaluate xpath
3707 */
3708 xpath = xmlXPathEvalExpression(expr, ctx);
3709 if(xpath == NULL) {
3710 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003711xmlFree(expr);
3712 xmlXPathFreeContext(ctx);
3713 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003714 return(NULL);
3715 }
3716
3717 /* print_xpath_nodes(xpath->nodesetval); */
3718
Daniel Veillardaa6de472008-08-25 14:53:31 +00003719 xmlFree(expr);
3720 xmlXPathFreeContext(ctx);
3721 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003722 return(xpath);
3723}
3724
3725/*
3726 * Macro used to grow the current buffer.
3727 */
3728#define xxx_growBufferReentrant() { \
3729 buffer_size *= 2; \
3730 buffer = (xmlChar **) \
Daniel Veillardaa6de472008-08-25 14:53:31 +00003731 xmlRealloc(buffer, buffer_size * sizeof(xmlChar*)); \
William M. Brackca15a542005-07-06 20:41:33 +00003732 if (buffer == NULL) { \
3733 perror("realloc failed"); \
3734 return(NULL); \
3735 } \
3736}
3737
3738static xmlChar **
3739parse_list(xmlChar *str) {
3740 xmlChar **buffer;
3741 xmlChar **out = NULL;
3742 int buffer_size = 0;
3743 int len;
3744
3745 if(str == NULL) {
3746 return(NULL);
3747 }
3748
3749 len = xmlStrlen(str);
3750 if((str[0] == '\'') && (str[len - 1] == '\'')) {
3751 str[len - 1] = '\0';
3752 str++;
William M. Brackca15a542005-07-06 20:41:33 +00003753 }
3754 /*
3755 * allocate an translation buffer.
3756 */
3757 buffer_size = 1000;
3758 buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*));
3759 if (buffer == NULL) {
3760 perror("malloc failed");
3761 return(NULL);
3762 }
3763 out = buffer;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003764
William M. Brackca15a542005-07-06 20:41:33 +00003765 while(*str != '\0') {
3766 if (out - buffer > buffer_size - 10) {
3767 int indx = out - buffer;
3768
3769 xxx_growBufferReentrant();
3770 out = &buffer[indx];
3771 }
3772 (*out++) = str;
3773 while(*str != ',' && *str != '\0') ++str;
3774 if(*str == ',') *(str++) = '\0';
3775 }
3776 (*out) = NULL;
3777 return buffer;
3778}
3779
Daniel Veillardaa6de472008-08-25 14:53:31 +00003780static int
Aleksey Sanin83868242009-07-09 10:26:22 +02003781c14nRunTest(const char* xml_filename, int with_comments, int mode,
William M. Brackca15a542005-07-06 20:41:33 +00003782 const char* xpath_filename, const char *ns_filename,
3783 const char* result_file) {
3784 xmlDocPtr doc;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003785 xmlXPathObjectPtr xpath = NULL;
William M. Brackca15a542005-07-06 20:41:33 +00003786 xmlChar *result = NULL;
3787 int ret;
3788 xmlChar **inclusive_namespaces = NULL;
3789 const char *nslist = NULL;
3790 int nssize;
3791
3792
3793 /*
3794 * build an XML tree from a the file; we need to add default
3795 * attributes and resolve all character and entities references
3796 */
3797 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3798 xmlSubstituteEntitiesDefault(1);
3799
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003800 doc = xmlReadFile(xml_filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
William M. Brackca15a542005-07-06 20:41:33 +00003801 if (doc == NULL) {
3802 fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename);
3803 return(-1);
3804 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003805
William M. Brackca15a542005-07-06 20:41:33 +00003806 /*
3807 * Check the document is of the right kind
Daniel Veillardaa6de472008-08-25 14:53:31 +00003808 */
William M. Brackca15a542005-07-06 20:41:33 +00003809 if(xmlDocGetRootElement(doc) == NULL) {
3810 fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename);
3811 xmlFreeDoc(doc);
3812 return(-1);
3813 }
3814
Daniel Veillardaa6de472008-08-25 14:53:31 +00003815 /*
3816 * load xpath file if specified
William M. Brackca15a542005-07-06 20:41:33 +00003817 */
3818 if(xpath_filename) {
3819 xpath = load_xpath_expr(doc, xpath_filename);
3820 if(xpath == NULL) {
3821 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003822 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003823 return(-1);
3824 }
3825 }
3826
3827 if (ns_filename != NULL) {
3828 if (loadMem(ns_filename, &nslist, &nssize)) {
3829 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3830 if(xpath != NULL) xmlXPathFreeObject(xpath);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003831 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003832 return(-1);
3833 }
3834 inclusive_namespaces = parse_list((xmlChar *) nslist);
3835 }
3836
3837 /*
3838 * Canonical form
Daniel Veillardaa6de472008-08-25 14:53:31 +00003839 */
William M. Brackca15a542005-07-06 20:41:33 +00003840 /* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */
Daniel Veillardaa6de472008-08-25 14:53:31 +00003841 ret = xmlC14NDocDumpMemory(doc,
3842 (xpath) ? xpath->nodesetval : NULL,
Aleksey Sanin83868242009-07-09 10:26:22 +02003843 mode, inclusive_namespaces,
William M. Brackca15a542005-07-06 20:41:33 +00003844 with_comments, &result);
3845 if (ret >= 0) {
3846 if(result != NULL) {
3847 if (compareFileMem(result_file, (const char *) result, ret)) {
3848 fprintf(stderr, "Result mismatch for %s\n", xml_filename);
Aleksey Sanin83868242009-07-09 10:26:22 +02003849 fprintf(stderr, "RESULT:\n%s\n", (const char*)result);
William M. Brackca15a542005-07-06 20:41:33 +00003850 ret = -1;
3851 }
3852 }
3853 } else {
3854 fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret);
3855 ret = -1;
3856 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003857
William M. Brackca15a542005-07-06 20:41:33 +00003858 /*
3859 * Cleanup
Daniel Veillardaa6de472008-08-25 14:53:31 +00003860 */
William M. Brackca15a542005-07-06 20:41:33 +00003861 if (result != NULL) xmlFree(result);
3862 if(xpath != NULL) xmlXPathFreeObject(xpath);
3863 if (inclusive_namespaces != NULL) xmlFree(inclusive_namespaces);
3864 if (nslist != NULL) free((char *) nslist);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003865 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003866
3867 return(ret);
3868}
3869
3870static int
Aleksey Sanin83868242009-07-09 10:26:22 +02003871c14nCommonTest(const char *filename, int with_comments, int mode,
William M. Brackca15a542005-07-06 20:41:33 +00003872 const char *subdir) {
3873 char buf[500];
3874 char prefix[500];
3875 const char *base;
3876 int len;
3877 char *result = NULL;
3878 char *xpath = NULL;
3879 char *ns = NULL;
3880 int ret = 0;
3881
3882 base = baseFilename(filename);
3883 len = strlen(base);
3884 len -= 4;
3885 memcpy(prefix, base, len);
3886 prefix[len] = 0;
3887
3888 snprintf(buf, 499, "result/c14n/%s/%s", subdir,prefix);
David Kilzer5c373822016-05-22 09:58:30 +08003889 if (!checkTestFile(buf) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00003890 fprintf(stderr, "Missing result file %s", buf);
3891 return(-1);
3892 }
3893 result = strdup(buf);
3894 snprintf(buf, 499, "test/c14n/%s/%s.xpath", subdir,prefix);
3895 if (checkTestFile(buf)) {
3896 xpath = strdup(buf);
3897 }
3898 snprintf(buf, 499, "test/c14n/%s/%s.ns", subdir,prefix);
3899 if (checkTestFile(buf)) {
3900 ns = strdup(buf);
3901 }
3902
3903 nb_tests++;
Aleksey Sanin83868242009-07-09 10:26:22 +02003904 if (c14nRunTest(filename, with_comments, mode,
William M. Brackca15a542005-07-06 20:41:33 +00003905 xpath, ns, result) < 0)
3906 ret = 1;
3907
3908 if (result != NULL) free(result);
3909 if (xpath != NULL) free(xpath);
3910 if (ns != NULL) free(ns);
3911 return(ret);
3912}
3913
3914static int
3915c14nWithCommentTest(const char *filename,
3916 const char *resul ATTRIBUTE_UNUSED,
3917 const char *err ATTRIBUTE_UNUSED,
3918 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003919 return(c14nCommonTest(filename, 1, XML_C14N_1_0, "with-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003920}
3921static int
3922c14nWithoutCommentTest(const char *filename,
3923 const char *resul ATTRIBUTE_UNUSED,
3924 const char *err ATTRIBUTE_UNUSED,
3925 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003926 return(c14nCommonTest(filename, 0, XML_C14N_1_0, "without-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003927}
3928static int
3929c14nExcWithoutCommentTest(const char *filename,
3930 const char *resul ATTRIBUTE_UNUSED,
3931 const char *err ATTRIBUTE_UNUSED,
3932 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003933 return(c14nCommonTest(filename, 0, XML_C14N_EXCLUSIVE_1_0, "exc-without-comments"));
3934}
3935static int
3936c14n11WithoutCommentTest(const char *filename,
3937 const char *resul ATTRIBUTE_UNUSED,
3938 const char *err ATTRIBUTE_UNUSED,
3939 int options ATTRIBUTE_UNUSED) {
3940 return(c14nCommonTest(filename, 0, XML_C14N_1_1, "1-1-without-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003941}
3942#endif
Nick Wellnhofer01a4b812017-06-16 21:27:47 +02003943#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
William M. Brackca15a542005-07-06 20:41:33 +00003944/************************************************************************
3945 * *
3946 * Catalog and threads test *
3947 * *
3948 ************************************************************************/
3949
3950/*
3951 * mostly a cut and paste from testThreads.c
3952 */
3953#define MAX_ARGC 20
3954
Nick Wellnhofercf820462017-10-21 14:43:00 +02003955typedef struct {
3956 const char *filename;
3957 int okay;
3958} xmlThreadParams;
William M. Brackca15a542005-07-06 20:41:33 +00003959
Nick Wellnhofercf820462017-10-21 14:43:00 +02003960static const char *catalog = "test/threads/complex.xml";
3961static xmlThreadParams threadParams[] = {
3962 { "test/threads/abc.xml", 0 },
3963 { "test/threads/acb.xml", 0 },
3964 { "test/threads/bac.xml", 0 },
3965 { "test/threads/bca.xml", 0 },
3966 { "test/threads/cab.xml", 0 },
3967 { "test/threads/cba.xml", 0 },
3968 { "test/threads/invalid.xml", 0 }
3969};
3970static const unsigned int num_threads = sizeof(threadParams) /
3971 sizeof(threadParams[0]);
William M. Brackca15a542005-07-06 20:41:33 +00003972
3973#ifndef xmlDoValidityCheckingDefaultValue
3974#error xmlDoValidityCheckingDefaultValue is not a macro
3975#endif
3976#ifndef xmlGenericErrorContext
3977#error xmlGenericErrorContext is not a macro
3978#endif
3979
3980static void *
3981thread_specific_data(void *private_data)
3982{
3983 xmlDocPtr myDoc;
Nick Wellnhofercf820462017-10-21 14:43:00 +02003984 xmlThreadParams *params = (xmlThreadParams *) private_data;
3985 const char *filename = params->filename;
William M. Brackca15a542005-07-06 20:41:33 +00003986 int okay = 1;
3987
3988 if (!strcmp(filename, "test/threads/invalid.xml")) {
3989 xmlDoValidityCheckingDefaultValue = 0;
3990 xmlGenericErrorContext = stdout;
3991 } else {
3992 xmlDoValidityCheckingDefaultValue = 1;
3993 xmlGenericErrorContext = stderr;
3994 }
Nick Wellnhofer01a4b812017-06-16 21:27:47 +02003995#ifdef LIBXML_SAX1_ENABLED
William M. Brackca15a542005-07-06 20:41:33 +00003996 myDoc = xmlParseFile(filename);
Nick Wellnhofer01a4b812017-06-16 21:27:47 +02003997#else
3998 myDoc = xmlReadFile(filename, NULL, XML_WITH_CATALOG);
3999#endif
William M. Brackca15a542005-07-06 20:41:33 +00004000 if (myDoc) {
4001 xmlFreeDoc(myDoc);
4002 } else {
4003 printf("parse failed\n");
4004 okay = 0;
4005 }
4006 if (!strcmp(filename, "test/threads/invalid.xml")) {
4007 if (xmlDoValidityCheckingDefaultValue != 0) {
4008 printf("ValidityCheckingDefaultValue override failed\n");
4009 okay = 0;
4010 }
4011 if (xmlGenericErrorContext != stdout) {
4012 printf("xmlGenericErrorContext override failed\n");
4013 okay = 0;
4014 }
4015 } else {
4016 if (xmlDoValidityCheckingDefaultValue != 1) {
4017 printf("ValidityCheckingDefaultValue override failed\n");
4018 okay = 0;
4019 }
4020 if (xmlGenericErrorContext != stderr) {
4021 printf("xmlGenericErrorContext override failed\n");
4022 okay = 0;
4023 }
4024 }
Nick Wellnhofercf820462017-10-21 14:43:00 +02004025 params->okay = okay;
4026 return(NULL);
William M. Brackca15a542005-07-06 20:41:33 +00004027}
4028
Nick Wellnhofere3890542017-10-09 00:20:01 +02004029#if defined(_WIN32) && !defined(__CYGWIN__)
William M. Brackca15a542005-07-06 20:41:33 +00004030#include <windows.h>
4031#include <string.h>
4032
4033#define TEST_REPEAT_COUNT 500
4034
4035static HANDLE tid[MAX_ARGC];
4036
4037static DWORD WINAPI
4038win32_thread_specific_data(void *private_data)
4039{
Nick Wellnhofercf820462017-10-21 14:43:00 +02004040 thread_specific_data(private_data);
4041 return(0);
William M. Brackca15a542005-07-06 20:41:33 +00004042}
4043
4044static int
4045testThread(void)
4046{
4047 unsigned int i, repeat;
William M. Brackca15a542005-07-06 20:41:33 +00004048 BOOL ret;
4049 int res = 0;
4050
4051 xmlInitParser();
4052 for (repeat = 0; repeat < TEST_REPEAT_COUNT; repeat++) {
4053 xmlLoadCatalog(catalog);
4054 nb_tests++;
4055
4056 for (i = 0; i < num_threads; i++) {
William M. Brackca15a542005-07-06 20:41:33 +00004057 tid[i] = (HANDLE) - 1;
4058 }
4059
4060 for (i = 0; i < num_threads; i++) {
4061 DWORD useless;
4062
4063 tid[i] = CreateThread(NULL, 0,
Daniel Veillardaa6de472008-08-25 14:53:31 +00004064 win32_thread_specific_data,
Nick Wellnhofercf820462017-10-21 14:43:00 +02004065 (void *) &threadParams[i], 0,
William M. Brackca15a542005-07-06 20:41:33 +00004066 &useless);
4067 if (tid[i] == NULL) {
4068 fprintf(stderr, "CreateThread failed\n");
4069 return(1);
4070 }
4071 }
4072
4073 if (WaitForMultipleObjects(num_threads, tid, TRUE, INFINITE) ==
4074 WAIT_FAILED) {
4075 fprintf(stderr, "WaitForMultipleObjects failed\n");
4076 return(1);
4077 }
4078
4079 for (i = 0; i < num_threads; i++) {
Nick Wellnhofercf820462017-10-21 14:43:00 +02004080 DWORD exitCode;
4081 ret = GetExitCodeThread(tid[i], &exitCode);
William M. Brackca15a542005-07-06 20:41:33 +00004082 if (ret == 0) {
4083 fprintf(stderr, "GetExitCodeThread failed\n");
4084 return(1);
4085 }
4086 CloseHandle(tid[i]);
4087 }
4088
4089 xmlCatalogCleanup();
4090 for (i = 0; i < num_threads; i++) {
Nick Wellnhofercf820462017-10-21 14:43:00 +02004091 if (threadParams[i].okay == 0) {
William M. Brackca15a542005-07-06 20:41:33 +00004092 fprintf(stderr, "Thread %d handling %s failed\n",
Nick Wellnhofercf820462017-10-21 14:43:00 +02004093 i, threadParams[i].filename);
William M. Brackca15a542005-07-06 20:41:33 +00004094 res = 1;
4095 }
4096 }
4097 }
4098
4099 return (res);
4100}
4101
4102#elif defined __BEOS__
4103#include <OS.h>
4104
4105static thread_id tid[MAX_ARGC];
4106
4107static int
4108testThread(void)
4109{
4110 unsigned int i, repeat;
William M. Brackca15a542005-07-06 20:41:33 +00004111 status_t ret;
4112 int res = 0;
4113
4114 xmlInitParser();
4115 for (repeat = 0; repeat < 500; repeat++) {
4116 xmlLoadCatalog(catalog);
4117 for (i = 0; i < num_threads; i++) {
William M. Brackca15a542005-07-06 20:41:33 +00004118 tid[i] = (thread_id) - 1;
4119 }
4120 for (i = 0; i < num_threads; i++) {
4121 tid[i] =
4122 spawn_thread(thread_specific_data, "xmlTestThread",
Nick Wellnhofercf820462017-10-21 14:43:00 +02004123 B_NORMAL_PRIORITY, (void *) &threadParams[i]);
William M. Brackca15a542005-07-06 20:41:33 +00004124 if (tid[i] < B_OK) {
4125 fprintf(stderr, "beos_thread_create failed\n");
4126 return (1);
4127 }
4128 printf("beos_thread_create %d -> %d\n", i, tid[i]);
4129 }
4130 for (i = 0; i < num_threads; i++) {
Nick Wellnhofercf820462017-10-21 14:43:00 +02004131 void *result;
4132 ret = wait_for_thread(tid[i], &result);
William M. Brackca15a542005-07-06 20:41:33 +00004133 printf("beos_thread_wait %d -> %d\n", i, ret);
4134 if (ret != B_OK) {
4135 fprintf(stderr, "beos_thread_wait failed\n");
4136 return (1);
4137 }
4138 }
4139
4140 xmlCatalogCleanup();
4141 ret = B_OK;
4142 for (i = 0; i < num_threads; i++)
Nick Wellnhofercf820462017-10-21 14:43:00 +02004143 if (threadParams[i].okay == 0) {
4144 printf("Thread %d handling %s failed\n", i,
4145 threadParams[i].filename);
William M. Brackca15a542005-07-06 20:41:33 +00004146 ret = B_ERROR;
4147 }
4148 }
4149 if (ret != B_OK)
4150 return(1);
4151 return (0);
4152}
Daniel Richard G495a73d2012-08-07 10:14:56 +08004153
4154#elif defined HAVE_PTHREAD_H
4155#include <pthread.h>
4156
4157static pthread_t tid[MAX_ARGC];
4158
4159static int
4160testThread(void)
4161{
4162 unsigned int i, repeat;
Daniel Richard G495a73d2012-08-07 10:14:56 +08004163 int ret;
4164 int res = 0;
4165
4166 xmlInitParser();
4167
4168 for (repeat = 0; repeat < 500; repeat++) {
4169 xmlLoadCatalog(catalog);
4170 nb_tests++;
4171
4172 for (i = 0; i < num_threads; i++) {
Daniel Richard G495a73d2012-08-07 10:14:56 +08004173 tid[i] = (pthread_t) - 1;
4174 }
4175
4176 for (i = 0; i < num_threads; i++) {
4177 ret = pthread_create(&tid[i], 0, thread_specific_data,
Nick Wellnhofercf820462017-10-21 14:43:00 +02004178 (void *) &threadParams[i]);
Daniel Richard G495a73d2012-08-07 10:14:56 +08004179 if (ret != 0) {
4180 fprintf(stderr, "pthread_create failed\n");
4181 return (1);
4182 }
4183 }
4184 for (i = 0; i < num_threads; i++) {
Nick Wellnhofercf820462017-10-21 14:43:00 +02004185 void *result;
4186 ret = pthread_join(tid[i], &result);
Daniel Richard G495a73d2012-08-07 10:14:56 +08004187 if (ret != 0) {
4188 fprintf(stderr, "pthread_join failed\n");
4189 return (1);
4190 }
4191 }
4192
4193 xmlCatalogCleanup();
4194 for (i = 0; i < num_threads; i++)
Nick Wellnhofercf820462017-10-21 14:43:00 +02004195 if (threadParams[i].okay == 0) {
Daniel Richard G495a73d2012-08-07 10:14:56 +08004196 fprintf(stderr, "Thread %d handling %s failed\n",
Nick Wellnhofercf820462017-10-21 14:43:00 +02004197 i, threadParams[i].filename);
Daniel Richard G495a73d2012-08-07 10:14:56 +08004198 res = 1;
4199 }
4200 }
4201 return (res);
4202}
4203
William M. Brackca15a542005-07-06 20:41:33 +00004204#else
4205static int
4206testThread(void)
4207{
4208 fprintf(stderr,
4209 "Specific platform thread support not detected\n");
4210 return (-1);
4211}
4212#endif
Daniel Veillardaa6de472008-08-25 14:53:31 +00004213static int
William M. Brackca15a542005-07-06 20:41:33 +00004214threadsTest(const char *filename ATTRIBUTE_UNUSED,
4215 const char *resul ATTRIBUTE_UNUSED,
4216 const char *err ATTRIBUTE_UNUSED,
4217 int options ATTRIBUTE_UNUSED) {
4218 return(testThread());
4219}
4220#endif
4221/************************************************************************
4222 * *
4223 * Tests Descriptions *
4224 * *
4225 ************************************************************************/
4226
4227static
4228testDesc testDescriptions[] = {
4229 { "XML regression tests" ,
4230 oldParseTest, "./test/*", "result/", "", NULL,
4231 0 },
4232 { "XML regression tests on memory" ,
4233 memParseTest, "./test/*", "result/", "", NULL,
4234 0 },
4235 { "XML entity subst regression tests" ,
4236 noentParseTest, "./test/*", "result/noent/", "", NULL,
4237 XML_PARSE_NOENT },
4238 { "XML Namespaces regression tests",
4239 errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err",
4240 0 },
4241 { "Error cases regression tests",
4242 errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err",
4243 0 },
Nick Wellnhofere2663052017-06-05 15:37:17 +02004244 { "Error cases regression tests (old 1.0)",
4245 errParseTest, "./test/errors10/*.xml", "result/errors10/", "", ".err",
4246 XML_PARSE_OLD10 },
William M. Brackca15a542005-07-06 20:41:33 +00004247#ifdef LIBXML_READER_ENABLED
4248 { "Error cases stream regression tests",
4249 streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str",
4250 0 },
4251 { "Reader regression tests",
4252 streamParseTest, "./test/*", "result/", ".rdr", NULL,
4253 0 },
4254 { "Reader entities substitution regression tests",
4255 streamParseTest, "./test/*", "result/", ".rde", NULL,
4256 XML_PARSE_NOENT },
4257 { "Reader on memory regression tests",
4258 streamMemParseTest, "./test/*", "result/", ".rdr", NULL,
4259 0 },
4260 { "Walker regression tests",
4261 walkerParseTest, "./test/*", "result/", ".rdr", NULL,
4262 0 },
4263#endif
4264#ifdef LIBXML_SAX1_ENABLED
4265 { "SAX1 callbacks regression tests" ,
4266 saxParseTest, "./test/*", "result/", ".sax", NULL,
4267 XML_PARSE_SAX1 },
Nick Wellnhoferdbaab1f2017-06-16 21:38:57 +02004268#endif
William M. Brackca15a542005-07-06 20:41:33 +00004269 { "SAX2 callbacks regression tests" ,
4270 saxParseTest, "./test/*", "result/", ".sax2", NULL,
4271 0 },
Nick Wellnhoferdbaab1f2017-06-16 21:38:57 +02004272 { "SAX2 callbacks regression tests with entity substitution" ,
4273 saxParseTest, "./test/*", "result/noent/", ".sax2", NULL,
4274 XML_PARSE_NOENT },
William M. Brackca15a542005-07-06 20:41:33 +00004275#ifdef LIBXML_PUSH_ENABLED
4276 { "XML push regression tests" ,
4277 pushParseTest, "./test/*", "result/", "", NULL,
4278 0 },
4279#endif
4280#ifdef LIBXML_HTML_ENABLED
4281 { "HTML regression tests" ,
4282 errParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4283 XML_PARSE_HTML },
4284#ifdef LIBXML_PUSH_ENABLED
4285 { "Push HTML regression tests" ,
4286 pushParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4287 XML_PARSE_HTML },
4288#endif
William M. Brackca15a542005-07-06 20:41:33 +00004289 { "HTML SAX regression tests" ,
4290 saxParseTest, "./test/HTML/*", "result/HTML/", ".sax", NULL,
4291 XML_PARSE_HTML },
4292#endif
William M. Brackca15a542005-07-06 20:41:33 +00004293#ifdef LIBXML_VALID_ENABLED
4294 { "Valid documents regression tests" ,
4295 errParseTest, "./test/VCM/*", NULL, NULL, NULL,
4296 XML_PARSE_DTDVALID },
4297 { "Validity checking regression tests" ,
4298 errParseTest, "./test/VC/*", "result/VC/", NULL, "",
4299 XML_PARSE_DTDVALID },
Daniel Veillarda7982ce2012-10-25 15:39:39 +08004300#ifdef LIBXML_READER_ENABLED
4301 { "Streaming validity checking regression tests" ,
4302 streamParseTest, "./test/valid/*.xml", "result/valid/", NULL, ".err.rdr",
4303 XML_PARSE_DTDVALID },
4304 { "Streaming validity error checking regression tests" ,
4305 streamParseTest, "./test/VC/*", "result/VC/", NULL, ".rdr",
4306 XML_PARSE_DTDVALID },
4307#endif
William M. Brackca15a542005-07-06 20:41:33 +00004308 { "General documents valid regression tests" ,
4309 errParseTest, "./test/valid/*", "result/valid/", "", ".err",
4310 XML_PARSE_DTDVALID },
4311#endif
4312#ifdef LIBXML_XINCLUDE_ENABLED
4313 { "XInclude regression tests" ,
4314 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4315 /* Ignore errors at this point ".err", */
4316 XML_PARSE_XINCLUDE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004317#ifdef LIBXML_READER_ENABLED
William M. Brackca15a542005-07-06 20:41:33 +00004318 { "XInclude xmlReader regression tests",
4319 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4320 /* Ignore errors at this point ".err", */
4321 NULL, XML_PARSE_XINCLUDE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004322#endif
William M. Brackca15a542005-07-06 20:41:33 +00004323 { "XInclude regression tests stripping include nodes" ,
4324 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4325 /* Ignore errors at this point ".err", */
4326 XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004327#ifdef LIBXML_READER_ENABLED
William M. Brackca15a542005-07-06 20:41:33 +00004328 { "XInclude xmlReader regression tests stripping include nodes",
4329 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4330 /* Ignore errors at this point ".err", */
4331 NULL, XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
4332#endif
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004333#endif
William M. Brackca15a542005-07-06 20:41:33 +00004334#ifdef LIBXML_XPATH_ENABLED
4335#ifdef LIBXML_DEBUG_ENABLED
4336 { "XPath expressions regression tests" ,
4337 xpathExprTest, "./test/XPath/expr/*", "result/XPath/expr/", "", NULL,
4338 0 },
4339 { "XPath document queries regression tests" ,
4340 xpathDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4341 0 },
4342#ifdef LIBXML_XPTR_ENABLED
4343 { "XPointer document queries regression tests" ,
4344 xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4345 0 },
4346#endif
4347 { "xml:id regression tests" ,
4348 xmlidDocTest, "./test/xmlid/*", "result/xmlid/", "", ".err",
4349 0 },
4350#endif
4351#endif
4352 { "URI parsing tests" ,
4353 uriParseTest, "./test/URI/*.uri", "result/URI/", "", NULL,
4354 0 },
4355 { "URI base composition tests" ,
4356 uriBaseTest, "./test/URI/*.data", "result/URI/", "", NULL,
4357 0 },
Daniel Veillard336a8e12005-08-07 10:46:19 +00004358 { "Path URI conversion tests" ,
4359 uriPathTest, NULL, NULL, NULL, NULL,
4360 0 },
William M. Brackca15a542005-07-06 20:41:33 +00004361#ifdef LIBXML_SCHEMAS_ENABLED
4362 { "Schemas regression tests" ,
4363 schemasTest, "./test/schemas/*_*.xsd", NULL, NULL, NULL,
4364 0 },
4365 { "Relax-NG regression tests" ,
4366 rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4367 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4368#ifdef LIBXML_READER_ENABLED
4369 { "Relax-NG streaming regression tests" ,
4370 rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4371 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4372#endif
4373#endif
4374#ifdef LIBXML_PATTERN_ENABLED
4375#ifdef LIBXML_READER_ENABLED
4376 { "Pattern regression tests" ,
4377 patternTest, "./test/pattern/*.pat", "result/pattern/", NULL, NULL,
4378 0 },
4379#endif
4380#endif
4381#ifdef LIBXML_C14N_ENABLED
4382 { "C14N with comments regression tests" ,
4383 c14nWithCommentTest, "./test/c14n/with-comments/*.xml", NULL, NULL, NULL,
4384 0 },
4385 { "C14N without comments regression tests" ,
4386 c14nWithoutCommentTest, "./test/c14n/without-comments/*.xml", NULL, NULL, NULL,
4387 0 },
4388 { "C14N exclusive without comments regression tests" ,
4389 c14nExcWithoutCommentTest, "./test/c14n/exc-without-comments/*.xml", NULL, NULL, NULL,
4390 0 },
Aleksey Sanin83868242009-07-09 10:26:22 +02004391 { "C14N 1.1 without comments regression tests" ,
4392 c14n11WithoutCommentTest, "./test/c14n/1-1-without-comments/*.xml", NULL, NULL, NULL,
4393 0 },
William M. Brackca15a542005-07-06 20:41:33 +00004394#endif
Nick Wellnhofer01a4b812017-06-16 21:27:47 +02004395#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
William M. Brackca15a542005-07-06 20:41:33 +00004396 { "Catalog and Threads regression tests" ,
4397 threadsTest, NULL, NULL, NULL, NULL,
4398 0 },
4399#endif
4400 {NULL, NULL, NULL, NULL, NULL, NULL, 0}
4401};
4402
4403/************************************************************************
4404 * *
4405 * The main code driving the tests *
4406 * *
4407 ************************************************************************/
4408
4409static int
4410launchTests(testDescPtr tst) {
4411 int res = 0, err = 0;
4412 size_t i;
4413 char *result;
4414 char *error;
4415 int mem;
Nick Wellnhofer4b413592017-10-31 17:17:16 +01004416 xmlCharEncodingHandlerPtr ebcdicHandler;
4417
4418 ebcdicHandler = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_EBCDIC);
William M. Brackca15a542005-07-06 20:41:33 +00004419
4420 if (tst == NULL) return(-1);
4421 if (tst->in != NULL) {
4422 glob_t globbuf;
4423
4424 globbuf.gl_offs = 0;
4425 glob(tst->in, GLOB_DOOFFS, NULL, &globbuf);
4426 for (i = 0;i < globbuf.gl_pathc;i++) {
4427 if (!checkTestFile(globbuf.gl_pathv[i]))
4428 continue;
Nick Wellnhofer4b413592017-10-31 17:17:16 +01004429 if ((ebcdicHandler == NULL) &&
4430 (strstr(globbuf.gl_pathv[i], "ebcdic") != NULL))
4431 continue;
William M. Brackca15a542005-07-06 20:41:33 +00004432 if (tst->suffix != NULL) {
4433 result = resultFilename(globbuf.gl_pathv[i], tst->out,
4434 tst->suffix);
4435 if (result == NULL) {
4436 fprintf(stderr, "Out of memory !\n");
4437 fatalError();
4438 }
4439 } else {
4440 result = NULL;
4441 }
4442 if (tst->err != NULL) {
4443 error = resultFilename(globbuf.gl_pathv[i], tst->out,
4444 tst->err);
4445 if (error == NULL) {
4446 fprintf(stderr, "Out of memory !\n");
4447 fatalError();
4448 }
4449 } else {
4450 error = NULL;
4451 }
David Kilzer5c373822016-05-22 09:58:30 +08004452 if ((result) &&(!checkTestFile(result)) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00004453 fprintf(stderr, "Missing result file %s\n", result);
David Kilzer5c373822016-05-22 09:58:30 +08004454 } else if ((error) &&(!checkTestFile(error)) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00004455 fprintf(stderr, "Missing error file %s\n", error);
4456 } else {
4457 mem = xmlMemUsed();
4458 extraMemoryFromResolver = 0;
4459 testErrorsSize = 0;
4460 testErrors[0] = 0;
4461 res = tst->func(globbuf.gl_pathv[i], result, error,
Daniel Veillard8874b942005-08-25 13:19:21 +00004462 tst->options | XML_PARSE_COMPACT);
William M. Brackca15a542005-07-06 20:41:33 +00004463 xmlResetLastError();
4464 if (res != 0) {
4465 fprintf(stderr, "File %s generated an error\n",
4466 globbuf.gl_pathv[i]);
4467 nb_errors++;
4468 err++;
4469 }
4470 else if (xmlMemUsed() != mem) {
4471 if ((xmlMemUsed() != mem) &&
4472 (extraMemoryFromResolver == 0)) {
4473 fprintf(stderr, "File %s leaked %d bytes\n",
4474 globbuf.gl_pathv[i], xmlMemUsed() - mem);
4475 nb_leaks++;
4476 err++;
4477 }
4478 }
4479 testErrorsSize = 0;
4480 }
4481 if (result)
4482 free(result);
4483 if (error)
4484 free(error);
4485 }
4486 globfree(&globbuf);
4487 } else {
4488 testErrorsSize = 0;
4489 testErrors[0] = 0;
4490 extraMemoryFromResolver = 0;
4491 res = tst->func(NULL, NULL, NULL, tst->options);
4492 if (res != 0) {
4493 nb_errors++;
4494 err++;
4495 }
4496 }
Nick Wellnhofer4b413592017-10-31 17:17:16 +01004497
4498 xmlCharEncCloseFunc(ebcdicHandler);
4499
William M. Brackca15a542005-07-06 20:41:33 +00004500 return(err);
4501}
4502
Daniel Veillarddb68b742005-07-30 13:18:24 +00004503static int verbose = 0;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004504static int tests_quiet = 0;
Daniel Veillarddb68b742005-07-30 13:18:24 +00004505
4506static int
4507runtest(int i) {
4508 int ret = 0, res;
4509 int old_errors, old_tests, old_leaks;
4510
4511 old_errors = nb_errors;
4512 old_tests = nb_tests;
4513 old_leaks = nb_leaks;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004514 if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
Daniel Veillarddb68b742005-07-30 13:18:24 +00004515 printf("## %s\n", testDescriptions[i].desc);
4516 res = launchTests(&testDescriptions[i]);
4517 if (res != 0)
4518 ret++;
4519 if (verbose) {
4520 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
4521 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
4522 else
4523 printf("Ran %d tests, %d errors, %d leaks\n",
4524 nb_tests - old_tests,
4525 nb_errors - old_errors,
4526 nb_leaks - old_leaks);
4527 }
4528 return(ret);
4529}
4530
William M. Brackca15a542005-07-06 20:41:33 +00004531int
4532main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
Daniel Veillarddb68b742005-07-30 13:18:24 +00004533 int i, a, ret = 0;
4534 int subset = 0;
William M. Brackca15a542005-07-06 20:41:33 +00004535
Nick Wellnhofer82e03942017-10-09 02:05:41 +02004536#if defined(_WIN32) && !defined(__CYGWIN__)
4537 setvbuf(stdout, NULL, _IONBF, 0);
4538 setvbuf(stderr, NULL, _IONBF, 0);
4539#endif
4540
William M. Brackca15a542005-07-06 20:41:33 +00004541 initializeLibxml2();
4542
Daniel Veillarddb68b742005-07-30 13:18:24 +00004543 for (a = 1; a < argc;a++) {
4544 if (!strcmp(argv[a], "-v"))
4545 verbose = 1;
David Kilzer5c373822016-05-22 09:58:30 +08004546 else if (!strcmp(argv[a], "-u"))
4547 update_results = 1;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004548 else if (!strcmp(argv[a], "-quiet"))
4549 tests_quiet = 1;
Daniel Veillarddb68b742005-07-30 13:18:24 +00004550 else {
4551 for (i = 0; testDescriptions[i].func != NULL; i++) {
4552 if (strstr(testDescriptions[i].desc, argv[a])) {
4553 ret += runtest(i);
4554 subset++;
4555 }
4556 }
4557 }
4558 }
4559 if (subset == 0) {
4560 for (i = 0; testDescriptions[i].func != NULL; i++) {
4561 ret += runtest(i);
William M. Brackca15a542005-07-06 20:41:33 +00004562 }
4563 }
4564 if ((nb_errors == 0) && (nb_leaks == 0)) {
4565 ret = 0;
4566 printf("Total %d tests, no errors\n",
4567 nb_tests);
4568 } else {
4569 ret = 1;
4570 printf("Total %d tests, %d errors, %d leaks\n",
4571 nb_tests, nb_errors, nb_leaks);
4572 }
4573 xmlCleanupParser();
4574 xmlMemoryDump();
4575
4576 return(ret);
4577}
4578
4579#else /* ! LIBXML_OUTPUT_ENABLED */
4580int
4581main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
4582 fprintf(stderr, "runtest requires output to be enabled in libxml2\n");
4583 return(1);
4584}
4585#endif