blob: 0f178cb050af8065dc542857d8c722c015d38046 [file] [log] [blame]
William M. Brackca15a542005-07-06 20:41:33 +00001/*
2 * runtest.c: C program to run libxml2 regression tests without
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003 * requiring make or Python, and reducing platform dependencies
William M. Brackca15a542005-07-06 20:41:33 +00004 * 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 {
Haibo Huangcfd91dc2020-07-30 23:01:33 -070098 const char *desc; /* description of the test */
William M. Brackca15a542005-07-06 20:41:33 +000099 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;
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700108static char* temp_directory = NULL;
William M. Brackca15a542005-07-06 20:41:33 +0000109static int checkTestFile(const char *filename);
110
111#if defined(_WIN32) && !defined(__CYGWIN__)
112
113#include <windows.h>
114#include <io.h>
115
116typedef struct
117{
118 size_t gl_pathc; /* Count of paths matched so far */
119 char **gl_pathv; /* List of matched pathnames. */
120 size_t gl_offs; /* Slots to reserve in 'gl_pathv'. */
121} glob_t;
122
123#define GLOB_DOOFFS 0
Nick Wellnhofer82e03942017-10-09 02:05:41 +0200124static int glob(const char *pattern, ATTRIBUTE_UNUSED int flags,
125 ATTRIBUTE_UNUSED int errfunc(const char *epath, int eerrno),
William M. Brackca15a542005-07-06 20:41:33 +0000126 glob_t *pglob) {
127 glob_t *ret;
128 WIN32_FIND_DATA FindFileData;
129 HANDLE hFind;
130 unsigned int nb_paths = 0;
131 char directory[500];
132 int len;
133
134 if ((pattern == NULL) || (pglob == NULL)) return(-1);
Daniel Veillardaa6de472008-08-25 14:53:31 +0000135
William M. Brackca15a542005-07-06 20:41:33 +0000136 strncpy(directory, pattern, 499);
137 for (len = strlen(directory);len >= 0;len--) {
138 if (directory[len] == '/') {
139 len++;
140 directory[len] = 0;
141 break;
142 }
143 }
144 if (len <= 0)
145 len = 0;
146
Daniel Veillardaa6de472008-08-25 14:53:31 +0000147
William M. Brackca15a542005-07-06 20:41:33 +0000148 ret = pglob;
149 memset(ret, 0, sizeof(glob_t));
Daniel Veillardaa6de472008-08-25 14:53:31 +0000150
William M. Brackca15a542005-07-06 20:41:33 +0000151 hFind = FindFirstFileA(pattern, &FindFileData);
Daniel Veillardaa6de472008-08-25 14:53:31 +0000152 if (hFind == INVALID_HANDLE_VALUE)
William M. Brackca15a542005-07-06 20:41:33 +0000153 return(0);
154 nb_paths = 20;
155 ret->gl_pathv = (char **) malloc(nb_paths * sizeof(char *));
156 if (ret->gl_pathv == NULL) {
157 FindClose(hFind);
158 return(-1);
159 }
160 strncpy(directory + len, FindFileData.cFileName, 499 - len);
161 ret->gl_pathv[ret->gl_pathc] = strdup(directory);
162 if (ret->gl_pathv[ret->gl_pathc] == NULL)
163 goto done;
164 ret->gl_pathc++;
165 while(FindNextFileA(hFind, &FindFileData)) {
166 if (FindFileData.cFileName[0] == '.')
167 continue;
168 if (ret->gl_pathc + 2 > nb_paths) {
169 char **tmp = realloc(ret->gl_pathv, nb_paths * 2 * sizeof(char *));
170 if (tmp == NULL)
171 break;
172 ret->gl_pathv = tmp;
173 nb_paths *= 2;
174 }
175 strncpy(directory + len, FindFileData.cFileName, 499 - len);
176 ret->gl_pathv[ret->gl_pathc] = strdup(directory);
177 if (ret->gl_pathv[ret->gl_pathc] == NULL)
178 break;
179 ret->gl_pathc++;
180 }
181 ret->gl_pathv[ret->gl_pathc] = NULL;
182
183done:
184 FindClose(hFind);
185 return(0);
186}
Daniel Veillardaa6de472008-08-25 14:53:31 +0000187
William M. Brackca15a542005-07-06 20:41:33 +0000188
189
190static void globfree(glob_t *pglob) {
191 unsigned int i;
192 if (pglob == NULL)
193 return;
Daniel Veillardaa6de472008-08-25 14:53:31 +0000194
William M. Brackca15a542005-07-06 20:41:33 +0000195 for (i = 0;i < pglob->gl_pathc;i++) {
196 if (pglob->gl_pathv[i] != NULL)
197 free(pglob->gl_pathv[i]);
198 }
199}
Daniel Veillard22030ef2012-05-23 15:52:45 +0800200
William M. Brackca15a542005-07-06 20:41:33 +0000201#else
202#include <glob.h>
203#endif
204
205/************************************************************************
206 * *
207 * Libxml2 specific routines *
208 * *
209 ************************************************************************/
210
211static int nb_tests = 0;
212static int nb_errors = 0;
213static int nb_leaks = 0;
William M. Brackca15a542005-07-06 20:41:33 +0000214static int extraMemoryFromResolver = 0;
215
216static int
217fatalError(void) {
218 fprintf(stderr, "Exitting tests on fatal error\n");
219 exit(1);
220}
221
222/*
223 * We need to trap calls to the resolver to not account memory for the catalog
224 * which is shared to the current running test. We also don't want to have
225 * network downloads modifying tests.
226 */
Daniel Veillardaa6de472008-08-25 14:53:31 +0000227static xmlParserInputPtr
William M. Brackca15a542005-07-06 20:41:33 +0000228testExternalEntityLoader(const char *URL, const char *ID,
229 xmlParserCtxtPtr ctxt) {
230 xmlParserInputPtr ret;
231
232 if (checkTestFile(URL)) {
233 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
234 } else {
235 int memused = xmlMemUsed();
236 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
237 extraMemoryFromResolver += xmlMemUsed() - memused;
238 }
Daniel Veillardaa6de472008-08-25 14:53:31 +0000239
William M. Brackca15a542005-07-06 20:41:33 +0000240 return(ret);
241}
242
243/*
244 * Trapping the error messages at the generic level to grab the equivalent of
245 * stderr messages on CLI tools.
246 */
247static char testErrors[32769];
248static int testErrorsSize = 0;
249
Daniel Veillardffa3c742005-07-21 13:24:09 +0000250static void XMLCDECL
William M. Brackca15a542005-07-06 20:41:33 +0000251testErrorHandler(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
252 va_list args;
253 int res;
254
255 if (testErrorsSize >= 32768)
256 return;
257 va_start(args, msg);
258 res = vsnprintf(&testErrors[testErrorsSize],
259 32768 - testErrorsSize,
260 msg, args);
261 va_end(args);
262 if (testErrorsSize + res >= 32768) {
263 /* buffer is full */
264 testErrorsSize = 32768;
265 testErrors[testErrorsSize] = 0;
266 } else {
267 testErrorsSize += res;
268 }
269 testErrors[testErrorsSize] = 0;
270}
271
Daniel Veillardffa3c742005-07-21 13:24:09 +0000272static void XMLCDECL
William M. Brackca15a542005-07-06 20:41:33 +0000273channel(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
274 va_list args;
275 int res;
276
277 if (testErrorsSize >= 32768)
278 return;
279 va_start(args, msg);
280 res = vsnprintf(&testErrors[testErrorsSize],
281 32768 - testErrorsSize,
282 msg, args);
283 va_end(args);
284 if (testErrorsSize + res >= 32768) {
285 /* buffer is full */
286 testErrorsSize = 32768;
287 testErrors[testErrorsSize] = 0;
288 } else {
289 testErrorsSize += res;
290 }
291 testErrors[testErrorsSize] = 0;
292}
293
294/**
295 * xmlParserPrintFileContext:
296 * @input: an xmlParserInputPtr input
Daniel Veillardaa6de472008-08-25 14:53:31 +0000297 *
William M. Brackca15a542005-07-06 20:41:33 +0000298 * Displays current context within the input content for error tracking
299 */
300
301static void
Daniel Veillardaa6de472008-08-25 14:53:31 +0000302xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
William M. Brackca15a542005-07-06 20:41:33 +0000303 xmlGenericErrorFunc chanl, void *data ) {
304 const xmlChar *cur, *base;
305 unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */
306 xmlChar content[81]; /* space for 80 chars + line terminator */
307 xmlChar *ctnt;
308
309 if (input == NULL) return;
310 cur = input->cur;
311 base = input->base;
312 /* skip backwards over any end-of-lines */
313 while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
314 cur--;
315 }
316 n = 0;
317 /* search backwards for beginning-of-line (to max buff size) */
Daniel Veillardaa6de472008-08-25 14:53:31 +0000318 while ((n++ < (sizeof(content)-1)) && (cur > base) &&
319 (*(cur) != '\n') && (*(cur) != '\r'))
William M. Brackca15a542005-07-06 20:41:33 +0000320 cur--;
321 if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
322 /* calculate the error position in terms of the current position */
323 col = input->cur - cur;
324 /* search forward for end-of-line (to max buff size) */
325 n = 0;
326 ctnt = content;
327 /* copy selected text to our buffer */
Daniel Veillardaa6de472008-08-25 14:53:31 +0000328 while ((*cur != 0) && (*(cur) != '\n') &&
329 (*(cur) != '\r') && (n < sizeof(content)-1)) {
William M. Brackca15a542005-07-06 20:41:33 +0000330 *ctnt++ = *cur++;
331 n++;
332 }
333 *ctnt = 0;
334 /* print out the selected text */
335 chanl(data ,"%s\n", content);
336 /* create blank line with problem pointer */
337 n = 0;
338 ctnt = content;
339 /* (leave buffer space for pointer + line terminator) */
340 while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
341 if (*(ctnt) != '\t')
342 *(ctnt) = ' ';
343 ctnt++;
344 }
345 *ctnt++ = '^';
346 *ctnt = 0;
347 chanl(data ,"%s\n", content);
348}
349
350static void
351testStructuredErrorHandler(void *ctx ATTRIBUTE_UNUSED, xmlErrorPtr err) {
352 char *file = NULL;
353 int line = 0;
354 int code = -1;
355 int domain;
356 void *data = NULL;
357 const char *str;
358 const xmlChar *name = NULL;
359 xmlNodePtr node;
360 xmlErrorLevel level;
361 xmlParserInputPtr input = NULL;
362 xmlParserInputPtr cur = NULL;
363 xmlParserCtxtPtr ctxt = NULL;
364
365 if (err == NULL)
366 return;
367
368 file = err->file;
369 line = err->line;
370 code = err->code;
371 domain = err->domain;
372 level = err->level;
373 node = err->node;
374 if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
375 (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
376 (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
377 ctxt = err->ctxt;
378 }
379 str = err->message;
380
381 if (code == XML_ERR_OK)
382 return;
383
384 if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
385 name = node->name;
386
387 /*
388 * Maintain the compatibility with the legacy error handling
389 */
390 if (ctxt != NULL) {
391 input = ctxt->input;
392 if ((input != NULL) && (input->filename == NULL) &&
393 (ctxt->inputNr > 1)) {
394 cur = input;
395 input = ctxt->inputTab[ctxt->inputNr - 2];
396 }
397 if (input != NULL) {
398 if (input->filename)
399 channel(data, "%s:%d: ", input->filename, input->line);
400 else if ((line != 0) && (domain == XML_FROM_PARSER))
401 channel(data, "Entity: line %d: ", input->line);
402 }
403 } else {
404 if (file != NULL)
405 channel(data, "%s:%d: ", file, line);
406 else if ((line != 0) && (domain == XML_FROM_PARSER))
407 channel(data, "Entity: line %d: ", line);
408 }
409 if (name != NULL) {
410 channel(data, "element %s: ", name);
411 }
412 if (code == XML_ERR_OK)
413 return;
414 switch (domain) {
415 case XML_FROM_PARSER:
416 channel(data, "parser ");
417 break;
418 case XML_FROM_NAMESPACE:
419 channel(data, "namespace ");
420 break;
421 case XML_FROM_DTD:
422 case XML_FROM_VALID:
423 channel(data, "validity ");
424 break;
425 case XML_FROM_HTML:
426 channel(data, "HTML parser ");
427 break;
428 case XML_FROM_MEMORY:
429 channel(data, "memory ");
430 break;
431 case XML_FROM_OUTPUT:
432 channel(data, "output ");
433 break;
434 case XML_FROM_IO:
435 channel(data, "I/O ");
436 break;
437 case XML_FROM_XINCLUDE:
438 channel(data, "XInclude ");
439 break;
440 case XML_FROM_XPATH:
441 channel(data, "XPath ");
442 break;
443 case XML_FROM_XPOINTER:
444 channel(data, "parser ");
445 break;
446 case XML_FROM_REGEXP:
447 channel(data, "regexp ");
448 break;
449 case XML_FROM_MODULE:
450 channel(data, "module ");
451 break;
452 case XML_FROM_SCHEMASV:
453 channel(data, "Schemas validity ");
454 break;
455 case XML_FROM_SCHEMASP:
456 channel(data, "Schemas parser ");
457 break;
458 case XML_FROM_RELAXNGP:
459 channel(data, "Relax-NG parser ");
460 break;
461 case XML_FROM_RELAXNGV:
462 channel(data, "Relax-NG validity ");
463 break;
464 case XML_FROM_CATALOG:
465 channel(data, "Catalog ");
466 break;
467 case XML_FROM_C14N:
468 channel(data, "C14N ");
469 break;
470 case XML_FROM_XSLT:
471 channel(data, "XSLT ");
472 break;
473 default:
474 break;
475 }
476 if (code == XML_ERR_OK)
477 return;
478 switch (level) {
479 case XML_ERR_NONE:
480 channel(data, ": ");
481 break;
482 case XML_ERR_WARNING:
483 channel(data, "warning : ");
484 break;
485 case XML_ERR_ERROR:
486 channel(data, "error : ");
487 break;
488 case XML_ERR_FATAL:
489 channel(data, "error : ");
490 break;
491 }
492 if (code == XML_ERR_OK)
493 return;
494 if (str != NULL) {
495 int len;
496 len = xmlStrlen((const xmlChar *)str);
497 if ((len > 0) && (str[len - 1] != '\n'))
498 channel(data, "%s\n", str);
499 else
500 channel(data, "%s", str);
501 } else {
502 channel(data, "%s\n", "out of memory error");
503 }
504 if (code == XML_ERR_OK)
505 return;
506
507 if (ctxt != NULL) {
508 xmlParserPrintFileContextInternal(input, channel, data);
509 if (cur != NULL) {
510 if (cur->filename)
511 channel(data, "%s:%d: \n", cur->filename, cur->line);
512 else if ((line != 0) && (domain == XML_FROM_PARSER))
513 channel(data, "Entity: line %d: \n", cur->line);
514 xmlParserPrintFileContextInternal(cur, channel, data);
515 }
516 }
517 if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
518 (err->int1 < 100) &&
519 (err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
520 xmlChar buf[150];
521 int i;
522
523 channel(data, "%s\n", err->str1);
524 for (i=0;i < err->int1;i++)
525 buf[i] = ' ';
526 buf[i++] = '^';
527 buf[i] = 0;
528 channel(data, "%s\n", buf);
529 }
530}
531
532static void
533initializeLibxml2(void) {
534 xmlGetWarningsDefaultValue = 0;
535 xmlPedanticParserDefault(0);
536
537 xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
538 xmlInitParser();
539 xmlSetExternalEntityLoader(testExternalEntityLoader);
540 xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
541#ifdef LIBXML_SCHEMAS_ENABLED
542 xmlSchemaInitTypes();
543 xmlRelaxNGInitTypes();
544#endif
William M. Brackca15a542005-07-06 20:41:33 +0000545}
546
547
548/************************************************************************
549 * *
550 * File name and path utilities *
551 * *
552 ************************************************************************/
553
554static const char *baseFilename(const char *filename) {
555 const char *cur;
556 if (filename == NULL)
557 return(NULL);
558 cur = &filename[strlen(filename)];
559 while ((cur > filename) && (*cur != '/'))
560 cur--;
561 if (*cur == '/')
562 return(cur + 1);
563 return(cur);
564}
565
566static char *resultFilename(const char *filename, const char *out,
567 const char *suffix) {
568 const char *base;
569 char res[500];
Daniel Veillard381ff362006-06-18 17:31:31 +0000570 char suffixbuff[500];
William M. Brackca15a542005-07-06 20:41:33 +0000571
572/*************
573 if ((filename[0] == 't') && (filename[1] == 'e') &&
574 (filename[2] == 's') && (filename[3] == 't') &&
575 (filename[4] == '/'))
576 filename = &filename[5];
577 *************/
Daniel Veillardaa6de472008-08-25 14:53:31 +0000578
William M. Brackca15a542005-07-06 20:41:33 +0000579 base = baseFilename(filename);
580 if (suffix == NULL)
581 suffix = ".tmp";
582 if (out == NULL)
583 out = "";
Daniel Veillard381ff362006-06-18 17:31:31 +0000584
585 strncpy(suffixbuff,suffix,499);
586#ifdef VMS
587 if(strstr(base,".") && suffixbuff[0]=='.')
588 suffixbuff[0]='_';
589#endif
590
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700591 if (snprintf(res, 499, "%s%s%s", out, base, suffixbuff) >= 499)
592 res[499] = 0;
William M. Brackca15a542005-07-06 20:41:33 +0000593 return(strdup(res));
594}
595
596static int checkTestFile(const char *filename) {
597 struct stat buf;
598
599 if (stat(filename, &buf) == -1)
600 return(0);
601
602#if defined(_WIN32) && !defined(__CYGWIN__)
603 if (!(buf.st_mode & _S_IFREG))
604 return(0);
605#else
606 if (!S_ISREG(buf.st_mode))
607 return(0);
608#endif
609
610 return(1);
611}
612
David Kilzer5c373822016-05-22 09:58:30 +0800613static int compareFiles(const char *r1 /* temp */, const char *r2 /* result */) {
William M. Brackca15a542005-07-06 20:41:33 +0000614 int res1, res2;
615 int fd1, fd2;
616 char bytes1[4096];
617 char bytes2[4096];
618
David Kilzer5c373822016-05-22 09:58:30 +0800619 if (update_results) {
620 fd1 = open(r1, RD_FLAGS);
621 if (fd1 < 0)
622 return(-1);
623 fd2 = open(r2, WR_FLAGS, 0644);
624 if (fd2 < 0) {
625 close(fd1);
626 return(-1);
627 }
628 do {
629 res1 = read(fd1, bytes1, 4096);
630 if (res1 <= 0)
631 break;
632 res2 = write(fd2, bytes1, res1);
633 if (res2 <= 0 || res2 != res1)
634 break;
635 } while (1);
636 close(fd2);
637 close(fd1);
638 return(res1 != 0);
639 }
640
William M. Brackca15a542005-07-06 20:41:33 +0000641 fd1 = open(r1, RD_FLAGS);
642 if (fd1 < 0)
643 return(-1);
644 fd2 = open(r2, RD_FLAGS);
645 if (fd2 < 0) {
646 close(fd1);
647 return(-1);
648 }
649 while (1) {
650 res1 = read(fd1, bytes1, 4096);
651 res2 = read(fd2, bytes2, 4096);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000652 if ((res1 != res2) || (res1 < 0)) {
William M. Brackca15a542005-07-06 20:41:33 +0000653 close(fd1);
654 close(fd2);
655 return(1);
656 }
657 if (res1 == 0)
658 break;
659 if (memcmp(bytes1, bytes2, res1) != 0) {
660 close(fd1);
661 close(fd2);
662 return(1);
663 }
664 }
665 close(fd1);
666 close(fd2);
667 return(0);
668}
669
670static int compareFileMem(const char *filename, const char *mem, int size) {
671 int res;
672 int fd;
673 char bytes[4096];
674 int idx = 0;
675 struct stat info;
676
David Kilzer5c373822016-05-22 09:58:30 +0800677 if (update_results) {
678 fd = open(filename, WR_FLAGS, 0644);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800679 if (fd < 0) {
680 fprintf(stderr, "failed to open %s for writing", filename);
David Kilzer5c373822016-05-22 09:58:30 +0800681 return(-1);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800682 }
David Kilzer5c373822016-05-22 09:58:30 +0800683 res = write(fd, mem, size);
684 close(fd);
685 return(res != size);
686 }
687
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800688 if (stat(filename, &info) < 0) {
689 fprintf(stderr, "failed to stat %s\n", filename);
William M. Brackca15a542005-07-06 20:41:33 +0000690 return(-1);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800691 }
692 if (info.st_size != size) {
693 fprintf(stderr, "file %s is %ld bytes, result is %d bytes\n",
Nick Wellnhoferc2545cb2016-08-22 11:44:18 +0200694 filename, (long) info.st_size, size);
William M. Brackca15a542005-07-06 20:41:33 +0000695 return(-1);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800696 }
William M. Brackca15a542005-07-06 20:41:33 +0000697 fd = open(filename, RD_FLAGS);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800698 if (fd < 0) {
699 fprintf(stderr, "failed to open %s for reading", filename);
William M. Brackca15a542005-07-06 20:41:33 +0000700 return(-1);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800701 }
William M. Brackca15a542005-07-06 20:41:33 +0000702 while (idx < size) {
703 res = read(fd, bytes, 4096);
704 if (res <= 0)
705 break;
Daniel Veillardaa6de472008-08-25 14:53:31 +0000706 if (res + idx > size)
William M. Brackca15a542005-07-06 20:41:33 +0000707 break;
708 if (memcmp(bytes, &mem[idx], res) != 0) {
709 int ix;
710 for (ix=0; ix<res; ix++)
711 if (bytes[ix] != mem[idx+ix])
712 break;
713 fprintf(stderr,"Compare error at position %d\n", idx+ix);
714 close(fd);
715 return(1);
716 }
717 idx += res;
718 }
719 close(fd);
Daniel Veillard9f2416c2016-05-22 11:14:45 +0800720 if (idx != size) {
721 fprintf(stderr,"Compare error index %d, size %d\n", idx, size);
722 }
William M. Brackca15a542005-07-06 20:41:33 +0000723 return(idx != size);
724}
725
726static int loadMem(const char *filename, const char **mem, int *size) {
727 int fd, res;
728 struct stat info;
729 char *base;
730 int siz = 0;
Daniel Veillardaa6de472008-08-25 14:53:31 +0000731 if (stat(filename, &info) < 0)
William M. Brackca15a542005-07-06 20:41:33 +0000732 return(-1);
733 base = malloc(info.st_size + 1);
734 if (base == NULL)
735 return(-1);
736 if ((fd = open(filename, RD_FLAGS)) < 0) {
737 free(base);
738 return(-1);
739 }
740 while ((res = read(fd, &base[siz], info.st_size - siz)) > 0) {
741 siz += res;
742 }
743 close(fd);
744#if !defined(_WIN32)
745 if (siz != info.st_size) {
746 free(base);
747 return(-1);
748 }
749#endif
750 base[siz] = 0;
751 *mem = base;
752 *size = siz;
753 return(0);
754}
755
756static int unloadMem(const char *mem) {
757 free((char *)mem);
758 return(0);
759}
760
761/************************************************************************
762 * *
763 * Tests implementations *
764 * *
765 ************************************************************************/
766
767/************************************************************************
768 * *
769 * Parse to SAX based tests *
770 * *
771 ************************************************************************/
772
Daniel Veillard24505b02005-07-28 23:49:35 +0000773static FILE *SAXdebug = NULL;
William M. Brackca15a542005-07-06 20:41:33 +0000774
775/*
776 * empty SAX block
777 */
Daniel Veillard24505b02005-07-28 23:49:35 +0000778static xmlSAXHandler emptySAXHandlerStruct = {
William M. Brackca15a542005-07-06 20:41:33 +0000779 NULL, /* internalSubset */
780 NULL, /* isStandalone */
781 NULL, /* hasInternalSubset */
782 NULL, /* hasExternalSubset */
783 NULL, /* resolveEntity */
784 NULL, /* getEntity */
785 NULL, /* entityDecl */
786 NULL, /* notationDecl */
787 NULL, /* attributeDecl */
788 NULL, /* elementDecl */
789 NULL, /* unparsedEntityDecl */
790 NULL, /* setDocumentLocator */
791 NULL, /* startDocument */
792 NULL, /* endDocument */
793 NULL, /* startElement */
794 NULL, /* endElement */
795 NULL, /* reference */
796 NULL, /* characters */
797 NULL, /* ignorableWhitespace */
798 NULL, /* processingInstruction */
799 NULL, /* comment */
800 NULL, /* xmlParserWarning */
801 NULL, /* xmlParserError */
802 NULL, /* xmlParserError */
803 NULL, /* getParameterEntity */
804 NULL, /* cdataBlock; */
805 NULL, /* externalSubset; */
806 1,
807 NULL,
808 NULL, /* startElementNs */
809 NULL, /* endElementNs */
810 NULL /* xmlStructuredErrorFunc */
811};
812
813static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct;
Daniel Veillard24505b02005-07-28 23:49:35 +0000814static int callbacks = 0;
815static int quiet = 0;
William M. Brackca15a542005-07-06 20:41:33 +0000816
817/**
818 * isStandaloneDebug:
819 * @ctxt: An XML parser context
820 *
821 * Is this document tagged standalone ?
822 *
823 * Returns 1 if true
824 */
825static int
826isStandaloneDebug(void *ctx ATTRIBUTE_UNUSED)
827{
828 callbacks++;
829 if (quiet)
830 return(0);
831 fprintf(SAXdebug, "SAX.isStandalone()\n");
832 return(0);
833}
834
835/**
836 * hasInternalSubsetDebug:
837 * @ctxt: An XML parser context
838 *
839 * Does this document has an internal subset
840 *
841 * Returns 1 if true
842 */
843static int
844hasInternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
845{
846 callbacks++;
847 if (quiet)
848 return(0);
849 fprintf(SAXdebug, "SAX.hasInternalSubset()\n");
850 return(0);
851}
852
853/**
854 * hasExternalSubsetDebug:
855 * @ctxt: An XML parser context
856 *
857 * Does this document has an external subset
858 *
859 * Returns 1 if true
860 */
861static int
862hasExternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
863{
864 callbacks++;
865 if (quiet)
866 return(0);
867 fprintf(SAXdebug, "SAX.hasExternalSubset()\n");
868 return(0);
869}
870
871/**
872 * internalSubsetDebug:
873 * @ctxt: An XML parser context
874 *
875 * Does this document has an internal subset
876 */
877static void
878internalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
879 const xmlChar *ExternalID, const xmlChar *SystemID)
880{
881 callbacks++;
882 if (quiet)
883 return;
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700884 if (name == NULL)
885 name = BAD_CAST "(null)";
William M. Brackca15a542005-07-06 20:41:33 +0000886 fprintf(SAXdebug, "SAX.internalSubset(%s,", name);
887 if (ExternalID == NULL)
888 fprintf(SAXdebug, " ,");
889 else
890 fprintf(SAXdebug, " %s,", ExternalID);
891 if (SystemID == NULL)
892 fprintf(SAXdebug, " )\n");
893 else
894 fprintf(SAXdebug, " %s)\n", SystemID);
895}
896
897/**
898 * externalSubsetDebug:
899 * @ctxt: An XML parser context
900 *
901 * Does this document has an external subset
902 */
903static void
904externalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
905 const xmlChar *ExternalID, const xmlChar *SystemID)
906{
907 callbacks++;
908 if (quiet)
909 return;
910 fprintf(SAXdebug, "SAX.externalSubset(%s,", name);
911 if (ExternalID == NULL)
912 fprintf(SAXdebug, " ,");
913 else
914 fprintf(SAXdebug, " %s,", ExternalID);
915 if (SystemID == NULL)
916 fprintf(SAXdebug, " )\n");
917 else
918 fprintf(SAXdebug, " %s)\n", SystemID);
919}
920
921/**
922 * resolveEntityDebug:
923 * @ctxt: An XML parser context
924 * @publicId: The public ID of the entity
925 * @systemId: The system ID of the entity
926 *
927 * Special entity resolver, better left to the parser, it has
928 * more context than the application layer.
929 * The default behaviour is to NOT resolve the entities, in that case
930 * the ENTITY_REF nodes are built in the structure (and the parameter
931 * values).
932 *
933 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
934 */
935static xmlParserInputPtr
936resolveEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *publicId, const xmlChar *systemId)
937{
938 callbacks++;
939 if (quiet)
940 return(NULL);
941 /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
942
Daniel Veillardaa6de472008-08-25 14:53:31 +0000943
William M. Brackca15a542005-07-06 20:41:33 +0000944 fprintf(SAXdebug, "SAX.resolveEntity(");
945 if (publicId != NULL)
946 fprintf(SAXdebug, "%s", (char *)publicId);
947 else
948 fprintf(SAXdebug, " ");
949 if (systemId != NULL)
950 fprintf(SAXdebug, ", %s)\n", (char *)systemId);
951 else
952 fprintf(SAXdebug, ", )\n");
953/*********
954 if (systemId != NULL) {
955 return(xmlNewInputFromFile(ctxt, (char *) systemId));
956 }
957 *********/
958 return(NULL);
959}
960
961/**
962 * getEntityDebug:
963 * @ctxt: An XML parser context
964 * @name: The entity name
965 *
966 * Get an entity by name
967 *
968 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
969 */
970static xmlEntityPtr
971getEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
972{
973 callbacks++;
974 if (quiet)
975 return(NULL);
976 fprintf(SAXdebug, "SAX.getEntity(%s)\n", name);
977 return(NULL);
978}
979
980/**
981 * getParameterEntityDebug:
982 * @ctxt: An XML parser context
983 * @name: The entity name
984 *
985 * Get a parameter entity by name
986 *
987 * Returns the xmlParserInputPtr
988 */
989static xmlEntityPtr
990getParameterEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
991{
992 callbacks++;
993 if (quiet)
994 return(NULL);
995 fprintf(SAXdebug, "SAX.getParameterEntity(%s)\n", name);
996 return(NULL);
997}
998
999
1000/**
1001 * entityDeclDebug:
1002 * @ctxt: An XML parser context
Daniel Veillardaa6de472008-08-25 14:53:31 +00001003 * @name: the entity name
1004 * @type: the entity type
William M. Brackca15a542005-07-06 20:41:33 +00001005 * @publicId: The public ID of the entity
1006 * @systemId: The system ID of the entity
1007 * @content: the entity value (without processing).
1008 *
1009 * An entity definition has been parsed
1010 */
1011static void
1012entityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
1013 const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
1014{
1015const xmlChar *nullstr = BAD_CAST "(null)";
1016 /* not all libraries handle printing null pointers nicely */
1017 if (publicId == NULL)
1018 publicId = nullstr;
1019 if (systemId == NULL)
1020 systemId = nullstr;
1021 if (content == NULL)
1022 content = (xmlChar *)nullstr;
1023 callbacks++;
1024 if (quiet)
1025 return;
1026 fprintf(SAXdebug, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
1027 name, type, publicId, systemId, content);
1028}
1029
1030/**
1031 * attributeDeclDebug:
1032 * @ctxt: An XML parser context
Daniel Veillardaa6de472008-08-25 14:53:31 +00001033 * @name: the attribute name
1034 * @type: the attribute type
William M. Brackca15a542005-07-06 20:41:33 +00001035 *
1036 * An attribute definition has been parsed
1037 */
1038static void
1039attributeDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar * elem,
1040 const xmlChar * name, int type, int def,
1041 const xmlChar * defaultValue, xmlEnumerationPtr tree)
1042{
1043 callbacks++;
1044 if (quiet)
1045 return;
1046 if (defaultValue == NULL)
1047 fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, NULL, ...)\n",
1048 elem, name, type, def);
1049 else
1050 fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
1051 elem, name, type, def, defaultValue);
1052 xmlFreeEnumeration(tree);
1053}
1054
1055/**
1056 * elementDeclDebug:
1057 * @ctxt: An XML parser context
Daniel Veillardaa6de472008-08-25 14:53:31 +00001058 * @name: the element name
1059 * @type: the element type
William M. Brackca15a542005-07-06 20:41:33 +00001060 * @content: the element value (without processing).
1061 *
1062 * An element definition has been parsed
1063 */
1064static void
1065elementDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
1066 xmlElementContentPtr content ATTRIBUTE_UNUSED)
1067{
1068 callbacks++;
1069 if (quiet)
1070 return;
1071 fprintf(SAXdebug, "SAX.elementDecl(%s, %d, ...)\n",
1072 name, type);
1073}
1074
1075/**
1076 * notationDeclDebug:
1077 * @ctxt: An XML parser context
1078 * @name: The name of the notation
1079 * @publicId: The public ID of the entity
1080 * @systemId: The system ID of the entity
1081 *
1082 * What to do when a notation declaration has been parsed.
1083 */
1084static void
1085notationDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
1086 const xmlChar *publicId, const xmlChar *systemId)
1087{
1088 callbacks++;
1089 if (quiet)
1090 return;
1091 fprintf(SAXdebug, "SAX.notationDecl(%s, %s, %s)\n",
1092 (char *) name, (char *) publicId, (char *) systemId);
1093}
1094
1095/**
1096 * unparsedEntityDeclDebug:
1097 * @ctxt: An XML parser context
1098 * @name: The name of the entity
1099 * @publicId: The public ID of the entity
1100 * @systemId: The system ID of the entity
1101 * @notationName: the name of the notation
1102 *
1103 * What to do when an unparsed entity declaration is parsed
1104 */
1105static void
1106unparsedEntityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
1107 const xmlChar *publicId, const xmlChar *systemId,
1108 const xmlChar *notationName)
1109{
1110const xmlChar *nullstr = BAD_CAST "(null)";
1111
1112 if (publicId == NULL)
1113 publicId = nullstr;
1114 if (systemId == NULL)
1115 systemId = nullstr;
1116 if (notationName == NULL)
1117 notationName = nullstr;
1118 callbacks++;
1119 if (quiet)
1120 return;
1121 fprintf(SAXdebug, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
1122 (char *) name, (char *) publicId, (char *) systemId,
1123 (char *) notationName);
1124}
1125
1126/**
1127 * setDocumentLocatorDebug:
1128 * @ctxt: An XML parser context
1129 * @loc: A SAX Locator
1130 *
1131 * Receive the document locator at startup, actually xmlDefaultSAXLocator
1132 * Everything is available on the context, so this is useless in our case.
1133 */
1134static void
1135setDocumentLocatorDebug(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
1136{
1137 callbacks++;
1138 if (quiet)
1139 return;
1140 fprintf(SAXdebug, "SAX.setDocumentLocator()\n");
1141}
1142
1143/**
1144 * startDocumentDebug:
1145 * @ctxt: An XML parser context
1146 *
1147 * called when the document start being processed.
1148 */
1149static void
1150startDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
1151{
1152 callbacks++;
1153 if (quiet)
1154 return;
1155 fprintf(SAXdebug, "SAX.startDocument()\n");
1156}
1157
1158/**
1159 * endDocumentDebug:
1160 * @ctxt: An XML parser context
1161 *
1162 * called when the document end has been detected.
1163 */
1164static void
1165endDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
1166{
1167 callbacks++;
1168 if (quiet)
1169 return;
1170 fprintf(SAXdebug, "SAX.endDocument()\n");
1171}
1172
1173/**
1174 * startElementDebug:
1175 * @ctxt: An XML parser context
1176 * @name: The element name
1177 *
1178 * called when an opening tag has been processed.
1179 */
1180static void
1181startElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
1182{
1183 int i;
1184
1185 callbacks++;
1186 if (quiet)
1187 return;
1188 fprintf(SAXdebug, "SAX.startElement(%s", (char *) name);
1189 if (atts != NULL) {
1190 for (i = 0;(atts[i] != NULL);i++) {
1191 fprintf(SAXdebug, ", %s='", atts[i++]);
1192 if (atts[i] != NULL)
1193 fprintf(SAXdebug, "%s'", atts[i]);
1194 }
1195 }
1196 fprintf(SAXdebug, ")\n");
1197}
1198
1199/**
1200 * endElementDebug:
1201 * @ctxt: An XML parser context
1202 * @name: The element name
1203 *
1204 * called when the end of an element has been detected.
1205 */
1206static void
1207endElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
1208{
1209 callbacks++;
1210 if (quiet)
1211 return;
1212 fprintf(SAXdebug, "SAX.endElement(%s)\n", (char *) name);
1213}
1214
1215/**
1216 * charactersDebug:
1217 * @ctxt: An XML parser context
1218 * @ch: a xmlChar string
1219 * @len: the number of xmlChar
1220 *
1221 * receiving some chars from the parser.
1222 * Question: how much at a time ???
1223 */
1224static void
1225charactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1226{
1227 char output[40];
1228 int i;
1229
1230 callbacks++;
1231 if (quiet)
1232 return;
1233 for (i = 0;(i<len) && (i < 30);i++)
1234 output[i] = ch[i];
1235 output[i] = 0;
1236
1237 fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len);
1238}
1239
1240/**
1241 * referenceDebug:
1242 * @ctxt: An XML parser context
1243 * @name: The entity name
1244 *
Daniel Veillardaa6de472008-08-25 14:53:31 +00001245 * called when an entity reference is detected.
William M. Brackca15a542005-07-06 20:41:33 +00001246 */
1247static void
1248referenceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
1249{
1250 callbacks++;
1251 if (quiet)
1252 return;
1253 fprintf(SAXdebug, "SAX.reference(%s)\n", name);
1254}
1255
1256/**
1257 * ignorableWhitespaceDebug:
1258 * @ctxt: An XML parser context
1259 * @ch: a xmlChar string
1260 * @start: the first char in the string
1261 * @len: the number of xmlChar
1262 *
1263 * receiving some ignorable whitespaces from the parser.
1264 * Question: how much at a time ???
1265 */
1266static void
1267ignorableWhitespaceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1268{
1269 char output[40];
1270 int i;
1271
1272 callbacks++;
1273 if (quiet)
1274 return;
1275 for (i = 0;(i<len) && (i < 30);i++)
1276 output[i] = ch[i];
1277 output[i] = 0;
1278 fprintf(SAXdebug, "SAX.ignorableWhitespace(%s, %d)\n", output, len);
1279}
1280
1281/**
1282 * processingInstructionDebug:
1283 * @ctxt: An XML parser context
1284 * @target: the target name
1285 * @data: the PI data's
1286 * @len: the number of xmlChar
1287 *
1288 * A processing instruction has been parsed.
1289 */
1290static void
1291processingInstructionDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *target,
1292 const xmlChar *data)
1293{
1294 callbacks++;
1295 if (quiet)
1296 return;
1297 if (data != NULL)
1298 fprintf(SAXdebug, "SAX.processingInstruction(%s, %s)\n",
1299 (char *) target, (char *) data);
1300 else
1301 fprintf(SAXdebug, "SAX.processingInstruction(%s, NULL)\n",
1302 (char *) target);
1303}
1304
1305/**
1306 * cdataBlockDebug:
1307 * @ctx: the user data (XML parser context)
1308 * @value: The pcdata content
1309 * @len: the block length
1310 *
1311 * called when a pcdata block has been parsed
1312 */
1313static void
1314cdataBlockDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value, int len)
1315{
1316 callbacks++;
1317 if (quiet)
1318 return;
1319 fprintf(SAXdebug, "SAX.pcdata(%.20s, %d)\n",
1320 (char *) value, len);
1321}
1322
1323/**
1324 * commentDebug:
1325 * @ctxt: An XML parser context
1326 * @value: the comment content
1327 *
1328 * A comment has been parsed.
1329 */
1330static void
1331commentDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value)
1332{
1333 callbacks++;
1334 if (quiet)
1335 return;
1336 fprintf(SAXdebug, "SAX.comment(%s)\n", value);
1337}
1338
1339/**
1340 * warningDebug:
1341 * @ctxt: An XML parser context
1342 * @msg: the message to display/transmit
1343 * @...: extra parameters for the message display
1344 *
1345 * Display and format a warning messages, gives file, line, position and
1346 * extra parameters.
1347 */
Daniel Veillardffa3c742005-07-21 13:24:09 +00001348static void XMLCDECL
William M. Brackca15a542005-07-06 20:41:33 +00001349warningDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1350{
1351 va_list args;
1352
1353 callbacks++;
1354 if (quiet)
1355 return;
1356 va_start(args, msg);
1357 fprintf(SAXdebug, "SAX.warning: ");
1358 vfprintf(SAXdebug, msg, args);
1359 va_end(args);
1360}
1361
1362/**
1363 * errorDebug:
1364 * @ctxt: An XML parser context
1365 * @msg: the message to display/transmit
1366 * @...: extra parameters for the message display
1367 *
1368 * Display and format a error messages, gives file, line, position and
1369 * extra parameters.
1370 */
Daniel Veillardffa3c742005-07-21 13:24:09 +00001371static void XMLCDECL
William M. Brackca15a542005-07-06 20:41:33 +00001372errorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1373{
1374 va_list args;
1375
1376 callbacks++;
1377 if (quiet)
1378 return;
1379 va_start(args, msg);
1380 fprintf(SAXdebug, "SAX.error: ");
1381 vfprintf(SAXdebug, msg, args);
1382 va_end(args);
1383}
1384
1385/**
1386 * fatalErrorDebug:
1387 * @ctxt: An XML parser context
1388 * @msg: the message to display/transmit
1389 * @...: extra parameters for the message display
1390 *
1391 * Display and format a fatalError messages, gives file, line, position and
1392 * extra parameters.
1393 */
Daniel Veillardffa3c742005-07-21 13:24:09 +00001394static void XMLCDECL
William M. Brackca15a542005-07-06 20:41:33 +00001395fatalErrorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1396{
1397 va_list args;
1398
1399 callbacks++;
1400 if (quiet)
1401 return;
1402 va_start(args, msg);
1403 fprintf(SAXdebug, "SAX.fatalError: ");
1404 vfprintf(SAXdebug, msg, args);
1405 va_end(args);
1406}
1407
Daniel Veillard24505b02005-07-28 23:49:35 +00001408static xmlSAXHandler debugSAXHandlerStruct = {
William M. Brackca15a542005-07-06 20:41:33 +00001409 internalSubsetDebug,
1410 isStandaloneDebug,
1411 hasInternalSubsetDebug,
1412 hasExternalSubsetDebug,
1413 resolveEntityDebug,
1414 getEntityDebug,
1415 entityDeclDebug,
1416 notationDeclDebug,
1417 attributeDeclDebug,
1418 elementDeclDebug,
1419 unparsedEntityDeclDebug,
1420 setDocumentLocatorDebug,
1421 startDocumentDebug,
1422 endDocumentDebug,
1423 startElementDebug,
1424 endElementDebug,
1425 referenceDebug,
1426 charactersDebug,
1427 ignorableWhitespaceDebug,
1428 processingInstructionDebug,
1429 commentDebug,
1430 warningDebug,
1431 errorDebug,
1432 fatalErrorDebug,
1433 getParameterEntityDebug,
1434 cdataBlockDebug,
1435 externalSubsetDebug,
1436 1,
1437 NULL,
1438 NULL,
1439 NULL,
1440 NULL
1441};
1442
Daniel Veillard24505b02005-07-28 23:49:35 +00001443static xmlSAXHandlerPtr debugSAXHandler = &debugSAXHandlerStruct;
William M. Brackca15a542005-07-06 20:41:33 +00001444
1445/*
1446 * SAX2 specific callbacks
1447 */
1448/**
1449 * startElementNsDebug:
1450 * @ctxt: An XML parser context
1451 * @name: The element name
1452 *
1453 * called when an opening tag has been processed.
1454 */
1455static void
1456startElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
1457 const xmlChar *localname,
1458 const xmlChar *prefix,
1459 const xmlChar *URI,
1460 int nb_namespaces,
1461 const xmlChar **namespaces,
1462 int nb_attributes,
1463 int nb_defaulted,
1464 const xmlChar **attributes)
1465{
1466 int i;
1467
1468 callbacks++;
1469 if (quiet)
1470 return;
1471 fprintf(SAXdebug, "SAX.startElementNs(%s", (char *) localname);
1472 if (prefix == NULL)
1473 fprintf(SAXdebug, ", NULL");
1474 else
1475 fprintf(SAXdebug, ", %s", (char *) prefix);
1476 if (URI == NULL)
1477 fprintf(SAXdebug, ", NULL");
1478 else
1479 fprintf(SAXdebug, ", '%s'", (char *) URI);
1480 fprintf(SAXdebug, ", %d", nb_namespaces);
Daniel Veillardaa6de472008-08-25 14:53:31 +00001481
William M. Brackca15a542005-07-06 20:41:33 +00001482 if (namespaces != NULL) {
1483 for (i = 0;i < nb_namespaces * 2;i++) {
1484 fprintf(SAXdebug, ", xmlns");
1485 if (namespaces[i] != NULL)
1486 fprintf(SAXdebug, ":%s", namespaces[i]);
1487 i++;
1488 fprintf(SAXdebug, "='%s'", namespaces[i]);
1489 }
1490 }
1491 fprintf(SAXdebug, ", %d, %d", nb_attributes, nb_defaulted);
1492 if (attributes != NULL) {
1493 for (i = 0;i < nb_attributes * 5;i += 5) {
1494 if (attributes[i + 1] != NULL)
1495 fprintf(SAXdebug, ", %s:%s='", attributes[i + 1], attributes[i]);
1496 else
1497 fprintf(SAXdebug, ", %s='", attributes[i]);
1498 fprintf(SAXdebug, "%.4s...', %d", attributes[i + 3],
1499 (int)(attributes[i + 4] - attributes[i + 3]));
1500 }
1501 }
1502 fprintf(SAXdebug, ")\n");
1503}
1504
1505/**
1506 * endElementDebug:
1507 * @ctxt: An XML parser context
1508 * @name: The element name
1509 *
1510 * called when the end of an element has been detected.
1511 */
1512static void
1513endElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
1514 const xmlChar *localname,
1515 const xmlChar *prefix,
1516 const xmlChar *URI)
1517{
1518 callbacks++;
1519 if (quiet)
1520 return;
1521 fprintf(SAXdebug, "SAX.endElementNs(%s", (char *) localname);
1522 if (prefix == NULL)
1523 fprintf(SAXdebug, ", NULL");
1524 else
1525 fprintf(SAXdebug, ", %s", (char *) prefix);
1526 if (URI == NULL)
1527 fprintf(SAXdebug, ", NULL)\n");
1528 else
1529 fprintf(SAXdebug, ", '%s')\n", (char *) URI);
1530}
1531
Daniel Veillard24505b02005-07-28 23:49:35 +00001532static xmlSAXHandler debugSAX2HandlerStruct = {
William M. Brackca15a542005-07-06 20:41:33 +00001533 internalSubsetDebug,
1534 isStandaloneDebug,
1535 hasInternalSubsetDebug,
1536 hasExternalSubsetDebug,
1537 resolveEntityDebug,
1538 getEntityDebug,
1539 entityDeclDebug,
1540 notationDeclDebug,
1541 attributeDeclDebug,
1542 elementDeclDebug,
1543 unparsedEntityDeclDebug,
1544 setDocumentLocatorDebug,
1545 startDocumentDebug,
1546 endDocumentDebug,
1547 NULL,
1548 NULL,
1549 referenceDebug,
1550 charactersDebug,
1551 ignorableWhitespaceDebug,
1552 processingInstructionDebug,
1553 commentDebug,
1554 warningDebug,
1555 errorDebug,
1556 fatalErrorDebug,
1557 getParameterEntityDebug,
1558 cdataBlockDebug,
1559 externalSubsetDebug,
1560 XML_SAX2_MAGIC,
1561 NULL,
1562 startElementNsDebug,
1563 endElementNsDebug,
1564 NULL
1565};
1566
Daniel Veillard24505b02005-07-28 23:49:35 +00001567static xmlSAXHandlerPtr debugSAX2Handler = &debugSAX2HandlerStruct;
William M. Brackca15a542005-07-06 20:41:33 +00001568
1569#ifdef LIBXML_HTML_ENABLED
1570/**
1571 * htmlstartElementDebug:
1572 * @ctxt: An XML parser context
1573 * @name: The element name
1574 *
1575 * called when an opening tag has been processed.
1576 */
1577static void
1578htmlstartElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
1579{
1580 int i;
1581
1582 fprintf(SAXdebug, "SAX.startElement(%s", (char *) name);
1583 if (atts != NULL) {
1584 for (i = 0;(atts[i] != NULL);i++) {
1585 fprintf(SAXdebug, ", %s", atts[i++]);
1586 if (atts[i] != NULL) {
1587 unsigned char output[40];
1588 const unsigned char *att = atts[i];
1589 int outlen, attlen;
1590 fprintf(SAXdebug, "='");
1591 while ((attlen = strlen((char*)att)) > 0) {
1592 outlen = sizeof output - 1;
1593 htmlEncodeEntities(output, &outlen, att, &attlen, '\'');
1594 output[outlen] = 0;
1595 fprintf(SAXdebug, "%s", (char *) output);
1596 att += attlen;
1597 }
1598 fprintf(SAXdebug, "'");
1599 }
1600 }
1601 }
1602 fprintf(SAXdebug, ")\n");
1603}
1604
1605/**
1606 * htmlcharactersDebug:
1607 * @ctxt: An XML parser context
1608 * @ch: a xmlChar string
1609 * @len: the number of xmlChar
1610 *
1611 * receiving some chars from the parser.
1612 * Question: how much at a time ???
1613 */
1614static void
1615htmlcharactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1616{
1617 unsigned char output[40];
1618 int inlen = len, outlen = 30;
1619
1620 htmlEncodeEntities(output, &outlen, ch, &inlen, 0);
1621 output[outlen] = 0;
1622
1623 fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len);
1624}
1625
1626/**
1627 * htmlcdataDebug:
1628 * @ctxt: An XML parser context
1629 * @ch: a xmlChar string
1630 * @len: the number of xmlChar
1631 *
1632 * receiving some cdata chars from the parser.
1633 * Question: how much at a time ???
1634 */
1635static void
1636htmlcdataDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1637{
1638 unsigned char output[40];
1639 int inlen = len, outlen = 30;
1640
1641 htmlEncodeEntities(output, &outlen, ch, &inlen, 0);
1642 output[outlen] = 0;
1643
1644 fprintf(SAXdebug, "SAX.cdata(%s, %d)\n", output, len);
1645}
1646
Daniel Veillard24505b02005-07-28 23:49:35 +00001647static xmlSAXHandler debugHTMLSAXHandlerStruct = {
William M. Brackca15a542005-07-06 20:41:33 +00001648 internalSubsetDebug,
1649 isStandaloneDebug,
1650 hasInternalSubsetDebug,
1651 hasExternalSubsetDebug,
1652 resolveEntityDebug,
1653 getEntityDebug,
1654 entityDeclDebug,
1655 notationDeclDebug,
1656 attributeDeclDebug,
1657 elementDeclDebug,
1658 unparsedEntityDeclDebug,
1659 setDocumentLocatorDebug,
1660 startDocumentDebug,
1661 endDocumentDebug,
1662 htmlstartElementDebug,
1663 endElementDebug,
1664 referenceDebug,
1665 htmlcharactersDebug,
1666 ignorableWhitespaceDebug,
1667 processingInstructionDebug,
1668 commentDebug,
1669 warningDebug,
1670 errorDebug,
1671 fatalErrorDebug,
1672 getParameterEntityDebug,
1673 htmlcdataDebug,
1674 externalSubsetDebug,
1675 1,
1676 NULL,
1677 NULL,
1678 NULL,
1679 NULL
1680};
1681
Daniel Veillard24505b02005-07-28 23:49:35 +00001682static xmlSAXHandlerPtr debugHTMLSAXHandler = &debugHTMLSAXHandlerStruct;
William M. Brackca15a542005-07-06 20:41:33 +00001683#endif /* LIBXML_HTML_ENABLED */
1684
William M. Brackca15a542005-07-06 20:41:33 +00001685/**
1686 * saxParseTest:
1687 * @filename: the file to parse
1688 * @result: the file with expected result
1689 * @err: the file with error messages
1690 *
1691 * Parse a file using the SAX API and check for errors.
1692 *
1693 * Returns 0 in case of success, an error code otherwise
1694 */
1695static int
1696saxParseTest(const char *filename, const char *result,
1697 const char *err ATTRIBUTE_UNUSED,
1698 int options) {
1699 int ret;
1700 char *temp;
1701
1702 nb_tests++;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001703 temp = resultFilename(filename, temp_directory, ".res");
William M. Brackca15a542005-07-06 20:41:33 +00001704 if (temp == NULL) {
1705 fprintf(stderr, "out of memory\n");
1706 fatalError();
1707 }
1708 SAXdebug = fopen(temp, "wb");
1709 if (SAXdebug == NULL) {
1710 fprintf(stderr, "Failed to write to %s\n", temp);
1711 free(temp);
1712 return(-1);
1713 }
1714
1715 /* for SAX we really want the callbacks though the context handlers */
1716 xmlSetStructuredErrorFunc(NULL, NULL);
1717 xmlSetGenericErrorFunc(NULL, testErrorHandler);
1718
1719#ifdef LIBXML_HTML_ENABLED
1720 if (options & XML_PARSE_HTML) {
1721 htmlSAXParseFile(filename, NULL, emptySAXHandler, NULL);
1722 ret = 0;
1723 } else
1724#endif
Nick Wellnhoferdbaab1f2017-06-16 21:38:57 +02001725 {
1726 xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename);
1727 memcpy(ctxt->sax, emptySAXHandler, sizeof(xmlSAXHandler));
1728 xmlCtxtUseOptions(ctxt, options);
1729 xmlParseDocument(ctxt);
1730 ret = ctxt->wellFormed ? 0 : ctxt->errNo;
1731 xmlFreeDoc(ctxt->myDoc);
1732 xmlFreeParserCtxt(ctxt);
1733 }
William M. Brackca15a542005-07-06 20:41:33 +00001734 if (ret == XML_WAR_UNDECLARED_ENTITY) {
1735 fprintf(SAXdebug, "xmlSAXUserParseFile returned error %d\n", ret);
1736 ret = 0;
1737 }
1738 if (ret != 0) {
1739 fprintf(stderr, "Failed to parse %s\n", filename);
Philip Withnall5777ae72014-06-20 21:15:16 +01001740 ret = 1;
1741 goto done;
William M. Brackca15a542005-07-06 20:41:33 +00001742 }
1743#ifdef LIBXML_HTML_ENABLED
1744 if (options & XML_PARSE_HTML) {
1745 htmlSAXParseFile(filename, NULL, debugHTMLSAXHandler, NULL);
1746 ret = 0;
1747 } else
1748#endif
Nick Wellnhoferdbaab1f2017-06-16 21:38:57 +02001749 {
1750 xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename);
1751 if (options & XML_PARSE_SAX1) {
1752 memcpy(ctxt->sax, debugSAXHandler, sizeof(xmlSAXHandler));
1753 options -= XML_PARSE_SAX1;
1754 } else {
1755 memcpy(ctxt->sax, debugSAX2Handler, sizeof(xmlSAXHandler));
1756 }
1757 xmlCtxtUseOptions(ctxt, options);
1758 xmlParseDocument(ctxt);
1759 ret = ctxt->wellFormed ? 0 : ctxt->errNo;
1760 xmlFreeDoc(ctxt->myDoc);
1761 xmlFreeParserCtxt(ctxt);
William M. Brackca15a542005-07-06 20:41:33 +00001762 }
1763 if (ret == XML_WAR_UNDECLARED_ENTITY) {
1764 fprintf(SAXdebug, "xmlSAXUserParseFile returned error %d\n", ret);
1765 ret = 0;
1766 }
1767 fclose(SAXdebug);
1768 if (compareFiles(temp, result)) {
1769 fprintf(stderr, "Got a difference for %s\n", filename);
1770 ret = 1;
Daniel Veillard13cee4e2009-09-05 14:52:55 +02001771 }
Philip Withnall5777ae72014-06-20 21:15:16 +01001772
1773done:
Daniel Veillard13cee4e2009-09-05 14:52:55 +02001774 if (temp != NULL) {
1775 unlink(temp);
1776 free(temp);
1777 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00001778
William M. Brackca15a542005-07-06 20:41:33 +00001779 /* switch back to structured error handling */
1780 xmlSetGenericErrorFunc(NULL, NULL);
1781 xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
1782
1783 return(ret);
1784}
William M. Brackca15a542005-07-06 20:41:33 +00001785
1786/************************************************************************
1787 * *
1788 * Parse to tree based tests *
1789 * *
1790 ************************************************************************/
1791/**
1792 * oldParseTest:
1793 * @filename: the file to parse
1794 * @result: the file with expected result
1795 * @err: the file with error messages: unused
1796 *
1797 * Parse a file using the old xmlParseFile API, then serialize back
1798 * reparse the result and serialize again, then check for deviation
1799 * in serialization.
1800 *
1801 * Returns 0 in case of success, an error code otherwise
1802 */
1803static int
1804oldParseTest(const char *filename, const char *result,
1805 const char *err ATTRIBUTE_UNUSED,
1806 int options ATTRIBUTE_UNUSED) {
1807 xmlDocPtr doc;
1808 char *temp;
1809 int res = 0;
1810
1811 nb_tests++;
1812 /*
1813 * base of the test, parse with the old API
1814 */
1815#ifdef LIBXML_SAX1_ENABLED
1816 doc = xmlParseFile(filename);
1817#else
1818 doc = xmlReadFile(filename, NULL, 0);
1819#endif
1820 if (doc == NULL)
1821 return(1);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07001822 temp = resultFilename(filename, temp_directory, ".res");
William M. Brackca15a542005-07-06 20:41:33 +00001823 if (temp == NULL) {
1824 fprintf(stderr, "out of memory\n");
1825 fatalError();
1826 }
1827 xmlSaveFile(temp, doc);
1828 if (compareFiles(temp, result)) {
1829 res = 1;
1830 }
1831 xmlFreeDoc(doc);
1832
1833 /*
1834 * Parse the saved result to make sure the round trip is okay
1835 */
1836#ifdef LIBXML_SAX1_ENABLED
1837 doc = xmlParseFile(temp);
1838#else
1839 doc = xmlReadFile(temp, NULL, 0);
1840#endif
1841 if (doc == NULL)
1842 return(1);
1843 xmlSaveFile(temp, doc);
1844 if (compareFiles(temp, result)) {
1845 res = 1;
1846 }
1847 xmlFreeDoc(doc);
1848
Daniel Veillard13cee4e2009-09-05 14:52:55 +02001849 if (temp != NULL) {
1850 unlink(temp);
1851 free(temp);
1852 }
William M. Brackca15a542005-07-06 20:41:33 +00001853 return(res);
1854}
1855
1856#ifdef LIBXML_PUSH_ENABLED
1857/**
1858 * pushParseTest:
1859 * @filename: the file to parse
1860 * @result: the file with expected result
1861 * @err: the file with error messages: unused
1862 *
1863 * Parse a file using the Push API, then serialize back
1864 * to check for content.
1865 *
1866 * Returns 0 in case of success, an error code otherwise
1867 */
1868static int
1869pushParseTest(const char *filename, const char *result,
1870 const char *err ATTRIBUTE_UNUSED,
1871 int options) {
1872 xmlParserCtxtPtr ctxt;
1873 xmlDocPtr doc;
1874 const char *base;
1875 int size, res;
1876 int cur = 0;
David Kilzer85c112a2017-06-12 18:26:11 +02001877 int chunkSize = 4;
William M. Brackca15a542005-07-06 20:41:33 +00001878
1879 nb_tests++;
1880 /*
1881 * load the document in memory and work from there.
1882 */
1883 if (loadMem(filename, &base, &size) != 0) {
1884 fprintf(stderr, "Failed to load %s\n", filename);
1885 return(-1);
1886 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00001887
David Kilzer85c112a2017-06-12 18:26:11 +02001888 if (chunkSize > size)
1889 chunkSize = size;
1890
William M. Brackca15a542005-07-06 20:41:33 +00001891#ifdef LIBXML_HTML_ENABLED
1892 if (options & XML_PARSE_HTML)
David Kilzer85c112a2017-06-12 18:26:11 +02001893 ctxt = htmlCreatePushParserCtxt(NULL, NULL, base + cur, chunkSize, filename,
William M. Brackca15a542005-07-06 20:41:33 +00001894 XML_CHAR_ENCODING_NONE);
1895 else
1896#endif
David Kilzer85c112a2017-06-12 18:26:11 +02001897 ctxt = xmlCreatePushParserCtxt(NULL, NULL, base + cur, chunkSize, filename);
William M. Brackca15a542005-07-06 20:41:33 +00001898 xmlCtxtUseOptions(ctxt, options);
David Kilzer85c112a2017-06-12 18:26:11 +02001899 cur += chunkSize;
1900 chunkSize = 1024;
Pranjal Jumdea820dbe2016-03-01 11:34:04 -08001901 do {
David Kilzer85c112a2017-06-12 18:26:11 +02001902 if (cur + chunkSize >= size) {
William M. Brackca15a542005-07-06 20:41:33 +00001903#ifdef LIBXML_HTML_ENABLED
1904 if (options & XML_PARSE_HTML)
1905 htmlParseChunk(ctxt, base + cur, size - cur, 1);
1906 else
1907#endif
1908 xmlParseChunk(ctxt, base + cur, size - cur, 1);
1909 break;
1910 } else {
1911#ifdef LIBXML_HTML_ENABLED
1912 if (options & XML_PARSE_HTML)
David Kilzer85c112a2017-06-12 18:26:11 +02001913 htmlParseChunk(ctxt, base + cur, chunkSize, 0);
William M. Brackca15a542005-07-06 20:41:33 +00001914 else
1915#endif
David Kilzer85c112a2017-06-12 18:26:11 +02001916 xmlParseChunk(ctxt, base + cur, chunkSize, 0);
1917 cur += chunkSize;
William M. Brackca15a542005-07-06 20:41:33 +00001918 }
Pranjal Jumdea820dbe2016-03-01 11:34:04 -08001919 } while (cur < size);
William M. Brackca15a542005-07-06 20:41:33 +00001920 doc = ctxt->myDoc;
1921#ifdef LIBXML_HTML_ENABLED
1922 if (options & XML_PARSE_HTML)
1923 res = 1;
1924 else
1925#endif
1926 res = ctxt->wellFormed;
1927 xmlFreeParserCtxt(ctxt);
1928 free((char *)base);
1929 if (!res) {
1930 xmlFreeDoc(doc);
1931 fprintf(stderr, "Failed to parse %s\n", filename);
1932 return(-1);
1933 }
1934#ifdef LIBXML_HTML_ENABLED
1935 if (options & XML_PARSE_HTML)
1936 htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1937 else
1938#endif
1939 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1940 xmlFreeDoc(doc);
1941 res = compareFileMem(result, base, size);
1942 if ((base == NULL) || (res != 0)) {
1943 if (base != NULL)
1944 xmlFree((char *)base);
Daniel Veillard9f2416c2016-05-22 11:14:45 +08001945 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00001946 return(-1);
1947 }
1948 xmlFree((char *)base);
1949 if (err != NULL) {
1950 res = compareFileMem(err, testErrors, testErrorsSize);
1951 if (res != 0) {
1952 fprintf(stderr, "Error for %s failed\n", filename);
1953 return(-1);
1954 }
1955 }
1956 return(0);
1957}
1958#endif
1959
1960/**
1961 * memParseTest:
1962 * @filename: the file to parse
1963 * @result: the file with expected result
1964 * @err: the file with error messages: unused
1965 *
1966 * Parse a file using the old xmlReadMemory API, then serialize back
1967 * reparse the result and serialize again, then check for deviation
1968 * in serialization.
1969 *
1970 * Returns 0 in case of success, an error code otherwise
1971 */
1972static int
1973memParseTest(const char *filename, const char *result,
1974 const char *err ATTRIBUTE_UNUSED,
1975 int options ATTRIBUTE_UNUSED) {
1976 xmlDocPtr doc;
1977 const char *base;
1978 int size, res;
1979
1980 nb_tests++;
1981 /*
1982 * load and parse the memory
1983 */
1984 if (loadMem(filename, &base, &size) != 0) {
1985 fprintf(stderr, "Failed to load %s\n", filename);
1986 return(-1);
1987 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00001988
William M. Brackca15a542005-07-06 20:41:33 +00001989 doc = xmlReadMemory(base, size, filename, NULL, 0);
1990 unloadMem(base);
1991 if (doc == NULL) {
1992 return(1);
1993 }
1994 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1995 xmlFreeDoc(doc);
1996 res = compareFileMem(result, base, size);
1997 if ((base == NULL) || (res != 0)) {
1998 if (base != NULL)
1999 xmlFree((char *)base);
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002000 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002001 return(-1);
2002 }
2003 xmlFree((char *)base);
2004 return(0);
2005}
2006
2007/**
2008 * noentParseTest:
2009 * @filename: the file to parse
2010 * @result: the file with expected result
2011 * @err: the file with error messages: unused
2012 *
2013 * Parse a file with entity resolution, then serialize back
2014 * reparse the result and serialize again, then check for deviation
2015 * in serialization.
2016 *
2017 * Returns 0 in case of success, an error code otherwise
2018 */
2019static int
2020noentParseTest(const char *filename, const char *result,
2021 const char *err ATTRIBUTE_UNUSED,
2022 int options) {
2023 xmlDocPtr doc;
2024 char *temp;
2025 int res = 0;
2026
2027 nb_tests++;
2028 /*
2029 * base of the test, parse with the old API
2030 */
2031 doc = xmlReadFile(filename, NULL, options);
2032 if (doc == NULL)
2033 return(1);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002034 temp = resultFilename(filename, temp_directory, ".res");
William M. Brackca15a542005-07-06 20:41:33 +00002035 if (temp == NULL) {
2036 fprintf(stderr, "Out of memory\n");
2037 fatalError();
2038 }
2039 xmlSaveFile(temp, doc);
2040 if (compareFiles(temp, result)) {
2041 res = 1;
2042 }
2043 xmlFreeDoc(doc);
2044
2045 /*
2046 * Parse the saved result to make sure the round trip is okay
2047 */
2048 doc = xmlReadFile(filename, NULL, options);
2049 if (doc == NULL)
2050 return(1);
2051 xmlSaveFile(temp, doc);
2052 if (compareFiles(temp, result)) {
2053 res = 1;
2054 }
2055 xmlFreeDoc(doc);
2056
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002057 if (temp != NULL) {
2058 unlink(temp);
2059 free(temp);
2060 }
William M. Brackca15a542005-07-06 20:41:33 +00002061 return(res);
2062}
2063
2064/**
2065 * errParseTest:
2066 * @filename: the file to parse
2067 * @result: the file with expected result
2068 * @err: the file with error messages
2069 *
2070 * Parse a file using the xmlReadFile API and check for errors.
2071 *
2072 * Returns 0 in case of success, an error code otherwise
2073 */
2074static int
2075errParseTest(const char *filename, const char *result, const char *err,
2076 int options) {
2077 xmlDocPtr doc;
2078 const char *base = NULL;
2079 int size, res = 0;
2080
2081 nb_tests++;
2082#ifdef LIBXML_HTML_ENABLED
2083 if (options & XML_PARSE_HTML) {
2084 doc = htmlReadFile(filename, NULL, options);
2085 } else
2086#endif
2087#ifdef LIBXML_XINCLUDE_ENABLED
2088 if (options & XML_PARSE_XINCLUDE) {
2089 doc = xmlReadFile(filename, NULL, options);
2090 xmlXIncludeProcessFlags(doc, options);
2091 } else
2092#endif
2093 {
2094 xmlGetWarningsDefaultValue = 1;
2095 doc = xmlReadFile(filename, NULL, options);
2096 }
2097 xmlGetWarningsDefaultValue = 0;
2098 if (result) {
2099 if (doc == NULL) {
2100 base = "";
2101 size = 0;
2102 } else {
2103#ifdef LIBXML_HTML_ENABLED
2104 if (options & XML_PARSE_HTML) {
2105 htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2106 } else
2107#endif
2108 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2109 }
2110 res = compareFileMem(result, base, size);
2111 }
2112 if (doc != NULL) {
2113 if (base != NULL)
2114 xmlFree((char *)base);
2115 xmlFreeDoc(doc);
2116 }
Haibo Huangf0a546b2020-09-01 20:28:19 -07002117 if (res != 0) {
2118 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
2119 return(-1);
2120 }
William M. Brackca15a542005-07-06 20:41:33 +00002121 if (err != NULL) {
2122 res = compareFileMem(err, testErrors, testErrorsSize);
2123 if (res != 0) {
2124 fprintf(stderr, "Error for %s failed\n", filename);
2125 return(-1);
2126 }
2127 } else if (options & XML_PARSE_DTDVALID) {
2128 if (testErrorsSize != 0)
2129 fprintf(stderr, "Validation for %s failed\n", filename);
2130 }
2131
2132 return(0);
2133}
2134
2135#ifdef LIBXML_READER_ENABLED
2136/************************************************************************
2137 * *
2138 * Reader based tests *
2139 * *
2140 ************************************************************************/
2141
2142static void processNode(FILE *out, xmlTextReaderPtr reader) {
2143 const xmlChar *name, *value;
2144 int type, empty;
2145
2146 type = xmlTextReaderNodeType(reader);
2147 empty = xmlTextReaderIsEmptyElement(reader);
2148
2149 name = xmlTextReaderConstName(reader);
2150 if (name == NULL)
2151 name = BAD_CAST "--";
2152
2153 value = xmlTextReaderConstValue(reader);
2154
Daniel Veillardaa6de472008-08-25 14:53:31 +00002155
2156 fprintf(out, "%d %d %s %d %d",
William M. Brackca15a542005-07-06 20:41:33 +00002157 xmlTextReaderDepth(reader),
2158 type,
2159 name,
2160 empty,
2161 xmlTextReaderHasValue(reader));
2162 if (value == NULL)
2163 fprintf(out, "\n");
2164 else {
2165 fprintf(out, " %s\n", value);
2166 }
2167}
2168static int
2169streamProcessTest(const char *filename, const char *result, const char *err,
Nick Wellnhofer81c01ee2017-06-17 14:12:53 +02002170 xmlTextReaderPtr reader, const char *rng,
2171 int options ATTRIBUTE_UNUSED) {
William M. Brackca15a542005-07-06 20:41:33 +00002172 int ret;
2173 char *temp = NULL;
2174 FILE *t = NULL;
2175
2176 if (reader == NULL)
2177 return(-1);
2178
2179 nb_tests++;
2180 if (result != NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002181 temp = resultFilename(filename, temp_directory, ".res");
William M. Brackca15a542005-07-06 20:41:33 +00002182 if (temp == NULL) {
2183 fprintf(stderr, "Out of memory\n");
2184 fatalError();
2185 }
2186 t = fopen(temp, "wb");
2187 if (t == NULL) {
2188 fprintf(stderr, "Can't open temp file %s\n", temp);
2189 free(temp);
2190 return(-1);
2191 }
2192 }
2193#ifdef LIBXML_SCHEMAS_ENABLED
2194 if (rng != NULL) {
2195 ret = xmlTextReaderRelaxNGValidate(reader, rng);
2196 if (ret < 0) {
2197 testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n",
2198 rng);
2199 fclose(t);
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002200 if (temp != NULL) {
2201 unlink(temp);
2202 free(temp);
2203 }
William M. Brackca15a542005-07-06 20:41:33 +00002204 return(0);
2205 }
2206 }
2207#endif
2208 xmlGetWarningsDefaultValue = 1;
2209 ret = xmlTextReaderRead(reader);
2210 while (ret == 1) {
2211 if ((t != NULL) && (rng == NULL))
2212 processNode(t, reader);
2213 ret = xmlTextReaderRead(reader);
2214 }
2215 if (ret != 0) {
2216 testErrorHandler(NULL, "%s : failed to parse\n", filename);
2217 }
2218 if (rng != NULL) {
2219 if (xmlTextReaderIsValid(reader) != 1) {
2220 testErrorHandler(NULL, "%s fails to validate\n", filename);
2221 } else {
2222 testErrorHandler(NULL, "%s validates\n", filename);
2223 }
2224 }
2225 xmlGetWarningsDefaultValue = 0;
2226 if (t != NULL) {
2227 fclose(t);
2228 ret = compareFiles(temp, result);
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002229 if (temp != NULL) {
2230 unlink(temp);
2231 free(temp);
2232 }
William M. Brackca15a542005-07-06 20:41:33 +00002233 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002234 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002235 return(-1);
2236 }
2237 }
2238 if (err != NULL) {
2239 ret = compareFileMem(err, testErrors, testErrorsSize);
2240 if (ret != 0) {
2241 fprintf(stderr, "Error for %s failed\n", filename);
2242 printf("%s", testErrors);
2243 return(-1);
2244 }
2245 }
2246
2247 return(0);
2248}
2249
2250/**
2251 * streamParseTest:
2252 * @filename: the file to parse
2253 * @result: the file with expected result
2254 * @err: the file with error messages
2255 *
2256 * Parse a file using the reader API and check for errors.
2257 *
2258 * Returns 0 in case of success, an error code otherwise
2259 */
2260static int
2261streamParseTest(const char *filename, const char *result, const char *err,
2262 int options) {
2263 xmlTextReaderPtr reader;
2264 int ret;
2265
2266 reader = xmlReaderForFile(filename, NULL, options);
Daniel Veillarda7982ce2012-10-25 15:39:39 +08002267 ret = streamProcessTest(filename, result, err, reader, NULL, options);
William M. Brackca15a542005-07-06 20:41:33 +00002268 xmlFreeTextReader(reader);
2269 return(ret);
2270}
2271
2272/**
2273 * walkerParseTest:
2274 * @filename: the file to parse
2275 * @result: the file with expected result
2276 * @err: the file with error messages
2277 *
2278 * Parse a file using the walker, i.e. a reader built from a atree.
2279 *
2280 * Returns 0 in case of success, an error code otherwise
2281 */
2282static int
2283walkerParseTest(const char *filename, const char *result, const char *err,
2284 int options) {
2285 xmlDocPtr doc;
2286 xmlTextReaderPtr reader;
2287 int ret;
2288
2289 doc = xmlReadFile(filename, NULL, options);
2290 if (doc == NULL) {
2291 fprintf(stderr, "Failed to parse %s\n", filename);
2292 return(-1);
2293 }
2294 reader = xmlReaderWalker(doc);
Daniel Veillarda7982ce2012-10-25 15:39:39 +08002295 ret = streamProcessTest(filename, result, err, reader, NULL, options);
William M. Brackca15a542005-07-06 20:41:33 +00002296 xmlFreeTextReader(reader);
2297 xmlFreeDoc(doc);
2298 return(ret);
2299}
2300
2301/**
2302 * streamMemParseTest:
2303 * @filename: the file to parse
2304 * @result: the file with expected result
2305 * @err: the file with error messages
2306 *
2307 * Parse a file using the reader API from memory and check for errors.
2308 *
2309 * Returns 0 in case of success, an error code otherwise
2310 */
2311static int
2312streamMemParseTest(const char *filename, const char *result, const char *err,
2313 int options) {
2314 xmlTextReaderPtr reader;
2315 int ret;
2316 const char *base;
2317 int size;
2318
2319 /*
2320 * load and parse the memory
2321 */
2322 if (loadMem(filename, &base, &size) != 0) {
2323 fprintf(stderr, "Failed to load %s\n", filename);
2324 return(-1);
2325 }
2326 reader = xmlReaderForMemory(base, size, filename, NULL, options);
Daniel Veillarda7982ce2012-10-25 15:39:39 +08002327 ret = streamProcessTest(filename, result, err, reader, NULL, options);
William M. Brackca15a542005-07-06 20:41:33 +00002328 free((char *)base);
2329 xmlFreeTextReader(reader);
2330 return(ret);
2331}
2332#endif
2333
2334#ifdef LIBXML_XPATH_ENABLED
2335#ifdef LIBXML_DEBUG_ENABLED
2336/************************************************************************
2337 * *
2338 * XPath and XPointer based tests *
2339 * *
2340 ************************************************************************/
2341
Daniel Veillard24505b02005-07-28 23:49:35 +00002342static FILE *xpathOutput;
2343static xmlDocPtr xpathDocument;
William M. Brackca15a542005-07-06 20:41:33 +00002344
2345static void
Nick Wellnhofer1fc55ca2016-06-25 12:35:09 +02002346ignoreGenericError(void *ctx ATTRIBUTE_UNUSED,
2347 const char *msg ATTRIBUTE_UNUSED, ...) {
2348}
2349
2350static void
William M. Brackca15a542005-07-06 20:41:33 +00002351testXPath(const char *str, int xptr, int expr) {
Nick Wellnhofer1fc55ca2016-06-25 12:35:09 +02002352 xmlGenericErrorFunc handler = ignoreGenericError;
William M. Brackca15a542005-07-06 20:41:33 +00002353 xmlXPathObjectPtr res;
2354 xmlXPathContextPtr ctxt;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002355
Nick Wellnhofer1fc55ca2016-06-25 12:35:09 +02002356 /* Don't print generic errors to stderr. */
2357 initGenericErrorDefaultFunc(&handler);
2358
William M. Brackca15a542005-07-06 20:41:33 +00002359 nb_tests++;
2360#if defined(LIBXML_XPTR_ENABLED)
2361 if (xptr) {
2362 ctxt = xmlXPtrNewContext(xpathDocument, NULL, NULL);
2363 res = xmlXPtrEval(BAD_CAST str, ctxt);
2364 } else {
2365#endif
2366 ctxt = xmlXPathNewContext(xpathDocument);
2367 ctxt->node = xmlDocGetRootElement(xpathDocument);
2368 if (expr)
2369 res = xmlXPathEvalExpression(BAD_CAST str, ctxt);
2370 else {
2371 /* res = xmlXPathEval(BAD_CAST str, ctxt); */
2372 xmlXPathCompExprPtr comp;
2373
2374 comp = xmlXPathCompile(BAD_CAST str);
2375 if (comp != NULL) {
2376 res = xmlXPathCompiledEval(comp, ctxt);
2377 xmlXPathFreeCompExpr(comp);
2378 } else
2379 res = NULL;
2380 }
2381#if defined(LIBXML_XPTR_ENABLED)
2382 }
2383#endif
2384 xmlXPathDebugDumpObject(xpathOutput, res, 0);
2385 xmlXPathFreeObject(res);
2386 xmlXPathFreeContext(ctxt);
Nick Wellnhofer1fc55ca2016-06-25 12:35:09 +02002387
2388 /* Reset generic error handler. */
2389 initGenericErrorDefaultFunc(NULL);
William M. Brackca15a542005-07-06 20:41:33 +00002390}
2391
2392/**
2393 * xpathExprTest:
2394 * @filename: the file to parse
2395 * @result: the file with expected result
2396 * @err: the file with error messages
2397 *
2398 * Parse a file containing XPath standalone expressions and evaluate them
2399 *
2400 * Returns 0 in case of success, an error code otherwise
2401 */
2402static int
2403xpathCommonTest(const char *filename, const char *result,
2404 int xptr, int expr) {
2405 FILE *input;
2406 char expression[5000];
2407 int len, ret = 0;
2408 char *temp;
2409
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002410 temp = resultFilename(filename, temp_directory, ".res");
William M. Brackca15a542005-07-06 20:41:33 +00002411 if (temp == NULL) {
2412 fprintf(stderr, "Out of memory\n");
2413 fatalError();
2414 }
2415 xpathOutput = fopen(temp, "wb");
2416 if (xpathOutput == NULL) {
2417 fprintf(stderr, "failed to open output file %s\n", temp);
2418 free(temp);
2419 return(-1);
2420 }
2421
2422 input = fopen(filename, "rb");
2423 if (input == NULL) {
2424 xmlGenericError(xmlGenericErrorContext,
2425 "Cannot open %s for reading\n", filename);
2426 free(temp);
2427 return(-1);
2428 }
2429 while (fgets(expression, 4500, input) != NULL) {
2430 len = strlen(expression);
2431 len--;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002432 while ((len >= 0) &&
William M. Brackca15a542005-07-06 20:41:33 +00002433 ((expression[len] == '\n') || (expression[len] == '\t') ||
2434 (expression[len] == '\r') || (expression[len] == ' '))) len--;
Daniel Veillardaa6de472008-08-25 14:53:31 +00002435 expression[len + 1] = 0;
William M. Brackca15a542005-07-06 20:41:33 +00002436 if (len >= 0) {
2437 fprintf(xpathOutput,
2438 "\n========================\nExpression: %s\n",
2439 expression) ;
2440 testXPath(expression, xptr, expr);
2441 }
2442 }
2443
2444 fclose(input);
2445 fclose(xpathOutput);
2446 if (result != NULL) {
2447 ret = compareFiles(temp, result);
2448 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002449 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002450 }
2451 }
2452
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002453 if (temp != NULL) {
2454 unlink(temp);
2455 free(temp);
2456 }
William M. Brackca15a542005-07-06 20:41:33 +00002457 return(ret);
2458}
2459
2460/**
2461 * xpathExprTest:
2462 * @filename: the file to parse
2463 * @result: the file with expected result
2464 * @err: the file with error messages
2465 *
2466 * Parse a file containing XPath standalone expressions and evaluate them
2467 *
2468 * Returns 0 in case of success, an error code otherwise
2469 */
2470static int
2471xpathExprTest(const char *filename, const char *result,
2472 const char *err ATTRIBUTE_UNUSED,
2473 int options ATTRIBUTE_UNUSED) {
2474 return(xpathCommonTest(filename, result, 0, 1));
2475}
2476
2477/**
2478 * xpathDocTest:
2479 * @filename: the file to parse
2480 * @result: the file with expected result
2481 * @err: the file with error messages
2482 *
2483 * Parse a file containing XPath expressions and evaluate them against
2484 * a set of corresponding documents.
2485 *
2486 * Returns 0 in case of success, an error code otherwise
2487 */
2488static int
2489xpathDocTest(const char *filename,
2490 const char *resul ATTRIBUTE_UNUSED,
2491 const char *err ATTRIBUTE_UNUSED,
2492 int options) {
2493
2494 char pattern[500];
2495 char result[500];
2496 glob_t globbuf;
2497 size_t i;
2498 int ret = 0, res;
2499
2500 xpathDocument = xmlReadFile(filename, NULL,
2501 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2502 if (xpathDocument == NULL) {
2503 fprintf(stderr, "Failed to load %s\n", filename);
2504 return(-1);
2505 }
2506
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002507 res = snprintf(pattern, 499, "./test/XPath/tests/%s*",
2508 baseFilename(filename));
2509 if (res >= 499)
2510 pattern[499] = 0;
William M. Brackca15a542005-07-06 20:41:33 +00002511 globbuf.gl_offs = 0;
2512 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2513 for (i = 0;i < globbuf.gl_pathc;i++) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002514 res = snprintf(result, 499, "result/XPath/tests/%s",
William M. Brackca15a542005-07-06 20:41:33 +00002515 baseFilename(globbuf.gl_pathv[i]));
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002516 if (res >= 499)
2517 result[499] = 0;
William M. Brackca15a542005-07-06 20:41:33 +00002518 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 0, 0);
2519 if (res != 0)
2520 ret = res;
2521 }
2522 globfree(&globbuf);
2523
2524 xmlFreeDoc(xpathDocument);
2525 return(ret);
2526}
2527
2528#ifdef LIBXML_XPTR_ENABLED
2529/**
2530 * xptrDocTest:
2531 * @filename: the file to parse
2532 * @result: the file with expected result
2533 * @err: the file with error messages
2534 *
2535 * Parse a file containing XPath expressions and evaluate them against
2536 * a set of corresponding documents.
2537 *
2538 * Returns 0 in case of success, an error code otherwise
2539 */
2540static int
2541xptrDocTest(const char *filename,
2542 const char *resul ATTRIBUTE_UNUSED,
2543 const char *err ATTRIBUTE_UNUSED,
2544 int options) {
2545
2546 char pattern[500];
2547 char result[500];
2548 glob_t globbuf;
2549 size_t i;
2550 int ret = 0, res;
2551
2552 xpathDocument = xmlReadFile(filename, NULL,
2553 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2554 if (xpathDocument == NULL) {
2555 fprintf(stderr, "Failed to load %s\n", filename);
2556 return(-1);
2557 }
2558
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002559 res = snprintf(pattern, 499, "./test/XPath/xptr/%s*",
2560 baseFilename(filename));
2561 if (res >= 499)
2562 pattern[499] = 0;
William M. Brackca15a542005-07-06 20:41:33 +00002563 globbuf.gl_offs = 0;
2564 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2565 for (i = 0;i < globbuf.gl_pathc;i++) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002566 res = snprintf(result, 499, "result/XPath/xptr/%s",
William M. Brackca15a542005-07-06 20:41:33 +00002567 baseFilename(globbuf.gl_pathv[i]));
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002568 if (res >= 499)
2569 result[499] = 0;
William M. Brackca15a542005-07-06 20:41:33 +00002570 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 1, 0);
2571 if (res != 0)
2572 ret = res;
2573 }
2574 globfree(&globbuf);
2575
2576 xmlFreeDoc(xpathDocument);
2577 return(ret);
2578}
2579#endif /* LIBXML_XPTR_ENABLED */
2580
2581/**
2582 * xmlidDocTest:
2583 * @filename: the file to parse
2584 * @result: the file with expected result
2585 * @err: the file with error messages
2586 *
2587 * Parse a file containing xml:id and check for errors and verify
2588 * that XPath queries will work on them as expected.
2589 *
2590 * Returns 0 in case of success, an error code otherwise
2591 */
2592static int
2593xmlidDocTest(const char *filename,
2594 const char *result,
2595 const char *err,
2596 int options) {
2597
2598 int res = 0;
2599 int ret = 0;
2600 char *temp;
2601
2602 xpathDocument = xmlReadFile(filename, NULL,
2603 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2604 if (xpathDocument == NULL) {
2605 fprintf(stderr, "Failed to load %s\n", filename);
2606 return(-1);
2607 }
2608
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002609 temp = resultFilename(filename, temp_directory, ".res");
William M. Brackca15a542005-07-06 20:41:33 +00002610 if (temp == NULL) {
2611 fprintf(stderr, "Out of memory\n");
2612 fatalError();
2613 }
2614 xpathOutput = fopen(temp, "wb");
2615 if (xpathOutput == NULL) {
2616 fprintf(stderr, "failed to open output file %s\n", temp);
2617 xmlFreeDoc(xpathDocument);
2618 free(temp);
2619 return(-1);
2620 }
2621
2622 testXPath("id('bar')", 0, 0);
2623
2624 fclose(xpathOutput);
2625 if (result != NULL) {
2626 ret = compareFiles(temp, result);
2627 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002628 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002629 res = 1;
2630 }
2631 }
2632
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002633 if (temp != NULL) {
2634 unlink(temp);
2635 free(temp);
2636 }
William M. Brackca15a542005-07-06 20:41:33 +00002637 xmlFreeDoc(xpathDocument);
2638
2639 if (err != NULL) {
2640 ret = compareFileMem(err, testErrors, testErrorsSize);
2641 if (ret != 0) {
2642 fprintf(stderr, "Error for %s failed\n", filename);
2643 res = 1;
2644 }
2645 }
2646 return(res);
2647}
2648
2649#endif /* LIBXML_DEBUG_ENABLED */
2650#endif /* XPATH */
2651/************************************************************************
2652 * *
2653 * URI based tests *
2654 * *
2655 ************************************************************************/
2656
2657static void
2658handleURI(const char *str, const char *base, FILE *o) {
2659 int ret;
2660 xmlURIPtr uri;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002661 xmlChar *res = NULL;
William M. Brackca15a542005-07-06 20:41:33 +00002662
2663 uri = xmlCreateURI();
2664
2665 if (base == NULL) {
2666 ret = xmlParseURIReference(uri, str);
2667 if (ret != 0)
2668 fprintf(o, "%s : error %d\n", str, ret);
2669 else {
2670 xmlNormalizeURIPath(uri->path);
2671 xmlPrintURI(o, uri);
2672 fprintf(o, "\n");
2673 }
2674 } else {
2675 res = xmlBuildURI((xmlChar *)str, (xmlChar *) base);
2676 if (res != NULL) {
2677 fprintf(o, "%s\n", (char *) res);
2678 }
2679 else
2680 fprintf(o, "::ERROR::\n");
2681 }
2682 if (res != NULL)
2683 xmlFree(res);
William M. Brackca15a542005-07-06 20:41:33 +00002684 xmlFreeURI(uri);
2685}
2686
2687/**
2688 * uriCommonTest:
2689 * @filename: the file to parse
2690 * @result: the file with expected result
2691 * @err: the file with error messages
2692 *
2693 * Parse a file containing URI and check for errors
2694 *
2695 * Returns 0 in case of success, an error code otherwise
2696 */
2697static int
2698uriCommonTest(const char *filename,
2699 const char *result,
2700 const char *err,
2701 const char *base) {
2702 char *temp;
2703 FILE *o, *f;
2704 char str[1024];
2705 int res = 0, i, ret;
2706
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002707 temp = resultFilename(filename, temp_directory, ".res");
William M. Brackca15a542005-07-06 20:41:33 +00002708 if (temp == NULL) {
2709 fprintf(stderr, "Out of memory\n");
2710 fatalError();
2711 }
2712 o = fopen(temp, "wb");
2713 if (o == NULL) {
2714 fprintf(stderr, "failed to open output file %s\n", temp);
2715 free(temp);
2716 return(-1);
2717 }
2718 f = fopen(filename, "rb");
2719 if (f == NULL) {
2720 fprintf(stderr, "failed to open input file %s\n", filename);
2721 fclose(o);
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002722 if (temp != NULL) {
2723 unlink(temp);
2724 free(temp);
2725 }
William M. Brackca15a542005-07-06 20:41:33 +00002726 return(-1);
2727 }
2728
2729 while (1) {
2730 /*
2731 * read one line in string buffer.
2732 */
2733 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
2734 break;
2735
2736 /*
2737 * remove the ending spaces
2738 */
2739 i = strlen(str);
2740 while ((i > 0) &&
2741 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
2742 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
2743 i--;
2744 str[i] = 0;
2745 }
2746 nb_tests++;
2747 handleURI(str, base, o);
2748 }
2749
2750 fclose(f);
2751 fclose(o);
2752
2753 if (result != NULL) {
2754 ret = compareFiles(temp, result);
2755 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08002756 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00002757 res = 1;
2758 }
2759 }
2760 if (err != NULL) {
2761 ret = compareFileMem(err, testErrors, testErrorsSize);
2762 if (ret != 0) {
2763 fprintf(stderr, "Error for %s failed\n", filename);
2764 res = 1;
2765 }
2766 }
2767
Daniel Veillard13cee4e2009-09-05 14:52:55 +02002768 if (temp != NULL) {
2769 unlink(temp);
2770 free(temp);
2771 }
William M. Brackca15a542005-07-06 20:41:33 +00002772 return(res);
2773}
2774
2775/**
2776 * uriParseTest:
2777 * @filename: the file to parse
2778 * @result: the file with expected result
2779 * @err: the file with error messages
2780 *
2781 * Parse a file containing URI and check for errors
2782 *
2783 * Returns 0 in case of success, an error code otherwise
2784 */
2785static int
2786uriParseTest(const char *filename,
2787 const char *result,
2788 const char *err,
2789 int options ATTRIBUTE_UNUSED) {
2790 return(uriCommonTest(filename, result, err, NULL));
2791}
2792
2793/**
2794 * uriBaseTest:
2795 * @filename: the file to parse
2796 * @result: the file with expected result
2797 * @err: the file with error messages
2798 *
2799 * Parse a file containing URI, compose them against a fixed base and
2800 * check for errors
2801 *
2802 * Returns 0 in case of success, an error code otherwise
2803 */
2804static int
2805uriBaseTest(const char *filename,
2806 const char *result,
2807 const char *err,
2808 int options ATTRIBUTE_UNUSED) {
2809 return(uriCommonTest(filename, result, err,
2810 "http://foo.com/path/to/index.html?orig#help"));
2811}
2812
Daniel Veillard336a8e12005-08-07 10:46:19 +00002813static int urip_success = 1;
2814static int urip_current = 0;
2815static const char *urip_testURLs[] = {
2816 "urip://example.com/a b.html",
2817 "urip://example.com/a%20b.html",
2818 "file:///path/to/a b.html",
2819 "file:///path/to/a%20b.html",
2820 "/path/to/a b.html",
2821 "/path/to/a%20b.html",
Daniel Veillardff7227f2012-08-20 20:58:24 +08002822 "urip://example.com/r" "\xe9" "sum" "\xe9" ".html",
Daniel Veillard336a8e12005-08-07 10:46:19 +00002823 "urip://example.com/test?a=1&b=2%263&c=4#foo",
2824 NULL
2825};
2826static const char *urip_rcvsURLs[] = {
2827 /* it is an URI the strings must be escaped */
2828 "urip://example.com/a%20b.html",
2829 /* check that % escaping is not broken */
2830 "urip://example.com/a%20b.html",
2831 /* it's an URI path the strings must be escaped */
2832 "file:///path/to/a%20b.html",
2833 /* check that % escaping is not broken */
2834 "file:///path/to/a%20b.html",
2835 /* this is not an URI, this is a path, so this should not be escaped */
2836 "/path/to/a b.html",
2837 /* check that paths with % are not broken */
2838 "/path/to/a%20b.html",
2839 /* out of context the encoding can't be guessed byte by byte conversion */
2840 "urip://example.com/r%E9sum%E9.html",
2841 /* verify we don't destroy URIs especially the query part */
2842 "urip://example.com/test?a=1&b=2%263&c=4#foo",
2843 NULL
2844};
2845static const char *urip_res = "<list/>";
2846static const char *urip_cur = NULL;
2847static int urip_rlen;
2848
2849/**
2850 * uripMatch:
2851 * @URI: an URI to test
2852 *
2853 * Check for an urip: query
2854 *
2855 * Returns 1 if yes and 0 if another Input module should be used
2856 */
2857static int
2858uripMatch(const char * URI) {
2859 if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog")))
2860 return(0);
2861 /* Verify we received the escaped URL */
2862 if (strcmp(urip_rcvsURLs[urip_current], URI))
2863 urip_success = 0;
2864 return(1);
2865}
2866
2867/**
2868 * uripOpen:
2869 * @URI: an URI to test
2870 *
2871 * Return a pointer to the urip: query handler, in this example simply
2872 * the urip_current pointer...
2873 *
2874 * Returns an Input context or NULL in case or error
2875 */
2876static void *
2877uripOpen(const char * URI) {
2878 if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog")))
2879 return(NULL);
2880 /* Verify we received the escaped URL */
2881 if (strcmp(urip_rcvsURLs[urip_current], URI))
2882 urip_success = 0;
2883 urip_cur = urip_res;
2884 urip_rlen = strlen(urip_res);
2885 return((void *) urip_cur);
2886}
2887
2888/**
2889 * uripClose:
2890 * @context: the read context
2891 *
2892 * Close the urip: query handler
2893 *
2894 * Returns 0 or -1 in case of error
2895 */
2896static int
2897uripClose(void * context) {
2898 if (context == NULL) return(-1);
2899 urip_cur = NULL;
2900 urip_rlen = 0;
2901 return(0);
2902}
2903
2904/**
2905 * uripRead:
2906 * @context: the read context
2907 * @buffer: where to store data
2908 * @len: number of bytes to read
2909 *
2910 * Implement an urip: query read.
2911 *
2912 * Returns the number of bytes read or -1 in case of error
2913 */
2914static int
2915uripRead(void * context, char * buffer, int len) {
2916 const char *ptr = (const char *) context;
2917
2918 if ((context == NULL) || (buffer == NULL) || (len < 0))
2919 return(-1);
2920
2921 if (len > urip_rlen) len = urip_rlen;
2922 memcpy(buffer, ptr, len);
2923 urip_rlen -= len;
2924 return(len);
2925}
2926
2927static int
2928urip_checkURL(const char *URL) {
2929 xmlDocPtr doc;
2930
2931 doc = xmlReadFile(URL, NULL, 0);
2932 if (doc == NULL)
2933 return(-1);
2934 xmlFreeDoc(doc);
2935 return(1);
2936}
2937
2938/**
2939 * uriPathTest:
2940 * @filename: ignored
2941 * @result: ignored
2942 * @err: ignored
2943 *
2944 * Run a set of tests to check how Path and URI are handled before
2945 * being passed to the I/O layer
2946 *
2947 * Returns 0 in case of success, an error code otherwise
2948 */
2949static int
2950uriPathTest(const char *filename ATTRIBUTE_UNUSED,
2951 const char *result ATTRIBUTE_UNUSED,
2952 const char *err ATTRIBUTE_UNUSED,
2953 int options ATTRIBUTE_UNUSED) {
2954 int parsed;
2955 int failures = 0;
2956
2957 /*
2958 * register the new I/O handlers
2959 */
2960 if (xmlRegisterInputCallbacks(uripMatch, uripOpen, uripRead, uripClose) < 0)
2961 {
2962 fprintf(stderr, "failed to register HTTP handler\n");
2963 return(-1);
2964 }
2965
2966 for (urip_current = 0;urip_testURLs[urip_current] != NULL;urip_current++) {
2967 urip_success = 1;
2968 parsed = urip_checkURL(urip_testURLs[urip_current]);
2969 if (urip_success != 1) {
2970 fprintf(stderr, "failed the URL passing test for %s",
2971 urip_testURLs[urip_current]);
2972 failures++;
2973 } else if (parsed != 1) {
2974 fprintf(stderr, "failed the parsing test for %s",
2975 urip_testURLs[urip_current]);
2976 failures++;
2977 }
2978 nb_tests++;
2979 }
2980
2981 xmlPopInputCallbacks();
2982 return(failures);
2983}
2984
William M. Brackca15a542005-07-06 20:41:33 +00002985#ifdef LIBXML_SCHEMAS_ENABLED
2986/************************************************************************
2987 * *
2988 * Schemas tests *
2989 * *
2990 ************************************************************************/
2991static int
2992schemasOneTest(const char *sch,
2993 const char *filename,
2994 const char *result,
2995 const char *err,
2996 int options,
2997 xmlSchemaPtr schemas) {
2998 xmlDocPtr doc;
2999 xmlSchemaValidCtxtPtr ctxt;
3000 int ret = 0;
Daniel Veillard381ff362006-06-18 17:31:31 +00003001 int validResult = 0;
William M. Brackca15a542005-07-06 20:41:33 +00003002 char *temp;
3003 FILE *schemasOutput;
3004
3005 doc = xmlReadFile(filename, NULL, options);
3006 if (doc == NULL) {
3007 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
3008 return(-1);
3009 }
3010
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003011 temp = resultFilename(result, temp_directory, ".res");
William M. Brackca15a542005-07-06 20:41:33 +00003012 if (temp == NULL) {
3013 fprintf(stderr, "Out of memory\n");
3014 fatalError();
3015 }
3016 schemasOutput = fopen(temp, "wb");
3017 if (schemasOutput == NULL) {
3018 fprintf(stderr, "failed to open output file %s\n", temp);
3019 xmlFreeDoc(doc);
3020 free(temp);
3021 return(-1);
3022 }
3023
3024 ctxt = xmlSchemaNewValidCtxt(schemas);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003025 xmlSchemaSetValidErrors(ctxt, testErrorHandler, testErrorHandler, ctxt);
Daniel Veillard381ff362006-06-18 17:31:31 +00003026 validResult = xmlSchemaValidateDoc(ctxt, doc);
3027 if (validResult == 0) {
William M. Brackca15a542005-07-06 20:41:33 +00003028 fprintf(schemasOutput, "%s validates\n", filename);
Daniel Veillard381ff362006-06-18 17:31:31 +00003029 } else if (validResult > 0) {
William M. Brackca15a542005-07-06 20:41:33 +00003030 fprintf(schemasOutput, "%s fails to validate\n", filename);
3031 } else {
3032 fprintf(schemasOutput, "%s validation generated an internal error\n",
3033 filename);
3034 }
3035 fclose(schemasOutput);
3036 if (result) {
3037 if (compareFiles(temp, result)) {
3038 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
3039 ret = 1;
3040 }
3041 }
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003042 if (temp != NULL) {
3043 unlink(temp);
3044 free(temp);
3045 }
William M. Brackca15a542005-07-06 20:41:33 +00003046
Daniel Veillard381ff362006-06-18 17:31:31 +00003047 if ((validResult != 0) && (err != NULL)) {
William M. Brackca15a542005-07-06 20:41:33 +00003048 if (compareFileMem(err, testErrors, testErrorsSize)) {
3049 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
3050 ret = 1;
3051 }
3052 }
3053
William M. Brackca15a542005-07-06 20:41:33 +00003054 xmlSchemaFreeValidCtxt(ctxt);
3055 xmlFreeDoc(doc);
3056 return(ret);
3057}
3058/**
3059 * schemasTest:
3060 * @filename: the schemas file
3061 * @result: the file with expected result
3062 * @err: the file with error messages
3063 *
3064 * Parse a file containing URI, compose them against a fixed base and
3065 * check for errors
3066 *
3067 * Returns 0 in case of success, an error code otherwise
3068 */
3069static int
3070schemasTest(const char *filename,
3071 const char *resul ATTRIBUTE_UNUSED,
3072 const char *errr ATTRIBUTE_UNUSED,
3073 int options) {
3074 const char *base = baseFilename(filename);
3075 const char *base2;
3076 const char *instance;
3077 xmlSchemaParserCtxtPtr ctxt;
3078 xmlSchemaPtr schemas;
3079 int res = 0, len, ret;
3080 char pattern[500];
3081 char prefix[500];
3082 char result[500];
3083 char err[500];
3084 glob_t globbuf;
3085 size_t i;
3086 char count = 0;
3087
3088 /* first compile the schemas if possible */
3089 ctxt = xmlSchemaNewParserCtxt(filename);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003090 xmlSchemaSetParserErrors(ctxt, testErrorHandler, testErrorHandler, ctxt);
William M. Brackca15a542005-07-06 20:41:33 +00003091 schemas = xmlSchemaParse(ctxt);
3092 xmlSchemaFreeParserCtxt(ctxt);
3093
3094 /*
3095 * most of the mess is about the output filenames generated by the Makefile
3096 */
3097 len = strlen(base);
3098 if ((len > 499) || (len < 5)) {
3099 xmlSchemaFree(schemas);
3100 return(-1);
3101 }
3102 len -= 4; /* remove trailing .xsd */
3103 if (base[len - 2] == '_') {
3104 len -= 2; /* remove subtest number */
3105 }
3106 if (base[len - 2] == '_') {
3107 len -= 2; /* remove subtest number */
3108 }
3109 memcpy(prefix, base, len);
3110 prefix[len] = 0;
3111
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003112 if (snprintf(pattern, 499, "./test/schemas/%s_?.xml", prefix) >= 499)
3113 pattern[499] = 0;
William M. Brackca15a542005-07-06 20:41:33 +00003114
3115 if (base[len] == '_') {
3116 len += 2;
3117 memcpy(prefix, base, len);
3118 prefix[len] = 0;
3119 }
3120
3121 globbuf.gl_offs = 0;
3122 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3123 for (i = 0;i < globbuf.gl_pathc;i++) {
3124 testErrorsSize = 0;
3125 testErrors[0] = 0;
3126 instance = globbuf.gl_pathv[i];
3127 base2 = baseFilename(instance);
3128 len = strlen(base2);
3129 if ((len > 6) && (base2[len - 6] == '_')) {
3130 count = base2[len - 5];
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003131 ret = snprintf(result, 499, "result/schemas/%s_%c",
William M. Brackca15a542005-07-06 20:41:33 +00003132 prefix, count);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003133 if (ret >= 499)
3134 result[499] = 0;
3135 ret = snprintf(err, 499, "result/schemas/%s_%c.err",
William M. Brackca15a542005-07-06 20:41:33 +00003136 prefix, count);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003137 if (ret >= 499)
3138 err[499] = 0;
William M. Brackca15a542005-07-06 20:41:33 +00003139 } else {
3140 fprintf(stderr, "don't know how to process %s\n", instance);
3141 continue;
3142 }
3143 if (schemas == NULL) {
3144 } else {
3145 nb_tests++;
3146 ret = schemasOneTest(filename, instance, result, err,
3147 options, schemas);
Daniel Veillard93e577f2005-11-15 08:50:04 +00003148 if (ret != 0)
3149 res = ret;
William M. Brackca15a542005-07-06 20:41:33 +00003150 }
3151 }
3152 globfree(&globbuf);
3153 xmlSchemaFree(schemas);
3154
3155 return(res);
3156}
3157
3158/************************************************************************
3159 * *
3160 * Schemas tests *
3161 * *
3162 ************************************************************************/
3163static int
3164rngOneTest(const char *sch,
3165 const char *filename,
3166 const char *result,
3167 const char *err,
3168 int options,
3169 xmlRelaxNGPtr schemas) {
3170 xmlDocPtr doc;
3171 xmlRelaxNGValidCtxtPtr ctxt;
3172 int ret = 0;
3173 char *temp;
3174 FILE *schemasOutput;
3175
3176 doc = xmlReadFile(filename, NULL, options);
3177 if (doc == NULL) {
3178 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
3179 return(-1);
3180 }
3181
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003182 temp = resultFilename(result, temp_directory, ".res");
William M. Brackca15a542005-07-06 20:41:33 +00003183 if (temp == NULL) {
3184 fprintf(stderr, "Out of memory\n");
3185 fatalError();
3186 }
3187 schemasOutput = fopen(temp, "wb");
3188 if (schemasOutput == NULL) {
3189 fprintf(stderr, "failed to open output file %s\n", temp);
3190 xmlFreeDoc(doc);
3191 free(temp);
3192 return(-1);
3193 }
3194
3195 ctxt = xmlRelaxNGNewValidCtxt(schemas);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003196 xmlRelaxNGSetValidErrors(ctxt, testErrorHandler, testErrorHandler, ctxt);
William M. Brackca15a542005-07-06 20:41:33 +00003197 ret = xmlRelaxNGValidateDoc(ctxt, doc);
3198 if (ret == 0) {
3199 testErrorHandler(NULL, "%s validates\n", filename);
3200 } else if (ret > 0) {
3201 testErrorHandler(NULL, "%s fails to validate\n", filename);
3202 } else {
3203 testErrorHandler(NULL, "%s validation generated an internal error\n",
3204 filename);
3205 }
3206 fclose(schemasOutput);
Daniel Veillard594e5df2009-09-07 14:58:47 +02003207 ret = 0;
William M. Brackca15a542005-07-06 20:41:33 +00003208 if (result) {
3209 if (compareFiles(temp, result)) {
3210 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
3211 ret = 1;
3212 }
3213 }
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003214 if (temp != NULL) {
3215 unlink(temp);
3216 free(temp);
3217 }
William M. Brackca15a542005-07-06 20:41:33 +00003218
3219 if (err != NULL) {
3220 if (compareFileMem(err, testErrors, testErrorsSize)) {
3221 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
3222 ret = 1;
3223 printf("%s", testErrors);
3224 }
3225 }
3226
3227
3228 xmlRelaxNGFreeValidCtxt(ctxt);
3229 xmlFreeDoc(doc);
3230 return(ret);
3231}
3232/**
3233 * rngTest:
3234 * @filename: the schemas file
3235 * @result: the file with expected result
3236 * @err: the file with error messages
3237 *
3238 * Parse an RNG schemas and then apply it to the related .xml
3239 *
3240 * Returns 0 in case of success, an error code otherwise
3241 */
3242static int
3243rngTest(const char *filename,
3244 const char *resul ATTRIBUTE_UNUSED,
3245 const char *errr ATTRIBUTE_UNUSED,
3246 int options) {
3247 const char *base = baseFilename(filename);
3248 const char *base2;
3249 const char *instance;
3250 xmlRelaxNGParserCtxtPtr ctxt;
3251 xmlRelaxNGPtr schemas;
Rob Richardsc9667902010-01-22 08:24:25 -05003252 int res = 0, len, ret = 0;
William M. Brackca15a542005-07-06 20:41:33 +00003253 char pattern[500];
3254 char prefix[500];
3255 char result[500];
3256 char err[500];
3257 glob_t globbuf;
3258 size_t i;
3259 char count = 0;
3260
3261 /* first compile the schemas if possible */
3262 ctxt = xmlRelaxNGNewParserCtxt(filename);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003263 xmlRelaxNGSetParserErrors(ctxt, testErrorHandler, testErrorHandler, ctxt);
William M. Brackca15a542005-07-06 20:41:33 +00003264 schemas = xmlRelaxNGParse(ctxt);
3265 xmlRelaxNGFreeParserCtxt(ctxt);
3266
3267 /*
3268 * most of the mess is about the output filenames generated by the Makefile
3269 */
3270 len = strlen(base);
3271 if ((len > 499) || (len < 5)) {
3272 xmlRelaxNGFree(schemas);
3273 return(-1);
3274 }
3275 len -= 4; /* remove trailing .rng */
3276 memcpy(prefix, base, len);
3277 prefix[len] = 0;
3278
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003279 if (snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix) >= 499)
3280 pattern[499] = 0;
William M. Brackca15a542005-07-06 20:41:33 +00003281
3282 globbuf.gl_offs = 0;
3283 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3284 for (i = 0;i < globbuf.gl_pathc;i++) {
3285 testErrorsSize = 0;
3286 testErrors[0] = 0;
3287 instance = globbuf.gl_pathv[i];
3288 base2 = baseFilename(instance);
3289 len = strlen(base2);
3290 if ((len > 6) && (base2[len - 6] == '_')) {
3291 count = base2[len - 5];
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003292 res = snprintf(result, 499, "result/relaxng/%s_%c",
William M. Brackca15a542005-07-06 20:41:33 +00003293 prefix, count);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003294 if (res >= 499)
3295 result[499] = 0;
3296 res = snprintf(err, 499, "result/relaxng/%s_%c.err",
William M. Brackca15a542005-07-06 20:41:33 +00003297 prefix, count);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003298 if (res >= 499)
3299 err[499] = 0;
William M. Brackca15a542005-07-06 20:41:33 +00003300 } else {
3301 fprintf(stderr, "don't know how to process %s\n", instance);
3302 continue;
3303 }
3304 if (schemas == NULL) {
3305 } else {
3306 nb_tests++;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003307 res = rngOneTest(filename, instance, result, err,
William M. Brackca15a542005-07-06 20:41:33 +00003308 options, schemas);
3309 if (res != 0)
3310 ret = res;
3311 }
3312 }
3313 globfree(&globbuf);
3314 xmlRelaxNGFree(schemas);
3315
Daniel Veillard594e5df2009-09-07 14:58:47 +02003316 return(ret);
William M. Brackca15a542005-07-06 20:41:33 +00003317}
3318
3319#ifdef LIBXML_READER_ENABLED
3320/**
3321 * rngStreamTest:
3322 * @filename: the schemas file
3323 * @result: the file with expected result
3324 * @err: the file with error messages
3325 *
Daniel Veillardaa6de472008-08-25 14:53:31 +00003326 * Parse a set of files with streaming, applying an RNG schemas
William M. Brackca15a542005-07-06 20:41:33 +00003327 *
3328 * Returns 0 in case of success, an error code otherwise
3329 */
3330static int
3331rngStreamTest(const char *filename,
3332 const char *resul ATTRIBUTE_UNUSED,
3333 const char *errr ATTRIBUTE_UNUSED,
3334 int options) {
3335 const char *base = baseFilename(filename);
3336 const char *base2;
3337 const char *instance;
3338 int res = 0, len, ret;
3339 char pattern[500];
3340 char prefix[500];
3341 char result[500];
3342 char err[500];
3343 glob_t globbuf;
3344 size_t i;
3345 char count = 0;
3346 xmlTextReaderPtr reader;
3347 int disable_err = 0;
3348
3349 /*
3350 * most of the mess is about the output filenames generated by the Makefile
3351 */
3352 len = strlen(base);
3353 if ((len > 499) || (len < 5)) {
3354 fprintf(stderr, "len(base) == %d !\n", len);
3355 return(-1);
3356 }
3357 len -= 4; /* remove trailing .rng */
3358 memcpy(prefix, base, len);
3359 prefix[len] = 0;
3360
3361 /*
3362 * strictly unifying the error messages is nearly impossible this
3363 * hack is also done in the Makefile
3364 */
3365 if ((!strcmp(prefix, "tutor10_1")) || (!strcmp(prefix, "tutor10_2")) ||
Daniel Veillardec18c962009-08-26 18:37:43 +02003366 (!strcmp(prefix, "tutor3_2")) || (!strcmp(prefix, "307377")) ||
3367 (!strcmp(prefix, "tutor8_2")))
William M. Brackca15a542005-07-06 20:41:33 +00003368 disable_err = 1;
3369
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003370 if (snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix) >= 499)
3371 pattern[499] = 0;
William M. Brackca15a542005-07-06 20:41:33 +00003372
3373 globbuf.gl_offs = 0;
3374 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3375 for (i = 0;i < globbuf.gl_pathc;i++) {
3376 testErrorsSize = 0;
3377 testErrors[0] = 0;
3378 instance = globbuf.gl_pathv[i];
3379 base2 = baseFilename(instance);
3380 len = strlen(base2);
3381 if ((len > 6) && (base2[len - 6] == '_')) {
3382 count = base2[len - 5];
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003383 ret = snprintf(result, 499, "result/relaxng/%s_%c",
William M. Brackca15a542005-07-06 20:41:33 +00003384 prefix, count);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003385 if (ret >= 499)
3386 result[499] = 0;
3387 ret = snprintf(err, 499, "result/relaxng/%s_%c.err",
William M. Brackca15a542005-07-06 20:41:33 +00003388 prefix, count);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003389 if (ret >= 499)
3390 err[499] = 0;
William M. Brackca15a542005-07-06 20:41:33 +00003391 } else {
3392 fprintf(stderr, "don't know how to process %s\n", instance);
3393 continue;
3394 }
3395 reader = xmlReaderForFile(instance, NULL, options);
3396 if (reader == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003397 fprintf(stderr, "Failed to build reader for %s\n", instance);
William M. Brackca15a542005-07-06 20:41:33 +00003398 }
3399 if (disable_err == 1)
Daniel Veillarda7982ce2012-10-25 15:39:39 +08003400 ret = streamProcessTest(instance, result, NULL, reader, filename,
3401 options);
William M. Brackca15a542005-07-06 20:41:33 +00003402 else
Daniel Veillarda7982ce2012-10-25 15:39:39 +08003403 ret = streamProcessTest(instance, result, err, reader, filename,
3404 options);
William M. Brackca15a542005-07-06 20:41:33 +00003405 xmlFreeTextReader(reader);
3406 if (ret != 0) {
3407 fprintf(stderr, "instance %s failed\n", instance);
3408 res = ret;
3409 }
3410 }
3411 globfree(&globbuf);
3412
3413 return(res);
3414}
3415#endif /* READER */
3416
3417#endif
3418
3419#ifdef LIBXML_PATTERN_ENABLED
3420#ifdef LIBXML_READER_ENABLED
3421/************************************************************************
3422 * *
3423 * Patterns tests *
3424 * *
3425 ************************************************************************/
3426static void patternNode(FILE *out, xmlTextReaderPtr reader,
3427 const char *pattern, xmlPatternPtr patternc,
3428 xmlStreamCtxtPtr patstream) {
3429 xmlChar *path = NULL;
3430 int match = -1;
3431 int type, empty;
3432
3433 type = xmlTextReaderNodeType(reader);
3434 empty = xmlTextReaderIsEmptyElement(reader);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003435
William M. Brackca15a542005-07-06 20:41:33 +00003436 if (type == XML_READER_TYPE_ELEMENT) {
3437 /* do the check only on element start */
3438 match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader));
3439
3440 if (match) {
3441 path = xmlGetNodePath(xmlTextReaderCurrentNode(reader));
3442 fprintf(out, "Node %s matches pattern %s\n", path, pattern);
3443 }
3444 }
3445 if (patstream != NULL) {
3446 int ret;
3447
3448 if (type == XML_READER_TYPE_ELEMENT) {
3449 ret = xmlStreamPush(patstream,
3450 xmlTextReaderConstLocalName(reader),
3451 xmlTextReaderConstNamespaceUri(reader));
3452 if (ret < 0) {
3453 fprintf(out, "xmlStreamPush() failure\n");
3454 xmlFreeStreamCtxt(patstream);
3455 patstream = NULL;
3456 } else if (ret != match) {
3457 if (path == NULL) {
3458 path = xmlGetNodePath(
3459 xmlTextReaderCurrentNode(reader));
3460 }
3461 fprintf(out,
3462 "xmlPatternMatch and xmlStreamPush disagree\n");
3463 fprintf(out,
3464 " pattern %s node %s\n",
3465 pattern, path);
3466 }
William M. Brackca15a542005-07-06 20:41:33 +00003467
Daniel Veillardaa6de472008-08-25 14:53:31 +00003468
3469 }
William M. Brackca15a542005-07-06 20:41:33 +00003470 if ((type == XML_READER_TYPE_END_ELEMENT) ||
3471 ((type == XML_READER_TYPE_ELEMENT) && (empty))) {
3472 ret = xmlStreamPop(patstream);
3473 if (ret < 0) {
3474 fprintf(out, "xmlStreamPop() failure\n");
3475 xmlFreeStreamCtxt(patstream);
3476 patstream = NULL;
3477 }
3478 }
3479 }
3480 if (path != NULL)
3481 xmlFree(path);
3482}
3483
3484/**
3485 * patternTest:
3486 * @filename: the schemas file
3487 * @result: the file with expected result
3488 * @err: the file with error messages
3489 *
Daniel Veillardaa6de472008-08-25 14:53:31 +00003490 * Parse a set of files with streaming, applying an RNG schemas
William M. Brackca15a542005-07-06 20:41:33 +00003491 *
3492 * Returns 0 in case of success, an error code otherwise
3493 */
3494static int
3495patternTest(const char *filename,
3496 const char *resul ATTRIBUTE_UNUSED,
3497 const char *err ATTRIBUTE_UNUSED,
3498 int options) {
3499 xmlPatternPtr patternc = NULL;
3500 xmlStreamCtxtPtr patstream = NULL;
3501 FILE *o, *f;
3502 char str[1024];
3503 char xml[500];
3504 char result[500];
3505 int len, i;
3506 int ret = 0, res;
3507 char *temp;
3508 xmlTextReaderPtr reader;
3509 xmlDocPtr doc;
3510
3511 len = strlen(filename);
3512 len -= 4;
3513 memcpy(xml, filename, len);
3514 xml[len] = 0;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003515 if (snprintf(result, 499, "result/pattern/%s", baseFilename(xml)) >= 499)
3516 result[499] = 0;
William M. Brackca15a542005-07-06 20:41:33 +00003517 memcpy(xml + len, ".xml", 5);
3518
David Kilzer5c373822016-05-22 09:58:30 +08003519 if (!checkTestFile(xml) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00003520 fprintf(stderr, "Missing xml file %s\n", xml);
3521 return(-1);
3522 }
David Kilzer5c373822016-05-22 09:58:30 +08003523 if (!checkTestFile(result) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00003524 fprintf(stderr, "Missing result file %s\n", result);
3525 return(-1);
3526 }
3527 f = fopen(filename, "rb");
3528 if (f == NULL) {
3529 fprintf(stderr, "Failed to open %s\n", filename);
3530 return(-1);
3531 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003532 temp = resultFilename(filename, temp_directory, ".res");
William M. Brackca15a542005-07-06 20:41:33 +00003533 if (temp == NULL) {
3534 fprintf(stderr, "Out of memory\n");
3535 fatalError();
3536 }
3537 o = fopen(temp, "wb");
3538 if (o == NULL) {
3539 fprintf(stderr, "failed to open output file %s\n", temp);
3540 fclose(f);
3541 free(temp);
3542 return(-1);
3543 }
3544 while (1) {
3545 /*
3546 * read one line in string buffer.
3547 */
3548 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
3549 break;
3550
3551 /*
3552 * remove the ending spaces
3553 */
3554 i = strlen(str);
3555 while ((i > 0) &&
3556 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
3557 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
3558 i--;
3559 str[i] = 0;
3560 }
3561 doc = xmlReadFile(xml, NULL, options);
3562 if (doc == NULL) {
3563 fprintf(stderr, "Failed to parse %s\n", xml);
3564 ret = 1;
3565 } else {
3566 xmlNodePtr root;
3567 const xmlChar *namespaces[22];
3568 int j;
3569 xmlNsPtr ns;
3570
3571 root = xmlDocGetRootElement(doc);
3572 for (ns = root->nsDef, j = 0;ns != NULL && j < 20;ns=ns->next) {
3573 namespaces[j++] = ns->href;
3574 namespaces[j++] = ns->prefix;
3575 }
3576 namespaces[j++] = NULL;
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003577 namespaces[j] = NULL;
William M. Brackca15a542005-07-06 20:41:33 +00003578
3579 patternc = xmlPatterncompile((const xmlChar *) str, doc->dict,
3580 0, &namespaces[0]);
3581 if (patternc == NULL) {
3582 testErrorHandler(NULL,
3583 "Pattern %s failed to compile\n", str);
3584 xmlFreeDoc(doc);
3585 ret = 1;
3586 continue;
3587 }
3588 patstream = xmlPatternGetStreamCtxt(patternc);
3589 if (patstream != NULL) {
3590 ret = xmlStreamPush(patstream, NULL, NULL);
3591 if (ret < 0) {
3592 fprintf(stderr, "xmlStreamPush() failure\n");
3593 xmlFreeStreamCtxt(patstream);
3594 patstream = NULL;
3595 }
3596 }
3597 nb_tests++;
3598
3599 reader = xmlReaderWalker(doc);
3600 res = xmlTextReaderRead(reader);
3601 while (res == 1) {
3602 patternNode(o, reader, str, patternc, patstream);
3603 res = xmlTextReaderRead(reader);
3604 }
3605 if (res != 0) {
3606 fprintf(o, "%s : failed to parse\n", filename);
3607 }
3608 xmlFreeTextReader(reader);
3609 xmlFreeDoc(doc);
3610 xmlFreeStreamCtxt(patstream);
3611 patstream = NULL;
3612 xmlFreePattern(patternc);
3613
3614 }
3615 }
3616
3617 fclose(f);
3618 fclose(o);
3619
3620 ret = compareFiles(temp, result);
3621 if (ret) {
Daniel Veillard9f2416c2016-05-22 11:14:45 +08003622 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
William M. Brackca15a542005-07-06 20:41:33 +00003623 ret = 1;
3624 }
Daniel Veillard13cee4e2009-09-05 14:52:55 +02003625 if (temp != NULL) {
3626 unlink(temp);
3627 free(temp);
3628 }
William M. Brackca15a542005-07-06 20:41:33 +00003629 return(ret);
3630}
3631#endif /* READER */
3632#endif /* PATTERN */
3633#ifdef LIBXML_C14N_ENABLED
3634/************************************************************************
3635 * *
3636 * Canonicalization tests *
3637 * *
3638 ************************************************************************/
3639static xmlXPathObjectPtr
3640load_xpath_expr (xmlDocPtr parent_doc, const char* filename) {
Daniel Veillardaa6de472008-08-25 14:53:31 +00003641 xmlXPathObjectPtr xpath;
William M. Brackca15a542005-07-06 20:41:33 +00003642 xmlDocPtr doc;
3643 xmlChar *expr;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003644 xmlXPathContextPtr ctx;
William M. Brackca15a542005-07-06 20:41:33 +00003645 xmlNodePtr node;
3646 xmlNsPtr ns;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003647
William M. Brackca15a542005-07-06 20:41:33 +00003648 /*
3649 * load XPath expr as a file
3650 */
3651 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3652 xmlSubstituteEntitiesDefault(1);
3653
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003654 doc = xmlReadFile(filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
William M. Brackca15a542005-07-06 20:41:33 +00003655 if (doc == NULL) {
3656 fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
3657 return(NULL);
3658 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003659
William M. Brackca15a542005-07-06 20:41:33 +00003660 /*
3661 * Check the document is of the right kind
Daniel Veillardaa6de472008-08-25 14:53:31 +00003662 */
William M. Brackca15a542005-07-06 20:41:33 +00003663 if(xmlDocGetRootElement(doc) == NULL) {
3664 fprintf(stderr,"Error: empty document for file \"%s\"\n", filename);
3665 xmlFreeDoc(doc);
3666 return(NULL);
3667 }
3668
3669 node = doc->children;
3670 while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) {
3671 node = node->next;
3672 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003673
3674 if(node == NULL) {
William M. Brackca15a542005-07-06 20:41:33 +00003675 fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename);
3676 xmlFreeDoc(doc);
3677 return(NULL);
3678 }
3679
3680 expr = xmlNodeGetContent(node);
3681 if(expr == NULL) {
3682 fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename);
3683 xmlFreeDoc(doc);
3684 return(NULL);
3685 }
3686
3687 ctx = xmlXPathNewContext(parent_doc);
3688 if(ctx == NULL) {
3689 fprintf(stderr,"Error: unable to create new context\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003690 xmlFree(expr);
3691 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003692 return(NULL);
3693 }
3694
3695 /*
3696 * Register namespaces
3697 */
3698 ns = node->nsDef;
3699 while(ns != NULL) {
3700 if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) {
3701 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 +00003702 xmlFree(expr);
3703 xmlXPathFreeContext(ctx);
3704 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003705 return(NULL);
3706 }
3707 ns = ns->next;
3708 }
3709
Daniel Veillardaa6de472008-08-25 14:53:31 +00003710 /*
William M. Brackca15a542005-07-06 20:41:33 +00003711 * Evaluate xpath
3712 */
3713 xpath = xmlXPathEvalExpression(expr, ctx);
3714 if(xpath == NULL) {
3715 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003716xmlFree(expr);
3717 xmlXPathFreeContext(ctx);
3718 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003719 return(NULL);
3720 }
3721
3722 /* print_xpath_nodes(xpath->nodesetval); */
3723
Daniel Veillardaa6de472008-08-25 14:53:31 +00003724 xmlFree(expr);
3725 xmlXPathFreeContext(ctx);
3726 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003727 return(xpath);
3728}
3729
3730/*
3731 * Macro used to grow the current buffer.
3732 */
3733#define xxx_growBufferReentrant() { \
3734 buffer_size *= 2; \
3735 buffer = (xmlChar **) \
Daniel Veillardaa6de472008-08-25 14:53:31 +00003736 xmlRealloc(buffer, buffer_size * sizeof(xmlChar*)); \
William M. Brackca15a542005-07-06 20:41:33 +00003737 if (buffer == NULL) { \
3738 perror("realloc failed"); \
3739 return(NULL); \
3740 } \
3741}
3742
3743static xmlChar **
3744parse_list(xmlChar *str) {
3745 xmlChar **buffer;
3746 xmlChar **out = NULL;
3747 int buffer_size = 0;
3748 int len;
3749
3750 if(str == NULL) {
3751 return(NULL);
3752 }
3753
3754 len = xmlStrlen(str);
3755 if((str[0] == '\'') && (str[len - 1] == '\'')) {
3756 str[len - 1] = '\0';
3757 str++;
William M. Brackca15a542005-07-06 20:41:33 +00003758 }
3759 /*
3760 * allocate an translation buffer.
3761 */
3762 buffer_size = 1000;
3763 buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*));
3764 if (buffer == NULL) {
3765 perror("malloc failed");
3766 return(NULL);
3767 }
3768 out = buffer;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003769
William M. Brackca15a542005-07-06 20:41:33 +00003770 while(*str != '\0') {
3771 if (out - buffer > buffer_size - 10) {
3772 int indx = out - buffer;
3773
3774 xxx_growBufferReentrant();
3775 out = &buffer[indx];
3776 }
3777 (*out++) = str;
3778 while(*str != ',' && *str != '\0') ++str;
3779 if(*str == ',') *(str++) = '\0';
3780 }
3781 (*out) = NULL;
3782 return buffer;
3783}
3784
Daniel Veillardaa6de472008-08-25 14:53:31 +00003785static int
Aleksey Sanin83868242009-07-09 10:26:22 +02003786c14nRunTest(const char* xml_filename, int with_comments, int mode,
William M. Brackca15a542005-07-06 20:41:33 +00003787 const char* xpath_filename, const char *ns_filename,
3788 const char* result_file) {
3789 xmlDocPtr doc;
Daniel Veillardaa6de472008-08-25 14:53:31 +00003790 xmlXPathObjectPtr xpath = NULL;
William M. Brackca15a542005-07-06 20:41:33 +00003791 xmlChar *result = NULL;
3792 int ret;
3793 xmlChar **inclusive_namespaces = NULL;
3794 const char *nslist = NULL;
3795 int nssize;
3796
3797
3798 /*
3799 * build an XML tree from a the file; we need to add default
3800 * attributes and resolve all character and entities references
3801 */
3802 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3803 xmlSubstituteEntitiesDefault(1);
3804
Daniel Veillardbca3ad22005-08-23 22:14:02 +00003805 doc = xmlReadFile(xml_filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
William M. Brackca15a542005-07-06 20:41:33 +00003806 if (doc == NULL) {
3807 fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename);
3808 return(-1);
3809 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003810
William M. Brackca15a542005-07-06 20:41:33 +00003811 /*
3812 * Check the document is of the right kind
Daniel Veillardaa6de472008-08-25 14:53:31 +00003813 */
William M. Brackca15a542005-07-06 20:41:33 +00003814 if(xmlDocGetRootElement(doc) == NULL) {
3815 fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename);
3816 xmlFreeDoc(doc);
3817 return(-1);
3818 }
3819
Daniel Veillardaa6de472008-08-25 14:53:31 +00003820 /*
3821 * load xpath file if specified
William M. Brackca15a542005-07-06 20:41:33 +00003822 */
3823 if(xpath_filename) {
3824 xpath = load_xpath_expr(doc, xpath_filename);
3825 if(xpath == NULL) {
3826 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
Daniel Veillardaa6de472008-08-25 14:53:31 +00003827 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003828 return(-1);
3829 }
3830 }
3831
3832 if (ns_filename != NULL) {
3833 if (loadMem(ns_filename, &nslist, &nssize)) {
3834 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3835 if(xpath != NULL) xmlXPathFreeObject(xpath);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003836 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003837 return(-1);
3838 }
3839 inclusive_namespaces = parse_list((xmlChar *) nslist);
3840 }
3841
3842 /*
3843 * Canonical form
Daniel Veillardaa6de472008-08-25 14:53:31 +00003844 */
William M. Brackca15a542005-07-06 20:41:33 +00003845 /* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */
Daniel Veillardaa6de472008-08-25 14:53:31 +00003846 ret = xmlC14NDocDumpMemory(doc,
3847 (xpath) ? xpath->nodesetval : NULL,
Aleksey Sanin83868242009-07-09 10:26:22 +02003848 mode, inclusive_namespaces,
William M. Brackca15a542005-07-06 20:41:33 +00003849 with_comments, &result);
3850 if (ret >= 0) {
3851 if(result != NULL) {
3852 if (compareFileMem(result_file, (const char *) result, ret)) {
3853 fprintf(stderr, "Result mismatch for %s\n", xml_filename);
Aleksey Sanin83868242009-07-09 10:26:22 +02003854 fprintf(stderr, "RESULT:\n%s\n", (const char*)result);
William M. Brackca15a542005-07-06 20:41:33 +00003855 ret = -1;
3856 }
3857 }
3858 } else {
3859 fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret);
3860 ret = -1;
3861 }
Daniel Veillardaa6de472008-08-25 14:53:31 +00003862
William M. Brackca15a542005-07-06 20:41:33 +00003863 /*
3864 * Cleanup
Daniel Veillardaa6de472008-08-25 14:53:31 +00003865 */
William M. Brackca15a542005-07-06 20:41:33 +00003866 if (result != NULL) xmlFree(result);
3867 if(xpath != NULL) xmlXPathFreeObject(xpath);
3868 if (inclusive_namespaces != NULL) xmlFree(inclusive_namespaces);
3869 if (nslist != NULL) free((char *) nslist);
Daniel Veillardaa6de472008-08-25 14:53:31 +00003870 xmlFreeDoc(doc);
William M. Brackca15a542005-07-06 20:41:33 +00003871
3872 return(ret);
3873}
3874
3875static int
Aleksey Sanin83868242009-07-09 10:26:22 +02003876c14nCommonTest(const char *filename, int with_comments, int mode,
William M. Brackca15a542005-07-06 20:41:33 +00003877 const char *subdir) {
3878 char buf[500];
3879 char prefix[500];
3880 const char *base;
3881 int len;
3882 char *result = NULL;
3883 char *xpath = NULL;
3884 char *ns = NULL;
3885 int ret = 0;
3886
3887 base = baseFilename(filename);
3888 len = strlen(base);
3889 len -= 4;
3890 memcpy(prefix, base, len);
3891 prefix[len] = 0;
3892
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003893 if (snprintf(buf, 499, "result/c14n/%s/%s", subdir, prefix) >= 499)
3894 buf[499] = 0;
David Kilzer5c373822016-05-22 09:58:30 +08003895 if (!checkTestFile(buf) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00003896 fprintf(stderr, "Missing result file %s", buf);
3897 return(-1);
3898 }
3899 result = strdup(buf);
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003900 if (snprintf(buf, 499, "test/c14n/%s/%s.xpath", subdir, prefix) >= 499)
3901 buf[499] = 0;
William M. Brackca15a542005-07-06 20:41:33 +00003902 if (checkTestFile(buf)) {
3903 xpath = strdup(buf);
3904 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003905 if (snprintf(buf, 499, "test/c14n/%s/%s.ns", subdir, prefix) >= 499)
3906 buf[499] = 0;
William M. Brackca15a542005-07-06 20:41:33 +00003907 if (checkTestFile(buf)) {
3908 ns = strdup(buf);
3909 }
3910
3911 nb_tests++;
Aleksey Sanin83868242009-07-09 10:26:22 +02003912 if (c14nRunTest(filename, with_comments, mode,
William M. Brackca15a542005-07-06 20:41:33 +00003913 xpath, ns, result) < 0)
3914 ret = 1;
3915
3916 if (result != NULL) free(result);
3917 if (xpath != NULL) free(xpath);
3918 if (ns != NULL) free(ns);
3919 return(ret);
3920}
3921
3922static int
3923c14nWithCommentTest(const char *filename,
3924 const char *resul ATTRIBUTE_UNUSED,
3925 const char *err ATTRIBUTE_UNUSED,
3926 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003927 return(c14nCommonTest(filename, 1, XML_C14N_1_0, "with-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003928}
3929static int
3930c14nWithoutCommentTest(const char *filename,
3931 const char *resul ATTRIBUTE_UNUSED,
3932 const char *err ATTRIBUTE_UNUSED,
3933 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003934 return(c14nCommonTest(filename, 0, XML_C14N_1_0, "without-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003935}
3936static int
3937c14nExcWithoutCommentTest(const char *filename,
3938 const char *resul ATTRIBUTE_UNUSED,
3939 const char *err ATTRIBUTE_UNUSED,
3940 int options ATTRIBUTE_UNUSED) {
Aleksey Sanin83868242009-07-09 10:26:22 +02003941 return(c14nCommonTest(filename, 0, XML_C14N_EXCLUSIVE_1_0, "exc-without-comments"));
3942}
3943static int
3944c14n11WithoutCommentTest(const char *filename,
3945 const char *resul ATTRIBUTE_UNUSED,
3946 const char *err ATTRIBUTE_UNUSED,
3947 int options ATTRIBUTE_UNUSED) {
3948 return(c14nCommonTest(filename, 0, XML_C14N_1_1, "1-1-without-comments"));
William M. Brackca15a542005-07-06 20:41:33 +00003949}
3950#endif
Nick Wellnhofer01a4b812017-06-16 21:27:47 +02003951#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
William M. Brackca15a542005-07-06 20:41:33 +00003952/************************************************************************
3953 * *
3954 * Catalog and threads test *
3955 * *
3956 ************************************************************************/
3957
3958/*
3959 * mostly a cut and paste from testThreads.c
3960 */
3961#define MAX_ARGC 20
3962
Nick Wellnhofercf820462017-10-21 14:43:00 +02003963typedef struct {
3964 const char *filename;
3965 int okay;
3966} xmlThreadParams;
William M. Brackca15a542005-07-06 20:41:33 +00003967
Nick Wellnhofercf820462017-10-21 14:43:00 +02003968static const char *catalog = "test/threads/complex.xml";
3969static xmlThreadParams threadParams[] = {
3970 { "test/threads/abc.xml", 0 },
3971 { "test/threads/acb.xml", 0 },
3972 { "test/threads/bac.xml", 0 },
3973 { "test/threads/bca.xml", 0 },
3974 { "test/threads/cab.xml", 0 },
3975 { "test/threads/cba.xml", 0 },
3976 { "test/threads/invalid.xml", 0 }
3977};
3978static const unsigned int num_threads = sizeof(threadParams) /
3979 sizeof(threadParams[0]);
William M. Brackca15a542005-07-06 20:41:33 +00003980
3981#ifndef xmlDoValidityCheckingDefaultValue
3982#error xmlDoValidityCheckingDefaultValue is not a macro
3983#endif
3984#ifndef xmlGenericErrorContext
3985#error xmlGenericErrorContext is not a macro
3986#endif
3987
3988static void *
3989thread_specific_data(void *private_data)
3990{
3991 xmlDocPtr myDoc;
Nick Wellnhofercf820462017-10-21 14:43:00 +02003992 xmlThreadParams *params = (xmlThreadParams *) private_data;
3993 const char *filename = params->filename;
William M. Brackca15a542005-07-06 20:41:33 +00003994 int okay = 1;
3995
3996 if (!strcmp(filename, "test/threads/invalid.xml")) {
3997 xmlDoValidityCheckingDefaultValue = 0;
3998 xmlGenericErrorContext = stdout;
3999 } else {
4000 xmlDoValidityCheckingDefaultValue = 1;
4001 xmlGenericErrorContext = stderr;
4002 }
Nick Wellnhofer01a4b812017-06-16 21:27:47 +02004003#ifdef LIBXML_SAX1_ENABLED
William M. Brackca15a542005-07-06 20:41:33 +00004004 myDoc = xmlParseFile(filename);
Nick Wellnhofer01a4b812017-06-16 21:27:47 +02004005#else
4006 myDoc = xmlReadFile(filename, NULL, XML_WITH_CATALOG);
4007#endif
William M. Brackca15a542005-07-06 20:41:33 +00004008 if (myDoc) {
4009 xmlFreeDoc(myDoc);
4010 } else {
4011 printf("parse failed\n");
4012 okay = 0;
4013 }
4014 if (!strcmp(filename, "test/threads/invalid.xml")) {
4015 if (xmlDoValidityCheckingDefaultValue != 0) {
4016 printf("ValidityCheckingDefaultValue override failed\n");
4017 okay = 0;
4018 }
4019 if (xmlGenericErrorContext != stdout) {
4020 printf("xmlGenericErrorContext override failed\n");
4021 okay = 0;
4022 }
4023 } else {
4024 if (xmlDoValidityCheckingDefaultValue != 1) {
4025 printf("ValidityCheckingDefaultValue override failed\n");
4026 okay = 0;
4027 }
4028 if (xmlGenericErrorContext != stderr) {
4029 printf("xmlGenericErrorContext override failed\n");
4030 okay = 0;
4031 }
4032 }
Nick Wellnhofercf820462017-10-21 14:43:00 +02004033 params->okay = okay;
4034 return(NULL);
William M. Brackca15a542005-07-06 20:41:33 +00004035}
4036
Nick Wellnhofere3890542017-10-09 00:20:01 +02004037#if defined(_WIN32) && !defined(__CYGWIN__)
William M. Brackca15a542005-07-06 20:41:33 +00004038#include <windows.h>
4039#include <string.h>
4040
4041#define TEST_REPEAT_COUNT 500
4042
4043static HANDLE tid[MAX_ARGC];
4044
4045static DWORD WINAPI
4046win32_thread_specific_data(void *private_data)
4047{
Nick Wellnhofercf820462017-10-21 14:43:00 +02004048 thread_specific_data(private_data);
4049 return(0);
William M. Brackca15a542005-07-06 20:41:33 +00004050}
4051
4052static int
4053testThread(void)
4054{
4055 unsigned int i, repeat;
William M. Brackca15a542005-07-06 20:41:33 +00004056 BOOL ret;
4057 int res = 0;
4058
4059 xmlInitParser();
4060 for (repeat = 0; repeat < TEST_REPEAT_COUNT; repeat++) {
4061 xmlLoadCatalog(catalog);
4062 nb_tests++;
4063
4064 for (i = 0; i < num_threads; i++) {
William M. Brackca15a542005-07-06 20:41:33 +00004065 tid[i] = (HANDLE) - 1;
4066 }
4067
4068 for (i = 0; i < num_threads; i++) {
4069 DWORD useless;
4070
4071 tid[i] = CreateThread(NULL, 0,
Daniel Veillardaa6de472008-08-25 14:53:31 +00004072 win32_thread_specific_data,
Nick Wellnhofercf820462017-10-21 14:43:00 +02004073 (void *) &threadParams[i], 0,
William M. Brackca15a542005-07-06 20:41:33 +00004074 &useless);
4075 if (tid[i] == NULL) {
4076 fprintf(stderr, "CreateThread failed\n");
4077 return(1);
4078 }
4079 }
4080
4081 if (WaitForMultipleObjects(num_threads, tid, TRUE, INFINITE) ==
4082 WAIT_FAILED) {
4083 fprintf(stderr, "WaitForMultipleObjects failed\n");
4084 return(1);
4085 }
4086
4087 for (i = 0; i < num_threads; i++) {
Nick Wellnhofercf820462017-10-21 14:43:00 +02004088 DWORD exitCode;
4089 ret = GetExitCodeThread(tid[i], &exitCode);
William M. Brackca15a542005-07-06 20:41:33 +00004090 if (ret == 0) {
4091 fprintf(stderr, "GetExitCodeThread failed\n");
4092 return(1);
4093 }
4094 CloseHandle(tid[i]);
4095 }
4096
4097 xmlCatalogCleanup();
4098 for (i = 0; i < num_threads; i++) {
Nick Wellnhofercf820462017-10-21 14:43:00 +02004099 if (threadParams[i].okay == 0) {
William M. Brackca15a542005-07-06 20:41:33 +00004100 fprintf(stderr, "Thread %d handling %s failed\n",
Nick Wellnhofercf820462017-10-21 14:43:00 +02004101 i, threadParams[i].filename);
William M. Brackca15a542005-07-06 20:41:33 +00004102 res = 1;
4103 }
4104 }
4105 }
4106
4107 return (res);
4108}
4109
4110#elif defined __BEOS__
4111#include <OS.h>
4112
4113static thread_id tid[MAX_ARGC];
4114
4115static int
4116testThread(void)
4117{
4118 unsigned int i, repeat;
William M. Brackca15a542005-07-06 20:41:33 +00004119 status_t ret;
4120 int res = 0;
4121
4122 xmlInitParser();
4123 for (repeat = 0; repeat < 500; repeat++) {
4124 xmlLoadCatalog(catalog);
4125 for (i = 0; i < num_threads; i++) {
William M. Brackca15a542005-07-06 20:41:33 +00004126 tid[i] = (thread_id) - 1;
4127 }
4128 for (i = 0; i < num_threads; i++) {
4129 tid[i] =
4130 spawn_thread(thread_specific_data, "xmlTestThread",
Nick Wellnhofercf820462017-10-21 14:43:00 +02004131 B_NORMAL_PRIORITY, (void *) &threadParams[i]);
William M. Brackca15a542005-07-06 20:41:33 +00004132 if (tid[i] < B_OK) {
4133 fprintf(stderr, "beos_thread_create failed\n");
4134 return (1);
4135 }
4136 printf("beos_thread_create %d -> %d\n", i, tid[i]);
4137 }
4138 for (i = 0; i < num_threads; i++) {
Nick Wellnhofercf820462017-10-21 14:43:00 +02004139 void *result;
4140 ret = wait_for_thread(tid[i], &result);
William M. Brackca15a542005-07-06 20:41:33 +00004141 printf("beos_thread_wait %d -> %d\n", i, ret);
4142 if (ret != B_OK) {
4143 fprintf(stderr, "beos_thread_wait failed\n");
4144 return (1);
4145 }
4146 }
4147
4148 xmlCatalogCleanup();
4149 ret = B_OK;
4150 for (i = 0; i < num_threads; i++)
Nick Wellnhofercf820462017-10-21 14:43:00 +02004151 if (threadParams[i].okay == 0) {
4152 printf("Thread %d handling %s failed\n", i,
4153 threadParams[i].filename);
William M. Brackca15a542005-07-06 20:41:33 +00004154 ret = B_ERROR;
4155 }
4156 }
4157 if (ret != B_OK)
4158 return(1);
4159 return (0);
4160}
Daniel Richard G495a73d2012-08-07 10:14:56 +08004161
4162#elif defined HAVE_PTHREAD_H
4163#include <pthread.h>
4164
4165static pthread_t tid[MAX_ARGC];
4166
4167static int
4168testThread(void)
4169{
4170 unsigned int i, repeat;
Daniel Richard G495a73d2012-08-07 10:14:56 +08004171 int ret;
4172 int res = 0;
4173
4174 xmlInitParser();
4175
4176 for (repeat = 0; repeat < 500; repeat++) {
4177 xmlLoadCatalog(catalog);
4178 nb_tests++;
4179
4180 for (i = 0; i < num_threads; i++) {
Daniel Richard G495a73d2012-08-07 10:14:56 +08004181 tid[i] = (pthread_t) - 1;
4182 }
4183
4184 for (i = 0; i < num_threads; i++) {
4185 ret = pthread_create(&tid[i], 0, thread_specific_data,
Nick Wellnhofercf820462017-10-21 14:43:00 +02004186 (void *) &threadParams[i]);
Daniel Richard G495a73d2012-08-07 10:14:56 +08004187 if (ret != 0) {
4188 fprintf(stderr, "pthread_create failed\n");
4189 return (1);
4190 }
4191 }
4192 for (i = 0; i < num_threads; i++) {
Nick Wellnhofercf820462017-10-21 14:43:00 +02004193 void *result;
4194 ret = pthread_join(tid[i], &result);
Daniel Richard G495a73d2012-08-07 10:14:56 +08004195 if (ret != 0) {
4196 fprintf(stderr, "pthread_join failed\n");
4197 return (1);
4198 }
4199 }
4200
4201 xmlCatalogCleanup();
4202 for (i = 0; i < num_threads; i++)
Nick Wellnhofercf820462017-10-21 14:43:00 +02004203 if (threadParams[i].okay == 0) {
Daniel Richard G495a73d2012-08-07 10:14:56 +08004204 fprintf(stderr, "Thread %d handling %s failed\n",
Nick Wellnhofercf820462017-10-21 14:43:00 +02004205 i, threadParams[i].filename);
Daniel Richard G495a73d2012-08-07 10:14:56 +08004206 res = 1;
4207 }
4208 }
4209 return (res);
4210}
4211
William M. Brackca15a542005-07-06 20:41:33 +00004212#else
4213static int
4214testThread(void)
4215{
4216 fprintf(stderr,
4217 "Specific platform thread support not detected\n");
4218 return (-1);
4219}
4220#endif
Daniel Veillardaa6de472008-08-25 14:53:31 +00004221static int
William M. Brackca15a542005-07-06 20:41:33 +00004222threadsTest(const char *filename ATTRIBUTE_UNUSED,
4223 const char *resul ATTRIBUTE_UNUSED,
4224 const char *err ATTRIBUTE_UNUSED,
4225 int options ATTRIBUTE_UNUSED) {
4226 return(testThread());
4227}
4228#endif
4229/************************************************************************
4230 * *
4231 * Tests Descriptions *
4232 * *
4233 ************************************************************************/
4234
4235static
4236testDesc testDescriptions[] = {
4237 { "XML regression tests" ,
4238 oldParseTest, "./test/*", "result/", "", NULL,
4239 0 },
4240 { "XML regression tests on memory" ,
4241 memParseTest, "./test/*", "result/", "", NULL,
4242 0 },
4243 { "XML entity subst regression tests" ,
4244 noentParseTest, "./test/*", "result/noent/", "", NULL,
4245 XML_PARSE_NOENT },
4246 { "XML Namespaces regression tests",
4247 errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err",
4248 0 },
4249 { "Error cases regression tests",
4250 errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err",
4251 0 },
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004252 { "Error cases regression tests with entity substitution",
4253 errParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".ent",
4254 XML_PARSE_NOENT },
Nick Wellnhofere2663052017-06-05 15:37:17 +02004255 { "Error cases regression tests (old 1.0)",
4256 errParseTest, "./test/errors10/*.xml", "result/errors10/", "", ".err",
4257 XML_PARSE_OLD10 },
William M. Brackca15a542005-07-06 20:41:33 +00004258#ifdef LIBXML_READER_ENABLED
4259 { "Error cases stream regression tests",
4260 streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str",
4261 0 },
4262 { "Reader regression tests",
4263 streamParseTest, "./test/*", "result/", ".rdr", NULL,
4264 0 },
4265 { "Reader entities substitution regression tests",
4266 streamParseTest, "./test/*", "result/", ".rde", NULL,
4267 XML_PARSE_NOENT },
4268 { "Reader on memory regression tests",
4269 streamMemParseTest, "./test/*", "result/", ".rdr", NULL,
4270 0 },
4271 { "Walker regression tests",
4272 walkerParseTest, "./test/*", "result/", ".rdr", NULL,
4273 0 },
4274#endif
4275#ifdef LIBXML_SAX1_ENABLED
4276 { "SAX1 callbacks regression tests" ,
4277 saxParseTest, "./test/*", "result/", ".sax", NULL,
4278 XML_PARSE_SAX1 },
Nick Wellnhoferdbaab1f2017-06-16 21:38:57 +02004279#endif
William M. Brackca15a542005-07-06 20:41:33 +00004280 { "SAX2 callbacks regression tests" ,
4281 saxParseTest, "./test/*", "result/", ".sax2", NULL,
4282 0 },
Nick Wellnhoferdbaab1f2017-06-16 21:38:57 +02004283 { "SAX2 callbacks regression tests with entity substitution" ,
4284 saxParseTest, "./test/*", "result/noent/", ".sax2", NULL,
4285 XML_PARSE_NOENT },
William M. Brackca15a542005-07-06 20:41:33 +00004286#ifdef LIBXML_PUSH_ENABLED
4287 { "XML push regression tests" ,
4288 pushParseTest, "./test/*", "result/", "", NULL,
4289 0 },
4290#endif
4291#ifdef LIBXML_HTML_ENABLED
4292 { "HTML regression tests" ,
4293 errParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4294 XML_PARSE_HTML },
4295#ifdef LIBXML_PUSH_ENABLED
4296 { "Push HTML regression tests" ,
4297 pushParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4298 XML_PARSE_HTML },
4299#endif
William M. Brackca15a542005-07-06 20:41:33 +00004300 { "HTML SAX regression tests" ,
4301 saxParseTest, "./test/HTML/*", "result/HTML/", ".sax", NULL,
4302 XML_PARSE_HTML },
4303#endif
William M. Brackca15a542005-07-06 20:41:33 +00004304#ifdef LIBXML_VALID_ENABLED
4305 { "Valid documents regression tests" ,
4306 errParseTest, "./test/VCM/*", NULL, NULL, NULL,
4307 XML_PARSE_DTDVALID },
4308 { "Validity checking regression tests" ,
4309 errParseTest, "./test/VC/*", "result/VC/", NULL, "",
4310 XML_PARSE_DTDVALID },
Daniel Veillarda7982ce2012-10-25 15:39:39 +08004311#ifdef LIBXML_READER_ENABLED
4312 { "Streaming validity checking regression tests" ,
4313 streamParseTest, "./test/valid/*.xml", "result/valid/", NULL, ".err.rdr",
4314 XML_PARSE_DTDVALID },
4315 { "Streaming validity error checking regression tests" ,
4316 streamParseTest, "./test/VC/*", "result/VC/", NULL, ".rdr",
4317 XML_PARSE_DTDVALID },
4318#endif
William M. Brackca15a542005-07-06 20:41:33 +00004319 { "General documents valid regression tests" ,
4320 errParseTest, "./test/valid/*", "result/valid/", "", ".err",
4321 XML_PARSE_DTDVALID },
4322#endif
4323#ifdef LIBXML_XINCLUDE_ENABLED
4324 { "XInclude regression tests" ,
4325 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4326 /* Ignore errors at this point ".err", */
4327 XML_PARSE_XINCLUDE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004328#ifdef LIBXML_READER_ENABLED
William M. Brackca15a542005-07-06 20:41:33 +00004329 { "XInclude xmlReader regression tests",
4330 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4331 /* Ignore errors at this point ".err", */
4332 NULL, XML_PARSE_XINCLUDE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004333#endif
William M. Brackca15a542005-07-06 20:41:33 +00004334 { "XInclude regression tests stripping include nodes" ,
4335 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4336 /* Ignore errors at this point ".err", */
4337 XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004338#ifdef LIBXML_READER_ENABLED
William M. Brackca15a542005-07-06 20:41:33 +00004339 { "XInclude xmlReader regression tests stripping include nodes",
4340 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4341 /* Ignore errors at this point ".err", */
4342 NULL, XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
4343#endif
Daniel Veillard438ebbd2008-05-12 12:58:46 +00004344#endif
William M. Brackca15a542005-07-06 20:41:33 +00004345#ifdef LIBXML_XPATH_ENABLED
4346#ifdef LIBXML_DEBUG_ENABLED
4347 { "XPath expressions regression tests" ,
4348 xpathExprTest, "./test/XPath/expr/*", "result/XPath/expr/", "", NULL,
4349 0 },
4350 { "XPath document queries regression tests" ,
4351 xpathDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4352 0 },
4353#ifdef LIBXML_XPTR_ENABLED
4354 { "XPointer document queries regression tests" ,
4355 xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4356 0 },
4357#endif
4358 { "xml:id regression tests" ,
4359 xmlidDocTest, "./test/xmlid/*", "result/xmlid/", "", ".err",
4360 0 },
4361#endif
4362#endif
4363 { "URI parsing tests" ,
4364 uriParseTest, "./test/URI/*.uri", "result/URI/", "", NULL,
4365 0 },
4366 { "URI base composition tests" ,
4367 uriBaseTest, "./test/URI/*.data", "result/URI/", "", NULL,
4368 0 },
Daniel Veillard336a8e12005-08-07 10:46:19 +00004369 { "Path URI conversion tests" ,
4370 uriPathTest, NULL, NULL, NULL, NULL,
4371 0 },
William M. Brackca15a542005-07-06 20:41:33 +00004372#ifdef LIBXML_SCHEMAS_ENABLED
4373 { "Schemas regression tests" ,
4374 schemasTest, "./test/schemas/*_*.xsd", NULL, NULL, NULL,
4375 0 },
4376 { "Relax-NG regression tests" ,
4377 rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4378 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4379#ifdef LIBXML_READER_ENABLED
4380 { "Relax-NG streaming regression tests" ,
4381 rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4382 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4383#endif
4384#endif
4385#ifdef LIBXML_PATTERN_ENABLED
4386#ifdef LIBXML_READER_ENABLED
4387 { "Pattern regression tests" ,
4388 patternTest, "./test/pattern/*.pat", "result/pattern/", NULL, NULL,
4389 0 },
4390#endif
4391#endif
4392#ifdef LIBXML_C14N_ENABLED
4393 { "C14N with comments regression tests" ,
4394 c14nWithCommentTest, "./test/c14n/with-comments/*.xml", NULL, NULL, NULL,
4395 0 },
4396 { "C14N without comments regression tests" ,
4397 c14nWithoutCommentTest, "./test/c14n/without-comments/*.xml", NULL, NULL, NULL,
4398 0 },
4399 { "C14N exclusive without comments regression tests" ,
4400 c14nExcWithoutCommentTest, "./test/c14n/exc-without-comments/*.xml", NULL, NULL, NULL,
4401 0 },
Aleksey Sanin83868242009-07-09 10:26:22 +02004402 { "C14N 1.1 without comments regression tests" ,
4403 c14n11WithoutCommentTest, "./test/c14n/1-1-without-comments/*.xml", NULL, NULL, NULL,
4404 0 },
William M. Brackca15a542005-07-06 20:41:33 +00004405#endif
Nick Wellnhofer01a4b812017-06-16 21:27:47 +02004406#if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
William M. Brackca15a542005-07-06 20:41:33 +00004407 { "Catalog and Threads regression tests" ,
4408 threadsTest, NULL, NULL, NULL, NULL,
4409 0 },
4410#endif
4411 {NULL, NULL, NULL, NULL, NULL, NULL, 0}
4412};
4413
4414/************************************************************************
4415 * *
4416 * The main code driving the tests *
4417 * *
4418 ************************************************************************/
4419
4420static int
4421launchTests(testDescPtr tst) {
4422 int res = 0, err = 0;
4423 size_t i;
4424 char *result;
4425 char *error;
4426 int mem;
Elliott Hughes7fbecab2019-01-10 16:42:03 -08004427 xmlCharEncodingHandlerPtr ebcdicHandler, eucJpHandler;
Nick Wellnhofer4b413592017-10-31 17:17:16 +01004428
4429 ebcdicHandler = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_EBCDIC);
Elliott Hughes7fbecab2019-01-10 16:42:03 -08004430 eucJpHandler = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_EUC_JP);
William M. Brackca15a542005-07-06 20:41:33 +00004431
4432 if (tst == NULL) return(-1);
4433 if (tst->in != NULL) {
4434 glob_t globbuf;
4435
4436 globbuf.gl_offs = 0;
4437 glob(tst->in, GLOB_DOOFFS, NULL, &globbuf);
4438 for (i = 0;i < globbuf.gl_pathc;i++) {
4439 if (!checkTestFile(globbuf.gl_pathv[i]))
4440 continue;
Elliott Hughes7fbecab2019-01-10 16:42:03 -08004441 if (((ebcdicHandler == NULL) &&
4442 (strstr(globbuf.gl_pathv[i], "ebcdic") != NULL)) ||
4443 ((eucJpHandler == NULL) &&
4444 (strstr(globbuf.gl_pathv[i], "icu_parse_test") != NULL)))
Nick Wellnhofer4b413592017-10-31 17:17:16 +01004445 continue;
William M. Brackca15a542005-07-06 20:41:33 +00004446 if (tst->suffix != NULL) {
4447 result = resultFilename(globbuf.gl_pathv[i], tst->out,
4448 tst->suffix);
4449 if (result == NULL) {
4450 fprintf(stderr, "Out of memory !\n");
4451 fatalError();
4452 }
4453 } else {
4454 result = NULL;
4455 }
4456 if (tst->err != NULL) {
4457 error = resultFilename(globbuf.gl_pathv[i], tst->out,
4458 tst->err);
4459 if (error == NULL) {
4460 fprintf(stderr, "Out of memory !\n");
4461 fatalError();
4462 }
4463 } else {
4464 error = NULL;
4465 }
David Kilzer5c373822016-05-22 09:58:30 +08004466 if ((result) &&(!checkTestFile(result)) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00004467 fprintf(stderr, "Missing result file %s\n", result);
David Kilzer5c373822016-05-22 09:58:30 +08004468 } else if ((error) &&(!checkTestFile(error)) && !update_results) {
William M. Brackca15a542005-07-06 20:41:33 +00004469 fprintf(stderr, "Missing error file %s\n", error);
4470 } else {
4471 mem = xmlMemUsed();
4472 extraMemoryFromResolver = 0;
4473 testErrorsSize = 0;
4474 testErrors[0] = 0;
4475 res = tst->func(globbuf.gl_pathv[i], result, error,
Daniel Veillard8874b942005-08-25 13:19:21 +00004476 tst->options | XML_PARSE_COMPACT);
William M. Brackca15a542005-07-06 20:41:33 +00004477 xmlResetLastError();
4478 if (res != 0) {
4479 fprintf(stderr, "File %s generated an error\n",
4480 globbuf.gl_pathv[i]);
4481 nb_errors++;
4482 err++;
4483 }
4484 else if (xmlMemUsed() != mem) {
4485 if ((xmlMemUsed() != mem) &&
4486 (extraMemoryFromResolver == 0)) {
4487 fprintf(stderr, "File %s leaked %d bytes\n",
4488 globbuf.gl_pathv[i], xmlMemUsed() - mem);
4489 nb_leaks++;
4490 err++;
4491 }
4492 }
4493 testErrorsSize = 0;
4494 }
4495 if (result)
4496 free(result);
4497 if (error)
4498 free(error);
4499 }
4500 globfree(&globbuf);
4501 } else {
4502 testErrorsSize = 0;
4503 testErrors[0] = 0;
4504 extraMemoryFromResolver = 0;
4505 res = tst->func(NULL, NULL, NULL, tst->options);
4506 if (res != 0) {
4507 nb_errors++;
4508 err++;
4509 }
4510 }
Nick Wellnhofer4b413592017-10-31 17:17:16 +01004511
4512 xmlCharEncCloseFunc(ebcdicHandler);
Elliott Hughes7fbecab2019-01-10 16:42:03 -08004513 xmlCharEncCloseFunc(eucJpHandler);
Nick Wellnhofer4b413592017-10-31 17:17:16 +01004514
William M. Brackca15a542005-07-06 20:41:33 +00004515 return(err);
4516}
4517
Daniel Veillarddb68b742005-07-30 13:18:24 +00004518static int verbose = 0;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004519static int tests_quiet = 0;
Daniel Veillarddb68b742005-07-30 13:18:24 +00004520
4521static int
4522runtest(int i) {
4523 int ret = 0, res;
4524 int old_errors, old_tests, old_leaks;
4525
4526 old_errors = nb_errors;
4527 old_tests = nb_tests;
4528 old_leaks = nb_leaks;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004529 if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
Daniel Veillarddb68b742005-07-30 13:18:24 +00004530 printf("## %s\n", testDescriptions[i].desc);
4531 res = launchTests(&testDescriptions[i]);
4532 if (res != 0)
4533 ret++;
4534 if (verbose) {
4535 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
4536 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
4537 else
4538 printf("Ran %d tests, %d errors, %d leaks\n",
4539 nb_tests - old_tests,
4540 nb_errors - old_errors,
4541 nb_leaks - old_leaks);
4542 }
4543 return(ret);
4544}
4545
William M. Brackca15a542005-07-06 20:41:33 +00004546int
4547main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
Daniel Veillarddb68b742005-07-30 13:18:24 +00004548 int i, a, ret = 0;
4549 int subset = 0;
William M. Brackca15a542005-07-06 20:41:33 +00004550
Nick Wellnhofer82e03942017-10-09 02:05:41 +02004551#if defined(_WIN32) && !defined(__CYGWIN__)
4552 setvbuf(stdout, NULL, _IONBF, 0);
4553 setvbuf(stderr, NULL, _IONBF, 0);
4554#endif
4555
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004556#if defined(_MSC_VER) && _MSC_VER >= 1400 && _MSC_VER < 1900
4557 _set_output_format(_TWO_DIGIT_EXPONENT);
4558#endif
4559
William M. Brackca15a542005-07-06 20:41:33 +00004560 initializeLibxml2();
4561
Daniel Veillarddb68b742005-07-30 13:18:24 +00004562 for (a = 1; a < argc;a++) {
4563 if (!strcmp(argv[a], "-v"))
4564 verbose = 1;
David Kilzer5c373822016-05-22 09:58:30 +08004565 else if (!strcmp(argv[a], "-u"))
4566 update_results = 1;
Daniel Veillard336a8e12005-08-07 10:46:19 +00004567 else if (!strcmp(argv[a], "-quiet"))
4568 tests_quiet = 1;
Haibo Huangcfd91dc2020-07-30 23:01:33 -07004569 else if (!strcmp(argv[a], "--out"))
4570 temp_directory = argv[++a];
Daniel Veillarddb68b742005-07-30 13:18:24 +00004571 else {
4572 for (i = 0; testDescriptions[i].func != NULL; i++) {
4573 if (strstr(testDescriptions[i].desc, argv[a])) {
4574 ret += runtest(i);
4575 subset++;
4576 }
4577 }
4578 }
4579 }
4580 if (subset == 0) {
4581 for (i = 0; testDescriptions[i].func != NULL; i++) {
4582 ret += runtest(i);
William M. Brackca15a542005-07-06 20:41:33 +00004583 }
4584 }
4585 if ((nb_errors == 0) && (nb_leaks == 0)) {
4586 ret = 0;
4587 printf("Total %d tests, no errors\n",
4588 nb_tests);
4589 } else {
4590 ret = 1;
4591 printf("Total %d tests, %d errors, %d leaks\n",
4592 nb_tests, nb_errors, nb_leaks);
4593 }
4594 xmlCleanupParser();
4595 xmlMemoryDump();
4596
4597 return(ret);
4598}
4599
4600#else /* ! LIBXML_OUTPUT_ENABLED */
4601int
4602main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
4603 fprintf(stderr, "runtest requires output to be enabled in libxml2\n");
4604 return(1);
4605}
4606#endif