1 /*
2 * runtest.c: C program to run libxml2 regression tests without
3 * requiring make or Python, and reducing platform dependencies
4 * to a strict minimum.
5 *
6 * To compile on Unixes:
7 * cc -o runtest `xml2-config --cflags` runtest.c `xml2-config --libs` -lpthread
8 *
9 * See Copyright for the status of this software.
10 *
11 * daniel@veillard.com
12 */
13
14 #define XML_DEPRECATED
15 #define XML_DEPRECATED_MEMBER
16
17 #include "libxml.h"
18 #include <stdio.h>
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #elif defined (_WIN32)
22 #include <io.h>
23 #endif
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28
29 #include <libxml/parser.h>
30 #include <libxml/parserInternals.h>
31 #include <libxml/tree.h>
32 #include <libxml/uri.h>
33 #include <libxml/encoding.h>
34
35 #ifdef LIBXML_OUTPUT_ENABLED
36 #ifdef LIBXML_READER_ENABLED
37 #include <libxml/xmlreader.h>
38 #endif
39
40 #ifdef LIBXML_XINCLUDE_ENABLED
41 #include <libxml/xinclude.h>
42 #endif
43
44 #ifdef LIBXML_XPATH_ENABLED
45 #include <libxml/xpath.h>
46 #include <libxml/xpathInternals.h>
47 #ifdef LIBXML_XPTR_ENABLED
48 #include <libxml/xpointer.h>
49 #endif
50 #endif
51
52 #ifdef LIBXML_SCHEMAS_ENABLED
53 #include <libxml/relaxng.h>
54 #include <libxml/xmlschemas.h>
55 #include <libxml/xmlschemastypes.h>
56 #endif
57
58 #ifdef LIBXML_PATTERN_ENABLED
59 #include <libxml/pattern.h>
60 #endif
61
62 #ifdef LIBXML_C14N_ENABLED
63 #include <libxml/c14n.h>
64 #endif
65
66 #ifdef LIBXML_HTML_ENABLED
67 #include <libxml/HTMLparser.h>
68 #include <libxml/HTMLtree.h>
69 #endif
70
71 #if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
72 #include <libxml/threads.h>
73 #include <libxml/parser.h>
74 #include <libxml/catalog.h>
75 #endif
76
77 /*
78 * pseudo flag for the unification of HTML and XML tests
79 */
80 #define XML_PARSE_HTML 1 << 24
81
82 /*
83 * O_BINARY is just for Windows compatibility - if it isn't defined
84 * on this system, avoid any compilation error
85 */
86 #ifdef O_BINARY
87 #define RD_FLAGS O_RDONLY | O_BINARY
88 #define WR_FLAGS O_WRONLY | O_CREAT | O_TRUNC | O_BINARY
89 #else
90 #define RD_FLAGS O_RDONLY
91 #define WR_FLAGS O_WRONLY | O_CREAT | O_TRUNC
92 #endif
93
94 typedef int (*functest) (const char *filename, const char *result,
95 const char *error, int options);
96
97 typedef struct testDesc testDesc;
98 typedef testDesc *testDescPtr;
99 struct testDesc {
100 const char *desc; /* description of the test */
101 functest func; /* function implementing the test */
102 const char *in; /* glob to path for input files */
103 const char *out; /* output directory */
104 const char *suffix;/* suffix for output files */
105 const char *err; /* suffix for error output files */
106 int options; /* parser options for the test */
107 };
108
109 static int update_results = 0;
110 static char* temp_directory = NULL;
111 static int checkTestFile(const char *filename);
112
113 #if defined(_WIN32)
114
115 #include <windows.h>
116
117 typedef struct
118 {
119 size_t gl_pathc; /* Count of paths matched so far */
120 char **gl_pathv; /* List of matched pathnames. */
121 size_t gl_offs; /* Slots to reserve in 'gl_pathv'. */
122 } glob_t;
123
124 #define GLOB_DOOFFS 0
glob(const char * pattern,ATTRIBUTE_UNUSED int flags,ATTRIBUTE_UNUSED int errfunc (const char * epath,int eerrno),glob_t * pglob)125 static int glob(const char *pattern, ATTRIBUTE_UNUSED int flags,
126 ATTRIBUTE_UNUSED int errfunc(const char *epath, int eerrno),
127 glob_t *pglob) {
128 glob_t *ret;
129 WIN32_FIND_DATA FindFileData;
130 HANDLE hFind;
131 unsigned int nb_paths = 0;
132 char directory[500];
133 int len;
134
135 if ((pattern == NULL) || (pglob == NULL)) return(-1);
136
137 strncpy(directory, pattern, 499);
138 for (len = strlen(directory);len >= 0;len--) {
139 if (directory[len] == '/') {
140 len++;
141 directory[len] = 0;
142 break;
143 }
144 }
145 if (len <= 0)
146 len = 0;
147
148
149 ret = pglob;
150 memset(ret, 0, sizeof(glob_t));
151
152 hFind = FindFirstFileA(pattern, &FindFileData);
153 if (hFind == INVALID_HANDLE_VALUE)
154 return(0);
155 nb_paths = 20;
156 ret->gl_pathv = (char **) malloc(nb_paths * sizeof(char *));
157 if (ret->gl_pathv == NULL) {
158 FindClose(hFind);
159 return(-1);
160 }
161 strncpy(directory + len, FindFileData.cFileName, 499 - len);
162 ret->gl_pathv[ret->gl_pathc] = strdup(directory);
163 if (ret->gl_pathv[ret->gl_pathc] == NULL)
164 goto done;
165 ret->gl_pathc++;
166 while(FindNextFileA(hFind, &FindFileData)) {
167 if (FindFileData.cFileName[0] == '.')
168 continue;
169 if (ret->gl_pathc + 2 > nb_paths) {
170 char **tmp = realloc(ret->gl_pathv, nb_paths * 2 * sizeof(char *));
171 if (tmp == NULL)
172 break;
173 ret->gl_pathv = tmp;
174 nb_paths *= 2;
175 }
176 strncpy(directory + len, FindFileData.cFileName, 499 - len);
177 ret->gl_pathv[ret->gl_pathc] = strdup(directory);
178 if (ret->gl_pathv[ret->gl_pathc] == NULL)
179 break;
180 ret->gl_pathc++;
181 }
182 ret->gl_pathv[ret->gl_pathc] = NULL;
183
184 done:
185 FindClose(hFind);
186 return(0);
187 }
188
189
190
globfree(glob_t * pglob)191 static void globfree(glob_t *pglob) {
192 unsigned int i;
193 if (pglob == NULL)
194 return;
195
196 for (i = 0;i < pglob->gl_pathc;i++) {
197 if (pglob->gl_pathv[i] != NULL)
198 free(pglob->gl_pathv[i]);
199 }
200 }
201
202 #else
203 #include <glob.h>
204 #endif
205
206 /************************************************************************
207 * *
208 * Libxml2 specific routines *
209 * *
210 ************************************************************************/
211
212 static int nb_tests = 0;
213 static int nb_errors = 0;
214 static int nb_leaks = 0;
215
216 static int
fatalError(void)217 fatalError(void) {
218 fprintf(stderr, "Exitting tests on fatal error\n");
219 exit(1);
220 }
221
222 /*
223 * Trapping the error messages at the generic level to grab the equivalent of
224 * stderr messages on CLI tools.
225 */
226 static char testErrors[32769];
227 static int testErrorsSize = 0;
228
229 static void
testErrorHandler(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)230 testErrorHandler(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
231 va_list args;
232 int res;
233
234 if (testErrorsSize >= 32768)
235 return;
236 va_start(args, msg);
237 res = vsnprintf(&testErrors[testErrorsSize],
238 32768 - testErrorsSize,
239 msg, args);
240 va_end(args);
241 if (testErrorsSize + res >= 32768) {
242 /* buffer is full */
243 testErrorsSize = 32768;
244 testErrors[testErrorsSize] = 0;
245 } else {
246 testErrorsSize += res;
247 }
248 testErrors[testErrorsSize] = 0;
249 }
250
251 static void
testStructuredErrorHandler(void * ctx ATTRIBUTE_UNUSED,const xmlError * err)252 testStructuredErrorHandler(void *ctx ATTRIBUTE_UNUSED, const xmlError *err) {
253 xmlFormatError(err, testErrorHandler, NULL);
254 }
255
256 static void
initializeLibxml2(void)257 initializeLibxml2(void) {
258 /*
259 * This verifies that xmlInitParser doesn't allocate memory with
260 * xmlMalloc
261 */
262 xmlFree = NULL;
263 xmlMalloc = NULL;
264 xmlRealloc = NULL;
265 xmlMemStrdup = NULL;
266 xmlInitParser();
267 xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
268 #ifdef LIBXML_CATALOG_ENABLED
269 #ifdef _WIN32
270 putenv("XML_CATALOG_FILES=");
271 #else
272 setenv("XML_CATALOG_FILES", "", 1);
273 #endif
274 xmlInitializeCatalog();
275 xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE);
276 #endif
277 #ifdef LIBXML_SCHEMAS_ENABLED
278 xmlSchemaInitTypes();
279 xmlRelaxNGInitTypes();
280 #endif
281 }
282
283
284 /************************************************************************
285 * *
286 * File name and path utilities *
287 * *
288 ************************************************************************/
289
baseFilename(const char * filename)290 static const char *baseFilename(const char *filename) {
291 const char *cur;
292 if (filename == NULL)
293 return(NULL);
294 cur = &filename[strlen(filename)];
295 while ((cur > filename) && (*cur != '/'))
296 cur--;
297 if (*cur == '/')
298 return(cur + 1);
299 return(cur);
300 }
301
resultFilename(const char * filename,const char * out,const char * suffix)302 static char *resultFilename(const char *filename, const char *out,
303 const char *suffix) {
304 const char *base;
305 char res[500];
306 char suffixbuff[500];
307
308 /*************
309 if ((filename[0] == 't') && (filename[1] == 'e') &&
310 (filename[2] == 's') && (filename[3] == 't') &&
311 (filename[4] == '/'))
312 filename = &filename[5];
313 *************/
314
315 base = baseFilename(filename);
316 if (suffix == NULL)
317 suffix = ".tmp";
318 if (out == NULL)
319 out = "";
320
321 strncpy(suffixbuff,suffix,499);
322
323 if (snprintf(res, 499, "%s%s%s", out, base, suffixbuff) >= 499)
324 res[499] = 0;
325 return(strdup(res));
326 }
327
checkTestFile(const char * filename)328 static int checkTestFile(const char *filename) {
329 struct stat buf;
330
331 if (stat(filename, &buf) == -1)
332 return(0);
333
334 #if defined(_WIN32)
335 if (!(buf.st_mode & _S_IFREG))
336 return(0);
337 #else
338 if (!S_ISREG(buf.st_mode))
339 return(0);
340 #endif
341
342 return(1);
343 }
344
compareFiles(const char * r1,const char * r2)345 static int compareFiles(const char *r1 /* temp */, const char *r2 /* result */) {
346 int res1, res2, total;
347 int fd1, fd2;
348 char bytes1[4096];
349 char bytes2[4096];
350
351 if (update_results) {
352 fd1 = open(r1, RD_FLAGS);
353 if (fd1 < 0)
354 return(-1);
355 fd2 = open(r2, WR_FLAGS, 0644);
356 if (fd2 < 0) {
357 close(fd1);
358 return(-1);
359 }
360 total = 0;
361 do {
362 res1 = read(fd1, bytes1, 4096);
363 if (res1 <= 0)
364 break;
365 total += res1;
366 res2 = write(fd2, bytes1, res1);
367 if (res2 <= 0 || res2 != res1)
368 break;
369 } while (1);
370 close(fd2);
371 close(fd1);
372 if (total == 0)
373 unlink(r2);
374 return(res1 != 0);
375 }
376
377 fd1 = open(r1, RD_FLAGS);
378 if (fd1 < 0)
379 return(-1);
380 fd2 = open(r2, RD_FLAGS);
381 while (1) {
382 res1 = read(fd1, bytes1, 4096);
383 res2 = fd2 >= 0 ? read(fd2, bytes2, 4096) : 0;
384 if ((res1 != res2) || (res1 < 0)) {
385 close(fd1);
386 if (fd2 >= 0)
387 close(fd2);
388 return(1);
389 }
390 if (res1 == 0)
391 break;
392 if (memcmp(bytes1, bytes2, res1) != 0) {
393 close(fd1);
394 if (fd2 >= 0)
395 close(fd2);
396 return(1);
397 }
398 }
399 close(fd1);
400 if (fd2 >= 0)
401 close(fd2);
402 return(0);
403 }
404
compareFileMem(const char * filename,const char * mem,int size)405 static int compareFileMem(const char *filename, const char *mem, int size) {
406 int res;
407 int fd;
408 char bytes[4096];
409 int idx = 0;
410 struct stat info;
411
412 if (update_results) {
413 if (size == 0) {
414 unlink(filename);
415 return(0);
416 }
417 fd = open(filename, WR_FLAGS, 0644);
418 if (fd < 0) {
419 fprintf(stderr, "failed to open %s for writing", filename);
420 return(-1);
421 }
422 res = write(fd, mem, size);
423 close(fd);
424 return(res != size);
425 }
426
427 if (stat(filename, &info) < 0) {
428 if (size == 0)
429 return(0);
430 fprintf(stderr, "failed to stat %s\n", filename);
431 return(-1);
432 }
433 if (info.st_size != size) {
434 fprintf(stderr, "file %s is %ld bytes, result is %d bytes\n",
435 filename, (long) info.st_size, size);
436 return(-1);
437 }
438 fd = open(filename, RD_FLAGS);
439 if (fd < 0) {
440 fprintf(stderr, "failed to open %s for reading", filename);
441 return(-1);
442 }
443 while (idx < size) {
444 res = read(fd, bytes, 4096);
445 if (res <= 0)
446 break;
447 if (res + idx > size)
448 break;
449 if (memcmp(bytes, &mem[idx], res) != 0) {
450 int ix;
451 for (ix=0; ix<res; ix++)
452 if (bytes[ix] != mem[idx+ix])
453 break;
454 fprintf(stderr,"Compare error at position %d\n", idx+ix);
455 close(fd);
456 return(1);
457 }
458 idx += res;
459 }
460 close(fd);
461 if (idx != size) {
462 fprintf(stderr,"Compare error index %d, size %d\n", idx, size);
463 }
464 return(idx != size);
465 }
466
loadMem(const char * filename,const char ** mem,int * size)467 static int loadMem(const char *filename, const char **mem, int *size) {
468 int fd, res;
469 struct stat info;
470 char *base;
471 int siz = 0;
472 if (stat(filename, &info) < 0)
473 return(-1);
474 base = malloc(info.st_size + 1);
475 if (base == NULL)
476 return(-1);
477 if ((fd = open(filename, RD_FLAGS)) < 0) {
478 free(base);
479 return(-1);
480 }
481 while ((res = read(fd, &base[siz], info.st_size - siz)) > 0) {
482 siz += res;
483 }
484 close(fd);
485 #if !defined(_WIN32)
486 if (siz != info.st_size) {
487 free(base);
488 return(-1);
489 }
490 #endif
491 base[siz] = 0;
492 *mem = base;
493 *size = siz;
494 return(0);
495 }
496
unloadMem(const char * mem)497 static int unloadMem(const char *mem) {
498 free((char *)mem);
499 return(0);
500 }
501
502 /************************************************************************
503 * *
504 * Tests implementations *
505 * *
506 ************************************************************************/
507
508 /************************************************************************
509 * *
510 * Parse to SAX based tests *
511 * *
512 ************************************************************************/
513
514 static FILE *SAXdebug = NULL;
515
516 /*
517 * empty SAX block
518 */
519 static xmlSAXHandler emptySAXHandlerStruct = {
520 NULL, /* internalSubset */
521 NULL, /* isStandalone */
522 NULL, /* hasInternalSubset */
523 NULL, /* hasExternalSubset */
524 NULL, /* resolveEntity */
525 NULL, /* getEntity */
526 NULL, /* entityDecl */
527 NULL, /* notationDecl */
528 NULL, /* attributeDecl */
529 NULL, /* elementDecl */
530 NULL, /* unparsedEntityDecl */
531 NULL, /* setDocumentLocator */
532 NULL, /* startDocument */
533 NULL, /* endDocument */
534 NULL, /* startElement */
535 NULL, /* endElement */
536 NULL, /* reference */
537 NULL, /* characters */
538 NULL, /* ignorableWhitespace */
539 NULL, /* processingInstruction */
540 NULL, /* comment */
541 NULL, /* xmlParserWarning */
542 NULL, /* xmlParserError */
543 NULL, /* xmlParserError */
544 NULL, /* getParameterEntity */
545 NULL, /* cdataBlock; */
546 NULL, /* externalSubset; */
547 1,
548 NULL,
549 NULL, /* startElementNs */
550 NULL, /* endElementNs */
551 NULL /* xmlStructuredErrorFunc */
552 };
553
554 typedef struct {
555 const char *filename;
556 xmlHashTablePtr generalEntities;
557 xmlHashTablePtr parameterEntities;
558 } debugContext;
559
560 static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct;
561 static int callbacks = 0;
562 static int quiet = 0;
563
564 /**
565 * isStandaloneDebug:
566 * @ctxt: An XML parser context
567 *
568 * Is this document tagged standalone ?
569 *
570 * Returns 1 if true
571 */
572 static int
isStandaloneDebug(void * ctx ATTRIBUTE_UNUSED)573 isStandaloneDebug(void *ctx ATTRIBUTE_UNUSED)
574 {
575 callbacks++;
576 if (quiet)
577 return(0);
578 fprintf(SAXdebug, "SAX.isStandalone()\n");
579 return(0);
580 }
581
582 /**
583 * hasInternalSubsetDebug:
584 * @ctxt: An XML parser context
585 *
586 * Does this document has an internal subset
587 *
588 * Returns 1 if true
589 */
590 static int
hasInternalSubsetDebug(void * ctx ATTRIBUTE_UNUSED)591 hasInternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
592 {
593 callbacks++;
594 if (quiet)
595 return(0);
596 fprintf(SAXdebug, "SAX.hasInternalSubset()\n");
597 return(0);
598 }
599
600 /**
601 * hasExternalSubsetDebug:
602 * @ctxt: An XML parser context
603 *
604 * Does this document has an external subset
605 *
606 * Returns 1 if true
607 */
608 static int
hasExternalSubsetDebug(void * ctx ATTRIBUTE_UNUSED)609 hasExternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
610 {
611 callbacks++;
612 if (quiet)
613 return(0);
614 fprintf(SAXdebug, "SAX.hasExternalSubset()\n");
615 return(0);
616 }
617
618 /**
619 * internalSubsetDebug:
620 * @ctxt: An XML parser context
621 *
622 * Does this document has an internal subset
623 */
624 static void
internalSubsetDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar * ExternalID,const xmlChar * SystemID)625 internalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
626 const xmlChar *ExternalID, const xmlChar *SystemID)
627 {
628 callbacks++;
629 if (quiet)
630 return;
631 if (name == NULL)
632 name = BAD_CAST "(null)";
633 fprintf(SAXdebug, "SAX.internalSubset(%s,", name);
634 if (ExternalID == NULL)
635 fprintf(SAXdebug, " ,");
636 else
637 fprintf(SAXdebug, " %s,", ExternalID);
638 if (SystemID == NULL)
639 fprintf(SAXdebug, " )\n");
640 else
641 fprintf(SAXdebug, " %s)\n", SystemID);
642 }
643
644 /**
645 * externalSubsetDebug:
646 * @ctxt: An XML parser context
647 *
648 * Does this document has an external subset
649 */
650 static void
externalSubsetDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar * ExternalID,const xmlChar * SystemID)651 externalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
652 const xmlChar *ExternalID, const xmlChar *SystemID)
653 {
654 callbacks++;
655 if (quiet)
656 return;
657 fprintf(SAXdebug, "SAX.externalSubset(%s,", name);
658 if (ExternalID == NULL)
659 fprintf(SAXdebug, " ,");
660 else
661 fprintf(SAXdebug, " %s,", ExternalID);
662 if (SystemID == NULL)
663 fprintf(SAXdebug, " )\n");
664 else
665 fprintf(SAXdebug, " %s)\n", SystemID);
666 }
667
668 /**
669 * resolveEntityDebug:
670 * @ctxt: An XML parser context
671 * @publicId: The public ID of the entity
672 * @systemId: The system ID of the entity
673 *
674 * Special entity resolver, better left to the parser, it has
675 * more context than the application layer.
676 * The default behaviour is to NOT resolve the entities, in that case
677 * the ENTITY_REF nodes are built in the structure (and the parameter
678 * values).
679 *
680 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
681 */
682 static xmlParserInputPtr
resolveEntityDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * publicId,const xmlChar * systemId)683 resolveEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *publicId, const xmlChar *systemId)
684 {
685 callbacks++;
686 if (quiet)
687 return(NULL);
688 /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
689
690
691 fprintf(SAXdebug, "SAX.resolveEntity(");
692 if (publicId != NULL)
693 fprintf(SAXdebug, "%s", (char *)publicId);
694 else
695 fprintf(SAXdebug, " ");
696 if (systemId != NULL)
697 fprintf(SAXdebug, ", %s)\n", (char *)systemId);
698 else
699 fprintf(SAXdebug, ", )\n");
700 /*********
701 if (systemId != NULL) {
702 return(xmlNewInputFromFile(ctxt, (char *) systemId));
703 }
704 *********/
705 return(NULL);
706 }
707
708 /**
709 * getEntityDebug:
710 * @ctxt: An XML parser context
711 * @name: The entity name
712 *
713 * Get an entity by name
714 *
715 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
716 */
717 static xmlEntityPtr
getEntityDebug(void * ctx,const xmlChar * name)718 getEntityDebug(void *ctx, const xmlChar *name)
719 {
720 debugContext *ctxt = ctx;
721
722 callbacks++;
723 if (quiet)
724 return(NULL);
725 fprintf(SAXdebug, "SAX.getEntity(%s)\n", name);
726
727 return(xmlHashLookup(ctxt->generalEntities, name));
728 }
729
730 /**
731 * getParameterEntityDebug:
732 * @ctxt: An XML parser context
733 * @name: The entity name
734 *
735 * Get a parameter entity by name
736 *
737 * Returns the xmlParserInputPtr
738 */
739 static xmlEntityPtr
getParameterEntityDebug(void * ctx,const xmlChar * name)740 getParameterEntityDebug(void *ctx, const xmlChar *name)
741 {
742 debugContext *ctxt = ctx;
743
744 callbacks++;
745 if (quiet)
746 return(NULL);
747 fprintf(SAXdebug, "SAX.getParameterEntity(%s)\n", name);
748
749 return(xmlHashLookup(ctxt->parameterEntities, name));
750 }
751
752
753 /**
754 * entityDeclDebug:
755 * @ctxt: An XML parser context
756 * @name: the entity name
757 * @type: the entity type
758 * @publicId: The public ID of the entity
759 * @systemId: The system ID of the entity
760 * @content: the entity value (without processing).
761 *
762 * An entity definition has been parsed
763 */
764 static void
entityDeclDebug(void * ctx,const xmlChar * name,int type,const xmlChar * publicId,const xmlChar * systemId,xmlChar * content)765 entityDeclDebug(void *ctx, const xmlChar *name, int type,
766 const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
767 {
768 debugContext *ctxt = ctx;
769 xmlEntityPtr ent;
770 const xmlChar *nullstr = BAD_CAST "(null)";
771
772 ent = xmlNewEntity(NULL, name, type, publicId, systemId, content);
773 if (systemId != NULL)
774 ent->URI = xmlBuildURI(systemId, (const xmlChar *) ctxt->filename);
775
776 if ((type == XML_INTERNAL_PARAMETER_ENTITY) ||
777 (type == XML_EXTERNAL_PARAMETER_ENTITY))
778 xmlHashAddEntry(ctxt->parameterEntities, name, ent);
779 else
780 xmlHashAddEntry(ctxt->generalEntities, name, ent);
781
782 /* not all libraries handle printing null pointers nicely */
783 if (publicId == NULL)
784 publicId = nullstr;
785 if (systemId == NULL)
786 systemId = nullstr;
787 if (content == NULL)
788 content = (xmlChar *)nullstr;
789 callbacks++;
790 if (quiet)
791 return;
792 fprintf(SAXdebug, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
793 name, type, publicId, systemId, content);
794 }
795
796 /**
797 * attributeDeclDebug:
798 * @ctxt: An XML parser context
799 * @name: the attribute name
800 * @type: the attribute type
801 *
802 * An attribute definition has been parsed
803 */
804 static void
attributeDeclDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * elem,const xmlChar * name,int type,int def,const xmlChar * defaultValue,xmlEnumerationPtr tree)805 attributeDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar * elem,
806 const xmlChar * name, int type, int def,
807 const xmlChar * defaultValue, xmlEnumerationPtr tree)
808 {
809 callbacks++;
810 if (quiet)
811 return;
812 if (defaultValue == NULL)
813 fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, NULL, ...)\n",
814 elem, name, type, def);
815 else
816 fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
817 elem, name, type, def, defaultValue);
818 xmlFreeEnumeration(tree);
819 }
820
821 /**
822 * elementDeclDebug:
823 * @ctxt: An XML parser context
824 * @name: the element name
825 * @type: the element type
826 * @content: the element value (without processing).
827 *
828 * An element definition has been parsed
829 */
830 static void
elementDeclDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,int type,xmlElementContentPtr content ATTRIBUTE_UNUSED)831 elementDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
832 xmlElementContentPtr content ATTRIBUTE_UNUSED)
833 {
834 callbacks++;
835 if (quiet)
836 return;
837 fprintf(SAXdebug, "SAX.elementDecl(%s, %d, ...)\n",
838 name, type);
839 }
840
841 /**
842 * notationDeclDebug:
843 * @ctxt: An XML parser context
844 * @name: The name of the notation
845 * @publicId: The public ID of the entity
846 * @systemId: The system ID of the entity
847 *
848 * What to do when a notation declaration has been parsed.
849 */
850 static void
notationDeclDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar * publicId,const xmlChar * systemId)851 notationDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
852 const xmlChar *publicId, const xmlChar *systemId)
853 {
854 callbacks++;
855 if (quiet)
856 return;
857 fprintf(SAXdebug, "SAX.notationDecl(%s, %s, %s)\n",
858 (char *) name, (char *) publicId, (char *) systemId);
859 }
860
861 /**
862 * unparsedEntityDeclDebug:
863 * @ctxt: An XML parser context
864 * @name: The name of the entity
865 * @publicId: The public ID of the entity
866 * @systemId: The system ID of the entity
867 * @notationName: the name of the notation
868 *
869 * What to do when an unparsed entity declaration is parsed
870 */
871 static void
unparsedEntityDeclDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar * publicId,const xmlChar * systemId,const xmlChar * notationName)872 unparsedEntityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
873 const xmlChar *publicId, const xmlChar *systemId,
874 const xmlChar *notationName)
875 {
876 const xmlChar *nullstr = BAD_CAST "(null)";
877
878 if (publicId == NULL)
879 publicId = nullstr;
880 if (systemId == NULL)
881 systemId = nullstr;
882 if (notationName == NULL)
883 notationName = nullstr;
884 callbacks++;
885 if (quiet)
886 return;
887 fprintf(SAXdebug, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
888 (char *) name, (char *) publicId, (char *) systemId,
889 (char *) notationName);
890 }
891
892 /**
893 * setDocumentLocatorDebug:
894 * @ctxt: An XML parser context
895 * @loc: A SAX Locator
896 *
897 * Receive the document locator at startup, actually xmlDefaultSAXLocator
898 * Everything is available on the context, so this is useless in our case.
899 */
900 static void
setDocumentLocatorDebug(void * ctx ATTRIBUTE_UNUSED,xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)901 setDocumentLocatorDebug(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
902 {
903 callbacks++;
904 if (quiet)
905 return;
906 fprintf(SAXdebug, "SAX.setDocumentLocator()\n");
907 }
908
909 /**
910 * startDocumentDebug:
911 * @ctxt: An XML parser context
912 *
913 * called when the document start being processed.
914 */
915 static void
startDocumentDebug(void * ctx ATTRIBUTE_UNUSED)916 startDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
917 {
918 callbacks++;
919 if (quiet)
920 return;
921 fprintf(SAXdebug, "SAX.startDocument()\n");
922 }
923
924 /**
925 * endDocumentDebug:
926 * @ctxt: An XML parser context
927 *
928 * called when the document end has been detected.
929 */
930 static void
endDocumentDebug(void * ctx ATTRIBUTE_UNUSED)931 endDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
932 {
933 callbacks++;
934 if (quiet)
935 return;
936 fprintf(SAXdebug, "SAX.endDocument()\n");
937 }
938
939 /**
940 * startElementDebug:
941 * @ctxt: An XML parser context
942 * @name: The element name
943 *
944 * called when an opening tag has been processed.
945 */
946 static void
startElementDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar ** atts)947 startElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
948 {
949 int i;
950
951 callbacks++;
952 if (quiet)
953 return;
954 fprintf(SAXdebug, "SAX.startElement(%s", (char *) name);
955 if (atts != NULL) {
956 for (i = 0;(atts[i] != NULL);i++) {
957 fprintf(SAXdebug, ", %s='", atts[i++]);
958 if (atts[i] != NULL)
959 fprintf(SAXdebug, "%s'", atts[i]);
960 }
961 }
962 fprintf(SAXdebug, ")\n");
963 }
964
965 /**
966 * endElementDebug:
967 * @ctxt: An XML parser context
968 * @name: The element name
969 *
970 * called when the end of an element has been detected.
971 */
972 static void
endElementDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name)973 endElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
974 {
975 callbacks++;
976 if (quiet)
977 return;
978 fprintf(SAXdebug, "SAX.endElement(%s)\n", (char *) name);
979 }
980
981 /**
982 * charactersDebug:
983 * @ctxt: An XML parser context
984 * @ch: a xmlChar string
985 * @len: the number of xmlChar
986 *
987 * receiving some chars from the parser.
988 * Question: how much at a time ???
989 */
990 static void
charactersDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * ch,int len)991 charactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
992 {
993 char output[40];
994 int i;
995
996 callbacks++;
997 if (quiet)
998 return;
999 for (i = 0;(i<len) && (i < 30);i++)
1000 output[i] = (char) ch[i];
1001 output[i] = 0;
1002
1003 fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len);
1004 }
1005
1006 /**
1007 * referenceDebug:
1008 * @ctxt: An XML parser context
1009 * @name: The entity name
1010 *
1011 * called when an entity reference is detected.
1012 */
1013 static void
referenceDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name)1014 referenceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
1015 {
1016 callbacks++;
1017 if (quiet)
1018 return;
1019 fprintf(SAXdebug, "SAX.reference(%s)\n", name);
1020 }
1021
1022 /**
1023 * ignorableWhitespaceDebug:
1024 * @ctxt: An XML parser context
1025 * @ch: a xmlChar string
1026 * @start: the first char in the string
1027 * @len: the number of xmlChar
1028 *
1029 * receiving some ignorable whitespaces from the parser.
1030 * Question: how much at a time ???
1031 */
1032 static void
ignorableWhitespaceDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * ch,int len)1033 ignorableWhitespaceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1034 {
1035 char output[40];
1036 int i;
1037
1038 callbacks++;
1039 if (quiet)
1040 return;
1041 for (i = 0;(i<len) && (i < 30);i++)
1042 output[i] = (char) ch[i];
1043 output[i] = 0;
1044 fprintf(SAXdebug, "SAX.ignorableWhitespace(%s, %d)\n", output, len);
1045 }
1046
1047 /**
1048 * processingInstructionDebug:
1049 * @ctxt: An XML parser context
1050 * @target: the target name
1051 * @data: the PI data's
1052 * @len: the number of xmlChar
1053 *
1054 * A processing instruction has been parsed.
1055 */
1056 static void
processingInstructionDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * target,const xmlChar * data)1057 processingInstructionDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *target,
1058 const xmlChar *data)
1059 {
1060 callbacks++;
1061 if (quiet)
1062 return;
1063 if (data != NULL)
1064 fprintf(SAXdebug, "SAX.processingInstruction(%s, %s)\n",
1065 (char *) target, (char *) data);
1066 else
1067 fprintf(SAXdebug, "SAX.processingInstruction(%s, NULL)\n",
1068 (char *) target);
1069 }
1070
1071 /**
1072 * cdataBlockDebug:
1073 * @ctx: the user data (XML parser context)
1074 * @value: The pcdata content
1075 * @len: the block length
1076 *
1077 * called when a pcdata block has been parsed
1078 */
1079 static void
cdataBlockDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * value,int len)1080 cdataBlockDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value, int len)
1081 {
1082 callbacks++;
1083 if (quiet)
1084 return;
1085 fprintf(SAXdebug, "SAX.pcdata(%.20s, %d)\n",
1086 (char *) value, len);
1087 }
1088
1089 /**
1090 * commentDebug:
1091 * @ctxt: An XML parser context
1092 * @value: the comment content
1093 *
1094 * A comment has been parsed.
1095 */
1096 static void
commentDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * value)1097 commentDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value)
1098 {
1099 callbacks++;
1100 if (quiet)
1101 return;
1102 fprintf(SAXdebug, "SAX.comment(%s)\n", value);
1103 }
1104
1105 /**
1106 * warningDebug:
1107 * @ctxt: An XML parser context
1108 * @msg: the message to display/transmit
1109 * @...: extra parameters for the message display
1110 *
1111 * Display and format a warning messages, gives file, line, position and
1112 * extra parameters.
1113 */
1114 static void
warningDebug(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)1115 warningDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1116 {
1117 va_list args;
1118
1119 callbacks++;
1120 if (quiet)
1121 return;
1122 va_start(args, msg);
1123 fprintf(SAXdebug, "SAX.warning: ");
1124 vfprintf(SAXdebug, msg, args);
1125 va_end(args);
1126 }
1127
1128 /**
1129 * errorDebug:
1130 * @ctxt: An XML parser context
1131 * @msg: the message to display/transmit
1132 * @...: extra parameters for the message display
1133 *
1134 * Display and format a error messages, gives file, line, position and
1135 * extra parameters.
1136 */
1137 static void
errorDebug(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)1138 errorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1139 {
1140 va_list args;
1141
1142 callbacks++;
1143 if (quiet)
1144 return;
1145 va_start(args, msg);
1146 fprintf(SAXdebug, "SAX.error: ");
1147 vfprintf(SAXdebug, msg, args);
1148 va_end(args);
1149 }
1150
1151 /**
1152 * fatalErrorDebug:
1153 * @ctxt: An XML parser context
1154 * @msg: the message to display/transmit
1155 * @...: extra parameters for the message display
1156 *
1157 * Display and format a fatalError messages, gives file, line, position and
1158 * extra parameters.
1159 */
1160 static void
fatalErrorDebug(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)1161 fatalErrorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1162 {
1163 va_list args;
1164
1165 callbacks++;
1166 if (quiet)
1167 return;
1168 va_start(args, msg);
1169 fprintf(SAXdebug, "SAX.fatalError: ");
1170 vfprintf(SAXdebug, msg, args);
1171 va_end(args);
1172 }
1173
1174 static xmlSAXHandler debugSAXHandlerStruct = {
1175 internalSubsetDebug,
1176 isStandaloneDebug,
1177 hasInternalSubsetDebug,
1178 hasExternalSubsetDebug,
1179 resolveEntityDebug,
1180 getEntityDebug,
1181 entityDeclDebug,
1182 notationDeclDebug,
1183 attributeDeclDebug,
1184 elementDeclDebug,
1185 unparsedEntityDeclDebug,
1186 setDocumentLocatorDebug,
1187 startDocumentDebug,
1188 endDocumentDebug,
1189 startElementDebug,
1190 endElementDebug,
1191 referenceDebug,
1192 charactersDebug,
1193 ignorableWhitespaceDebug,
1194 processingInstructionDebug,
1195 commentDebug,
1196 warningDebug,
1197 errorDebug,
1198 fatalErrorDebug,
1199 getParameterEntityDebug,
1200 cdataBlockDebug,
1201 externalSubsetDebug,
1202 1,
1203 NULL,
1204 NULL,
1205 NULL,
1206 NULL
1207 };
1208
1209 static xmlSAXHandlerPtr debugSAXHandler = &debugSAXHandlerStruct;
1210
1211 /*
1212 * SAX2 specific callbacks
1213 */
1214 /**
1215 * startElementNsDebug:
1216 * @ctxt: An XML parser context
1217 * @name: The element name
1218 *
1219 * called when an opening tag has been processed.
1220 */
1221 static void
startElementNsDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * localname,const xmlChar * prefix,const xmlChar * URI,int nb_namespaces,const xmlChar ** namespaces,int nb_attributes,int nb_defaulted,const xmlChar ** attributes)1222 startElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
1223 const xmlChar *localname,
1224 const xmlChar *prefix,
1225 const xmlChar *URI,
1226 int nb_namespaces,
1227 const xmlChar **namespaces,
1228 int nb_attributes,
1229 int nb_defaulted,
1230 const xmlChar **attributes)
1231 {
1232 int i;
1233
1234 callbacks++;
1235 if (quiet)
1236 return;
1237 fprintf(SAXdebug, "SAX.startElementNs(%s", (char *) localname);
1238 if (prefix == NULL)
1239 fprintf(SAXdebug, ", NULL");
1240 else
1241 fprintf(SAXdebug, ", %s", (char *) prefix);
1242 if (URI == NULL)
1243 fprintf(SAXdebug, ", NULL");
1244 else
1245 fprintf(SAXdebug, ", '%s'", (char *) URI);
1246 fprintf(SAXdebug, ", %d", nb_namespaces);
1247
1248 if (namespaces != NULL) {
1249 for (i = 0;i < nb_namespaces * 2;i++) {
1250 fprintf(SAXdebug, ", xmlns");
1251 if (namespaces[i] != NULL)
1252 fprintf(SAXdebug, ":%s", namespaces[i]);
1253 i++;
1254 fprintf(SAXdebug, "='%s'", namespaces[i]);
1255 }
1256 }
1257 fprintf(SAXdebug, ", %d, %d", nb_attributes, nb_defaulted);
1258 if (attributes != NULL) {
1259 for (i = 0;i < nb_attributes * 5;i += 5) {
1260 if (attributes[i + 1] != NULL)
1261 fprintf(SAXdebug, ", %s:%s='", attributes[i + 1], attributes[i]);
1262 else
1263 fprintf(SAXdebug, ", %s='", attributes[i]);
1264 fprintf(SAXdebug, "%.4s...', %d", attributes[i + 3],
1265 (int)(attributes[i + 4] - attributes[i + 3]));
1266 }
1267 }
1268 fprintf(SAXdebug, ")\n");
1269 }
1270
1271 /**
1272 * endElementDebug:
1273 * @ctxt: An XML parser context
1274 * @name: The element name
1275 *
1276 * called when the end of an element has been detected.
1277 */
1278 static void
endElementNsDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * localname,const xmlChar * prefix,const xmlChar * URI)1279 endElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
1280 const xmlChar *localname,
1281 const xmlChar *prefix,
1282 const xmlChar *URI)
1283 {
1284 callbacks++;
1285 if (quiet)
1286 return;
1287 fprintf(SAXdebug, "SAX.endElementNs(%s", (char *) localname);
1288 if (prefix == NULL)
1289 fprintf(SAXdebug, ", NULL");
1290 else
1291 fprintf(SAXdebug, ", %s", (char *) prefix);
1292 if (URI == NULL)
1293 fprintf(SAXdebug, ", NULL)\n");
1294 else
1295 fprintf(SAXdebug, ", '%s')\n", (char *) URI);
1296 }
1297
1298 static xmlSAXHandler debugSAX2HandlerStruct = {
1299 internalSubsetDebug,
1300 isStandaloneDebug,
1301 hasInternalSubsetDebug,
1302 hasExternalSubsetDebug,
1303 resolveEntityDebug,
1304 getEntityDebug,
1305 entityDeclDebug,
1306 notationDeclDebug,
1307 attributeDeclDebug,
1308 elementDeclDebug,
1309 unparsedEntityDeclDebug,
1310 setDocumentLocatorDebug,
1311 startDocumentDebug,
1312 endDocumentDebug,
1313 NULL,
1314 NULL,
1315 referenceDebug,
1316 charactersDebug,
1317 ignorableWhitespaceDebug,
1318 processingInstructionDebug,
1319 commentDebug,
1320 warningDebug,
1321 errorDebug,
1322 fatalErrorDebug,
1323 getParameterEntityDebug,
1324 cdataBlockDebug,
1325 externalSubsetDebug,
1326 XML_SAX2_MAGIC,
1327 NULL,
1328 startElementNsDebug,
1329 endElementNsDebug,
1330 NULL
1331 };
1332
1333 static xmlSAXHandlerPtr debugSAX2Handler = &debugSAX2HandlerStruct;
1334
1335 #ifdef LIBXML_HTML_ENABLED
1336 /**
1337 * htmlstartElementDebug:
1338 * @ctxt: An XML parser context
1339 * @name: The element name
1340 *
1341 * called when an opening tag has been processed.
1342 */
1343 static void
htmlstartElementDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar ** atts)1344 htmlstartElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
1345 {
1346 int i;
1347
1348 fprintf(SAXdebug, "SAX.startElement(%s", (char *) name);
1349 if (atts != NULL) {
1350 for (i = 0;(atts[i] != NULL);i++) {
1351 fprintf(SAXdebug, ", %s", atts[i++]);
1352 if (atts[i] != NULL) {
1353 unsigned char output[40];
1354 const unsigned char *att = atts[i];
1355 int outlen, attlen;
1356 fprintf(SAXdebug, "='");
1357 while ((attlen = strlen((char*)att)) > 0) {
1358 outlen = sizeof output - 1;
1359 htmlEncodeEntities(output, &outlen, att, &attlen, '\'');
1360 output[outlen] = 0;
1361 fprintf(SAXdebug, "%s", (char *) output);
1362 att += attlen;
1363 }
1364 fprintf(SAXdebug, "'");
1365 }
1366 }
1367 }
1368 fprintf(SAXdebug, ")\n");
1369 }
1370
1371 /**
1372 * htmlcharactersDebug:
1373 * @ctxt: An XML parser context
1374 * @ch: a xmlChar string
1375 * @len: the number of xmlChar
1376 *
1377 * receiving some chars from the parser.
1378 * Question: how much at a time ???
1379 */
1380 static void
htmlcharactersDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * ch,int len)1381 htmlcharactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1382 {
1383 unsigned char output[40];
1384 int inlen = len, outlen = 30;
1385
1386 htmlEncodeEntities(output, &outlen, ch, &inlen, 0);
1387 output[outlen] = 0;
1388
1389 fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len);
1390 }
1391
1392 /**
1393 * htmlcdataDebug:
1394 * @ctxt: An XML parser context
1395 * @ch: a xmlChar string
1396 * @len: the number of xmlChar
1397 *
1398 * receiving some cdata chars from the parser.
1399 * Question: how much at a time ???
1400 */
1401 static void
htmlcdataDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * ch,int len)1402 htmlcdataDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1403 {
1404 unsigned char output[40];
1405 int inlen = len, outlen = 30;
1406
1407 htmlEncodeEntities(output, &outlen, ch, &inlen, 0);
1408 output[outlen] = 0;
1409
1410 fprintf(SAXdebug, "SAX.cdata(%s, %d)\n", output, len);
1411 }
1412
1413 static xmlSAXHandler debugHTMLSAXHandlerStruct = {
1414 internalSubsetDebug,
1415 isStandaloneDebug,
1416 hasInternalSubsetDebug,
1417 hasExternalSubsetDebug,
1418 resolveEntityDebug,
1419 getEntityDebug,
1420 entityDeclDebug,
1421 notationDeclDebug,
1422 attributeDeclDebug,
1423 elementDeclDebug,
1424 unparsedEntityDeclDebug,
1425 setDocumentLocatorDebug,
1426 startDocumentDebug,
1427 endDocumentDebug,
1428 htmlstartElementDebug,
1429 endElementDebug,
1430 referenceDebug,
1431 htmlcharactersDebug,
1432 ignorableWhitespaceDebug,
1433 processingInstructionDebug,
1434 commentDebug,
1435 warningDebug,
1436 errorDebug,
1437 fatalErrorDebug,
1438 getParameterEntityDebug,
1439 htmlcdataDebug,
1440 externalSubsetDebug,
1441 1,
1442 NULL,
1443 NULL,
1444 NULL,
1445 NULL
1446 };
1447
1448 static xmlSAXHandlerPtr debugHTMLSAXHandler = &debugHTMLSAXHandlerStruct;
1449 #endif /* LIBXML_HTML_ENABLED */
1450
1451 static void
hashFreeEntity(void * payload,const xmlChar * name ATTRIBUTE_UNUSED)1452 hashFreeEntity(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
1453 xmlEntityPtr ent = payload;
1454
1455 xmlFreeEntity(ent);
1456 }
1457
1458 /**
1459 * saxParseTest:
1460 * @filename: the file to parse
1461 * @result: the file with expected result
1462 * @err: the file with error messages
1463 *
1464 * Parse a file using the SAX API and check for errors.
1465 *
1466 * Returns 0 in case of success, an error code otherwise
1467 */
1468 static int
saxParseTest(const char * filename,const char * result,const char * err ATTRIBUTE_UNUSED,int options)1469 saxParseTest(const char *filename, const char *result,
1470 const char *err ATTRIBUTE_UNUSED,
1471 int options) {
1472 int ret;
1473 char *temp;
1474
1475 nb_tests++;
1476 temp = resultFilename(filename, temp_directory, ".res");
1477 if (temp == NULL) {
1478 fprintf(stderr, "out of memory\n");
1479 fatalError();
1480 }
1481 SAXdebug = fopen(temp, "wb");
1482 if (SAXdebug == NULL) {
1483 fprintf(stderr, "Failed to write to %s\n", temp);
1484 free(temp);
1485 return(-1);
1486 }
1487
1488 #ifdef LIBXML_HTML_ENABLED
1489 if (options & XML_PARSE_HTML) {
1490 htmlParserCtxtPtr ctxt;
1491
1492 ctxt = htmlNewSAXParserCtxt(emptySAXHandler, NULL);
1493 htmlCtxtReadFile(ctxt, filename, NULL, options);
1494 htmlFreeParserCtxt(ctxt);
1495 ret = 0;
1496 } else
1497 #endif
1498 {
1499 xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename);
1500 memcpy(ctxt->sax, emptySAXHandler, sizeof(xmlSAXHandler));
1501 xmlCtxtUseOptions(ctxt, options);
1502 xmlParseDocument(ctxt);
1503 ret = ctxt->wellFormed ? 0 : ctxt->errNo;
1504 xmlFreeDoc(ctxt->myDoc);
1505 xmlFreeParserCtxt(ctxt);
1506 }
1507 if (ret == XML_ERR_UNDECLARED_ENTITY) {
1508 fprintf(SAXdebug, "xmlParseDocument returned error %d\n", ret);
1509 ret = 0;
1510 }
1511 if (ret != 0) {
1512 fprintf(stderr, "Failed to parse %s\n", filename);
1513 ret = 1;
1514 goto done;
1515 }
1516 #ifdef LIBXML_HTML_ENABLED
1517 if (options & XML_PARSE_HTML) {
1518 htmlParserCtxtPtr ctxt;
1519
1520 ctxt = htmlNewSAXParserCtxt(debugHTMLSAXHandler, NULL);
1521 htmlCtxtReadFile(ctxt, filename, NULL, options);
1522 htmlFreeParserCtxt(ctxt);
1523 ret = 0;
1524 } else
1525 #endif
1526 {
1527 debugContext userData;
1528 xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename);
1529
1530 if (options & XML_PARSE_SAX1) {
1531 memcpy(ctxt->sax, debugSAXHandler, sizeof(xmlSAXHandler));
1532 options -= XML_PARSE_SAX1;
1533 } else {
1534 memcpy(ctxt->sax, debugSAX2Handler, sizeof(xmlSAXHandler));
1535 }
1536 userData.filename = filename;
1537 userData.generalEntities = xmlHashCreate(0);
1538 userData.parameterEntities = xmlHashCreate(0);
1539 ctxt->userData = &userData;
1540 xmlCtxtUseOptions(ctxt, options);
1541 xmlParseDocument(ctxt);
1542 ret = ctxt->wellFormed ? 0 : ctxt->errNo;
1543 xmlHashFree(userData.generalEntities, hashFreeEntity);
1544 xmlHashFree(userData.parameterEntities, hashFreeEntity);
1545 xmlFreeDoc(ctxt->myDoc);
1546 xmlFreeParserCtxt(ctxt);
1547 }
1548 fclose(SAXdebug);
1549 if (compareFiles(temp, result)) {
1550 fprintf(stderr, "Got a difference for %s\n", filename);
1551 ret = 1;
1552 }
1553
1554 done:
1555 if (temp != NULL) {
1556 unlink(temp);
1557 free(temp);
1558 }
1559
1560 return(ret);
1561 }
1562
1563 /************************************************************************
1564 * *
1565 * Parse to tree based tests *
1566 * *
1567 ************************************************************************/
1568 /**
1569 * oldParseTest:
1570 * @filename: the file to parse
1571 * @result: the file with expected result
1572 * @err: the file with error messages: unused
1573 *
1574 * Parse a file using the old xmlParseFile API, then serialize back
1575 * reparse the result and serialize again, then check for deviation
1576 * in serialization.
1577 *
1578 * Returns 0 in case of success, an error code otherwise
1579 */
1580 static int
oldParseTest(const char * filename,const char * result,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)1581 oldParseTest(const char *filename, const char *result,
1582 const char *err ATTRIBUTE_UNUSED,
1583 int options ATTRIBUTE_UNUSED) {
1584 xmlDocPtr doc;
1585 char *temp;
1586 int res = 0;
1587
1588 nb_tests++;
1589 /*
1590 * base of the test, parse with the old API
1591 */
1592 #ifdef LIBXML_SAX1_ENABLED
1593 xmlGetWarningsDefaultValue = 0;
1594 doc = xmlParseFile(filename);
1595 xmlGetWarningsDefaultValue = 1;
1596 #else
1597 doc = xmlReadFile(filename, NULL, XML_PARSE_NOWARNING);
1598 #endif
1599 if (doc == NULL)
1600 return(1);
1601 temp = resultFilename(filename, temp_directory, ".res");
1602 if (temp == NULL) {
1603 fprintf(stderr, "out of memory\n");
1604 fatalError();
1605 }
1606 xmlSaveFile(temp, doc);
1607 if (compareFiles(temp, result)) {
1608 res = 1;
1609 }
1610 xmlFreeDoc(doc);
1611
1612 /*
1613 * Parse the saved result to make sure the round trip is okay
1614 */
1615 #ifdef LIBXML_SAX1_ENABLED
1616 xmlGetWarningsDefaultValue = 0;
1617 doc = xmlParseFile(temp);
1618 xmlGetWarningsDefaultValue = 1;
1619 #else
1620 doc = xmlReadFile(temp, NULL, XML_PARSE_NOWARNING);
1621 #endif
1622 if (doc == NULL)
1623 return(1);
1624 xmlSaveFile(temp, doc);
1625 if (compareFiles(temp, result)) {
1626 res = 1;
1627 }
1628 xmlFreeDoc(doc);
1629
1630 if (temp != NULL) {
1631 unlink(temp);
1632 free(temp);
1633 }
1634
1635 return(res);
1636 }
1637
1638 #ifdef LIBXML_PUSH_ENABLED
1639 /**
1640 * pushParseTest:
1641 * @filename: the file to parse
1642 * @result: the file with expected result
1643 * @err: the file with error messages: unused
1644 *
1645 * Parse a file using the Push API, then serialize back
1646 * to check for content.
1647 *
1648 * Returns 0 in case of success, an error code otherwise
1649 */
1650 static int
pushParseTest(const char * filename,const char * result,const char * err ATTRIBUTE_UNUSED,int options)1651 pushParseTest(const char *filename, const char *result,
1652 const char *err ATTRIBUTE_UNUSED,
1653 int options) {
1654 xmlParserCtxtPtr ctxt;
1655 xmlDocPtr doc;
1656 const char *base;
1657 int size, res;
1658 int cur = 0;
1659 int chunkSize = 4;
1660
1661 nb_tests++;
1662 /*
1663 * load the document in memory and work from there.
1664 */
1665 if (loadMem(filename, &base, &size) != 0) {
1666 fprintf(stderr, "Failed to load %s\n", filename);
1667 return(-1);
1668 }
1669
1670 if (chunkSize > size)
1671 chunkSize = size;
1672
1673 #ifdef LIBXML_HTML_ENABLED
1674 if (options & XML_PARSE_HTML)
1675 ctxt = htmlCreatePushParserCtxt(NULL, NULL, base + cur, chunkSize, filename,
1676 XML_CHAR_ENCODING_NONE);
1677 else
1678 #endif
1679 ctxt = xmlCreatePushParserCtxt(NULL, NULL, base + cur, chunkSize, filename);
1680 xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
1681 xmlCtxtUseOptions(ctxt, options);
1682 cur += chunkSize;
1683 chunkSize = 1024;
1684 do {
1685 if (cur + chunkSize >= size) {
1686 #ifdef LIBXML_HTML_ENABLED
1687 if (options & XML_PARSE_HTML)
1688 htmlParseChunk(ctxt, base + cur, size - cur, 1);
1689 else
1690 #endif
1691 xmlParseChunk(ctxt, base + cur, size - cur, 1);
1692 break;
1693 } else {
1694 #ifdef LIBXML_HTML_ENABLED
1695 if (options & XML_PARSE_HTML)
1696 htmlParseChunk(ctxt, base + cur, chunkSize, 0);
1697 else
1698 #endif
1699 xmlParseChunk(ctxt, base + cur, chunkSize, 0);
1700 cur += chunkSize;
1701 }
1702 } while (cur < size);
1703 doc = ctxt->myDoc;
1704 #ifdef LIBXML_HTML_ENABLED
1705 if (options & XML_PARSE_HTML)
1706 res = 1;
1707 else
1708 #endif
1709 res = ctxt->wellFormed;
1710 xmlFreeParserCtxt(ctxt);
1711 free((char *)base);
1712 if (!res) {
1713 xmlFreeDoc(doc);
1714 fprintf(stderr, "Failed to parse %s\n", filename);
1715 return(-1);
1716 }
1717 #ifdef LIBXML_HTML_ENABLED
1718 if (options & XML_PARSE_HTML)
1719 htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1720 else
1721 #endif
1722 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1723 xmlFreeDoc(doc);
1724 res = compareFileMem(result, base, size);
1725 if ((base == NULL) || (res != 0)) {
1726 if (base != NULL)
1727 xmlFree((char *)base);
1728 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
1729 return(-1);
1730 }
1731 xmlFree((char *)base);
1732 if (err != NULL) {
1733 res = compareFileMem(err, testErrors, testErrorsSize);
1734 if (res != 0) {
1735 fprintf(stderr, "Error for %s failed\n", filename);
1736 return(-1);
1737 }
1738 }
1739 return(0);
1740 }
1741
1742 static int pushBoundaryCount;
1743 static int pushBoundaryRefCount;
1744 static int pushBoundaryCharsCount;
1745 static int pushBoundaryCDataCount;
1746
1747 static void
internalSubsetBnd(void * ctx,const xmlChar * name,const xmlChar * externalID,const xmlChar * systemID)1748 internalSubsetBnd(void *ctx, const xmlChar *name, const xmlChar *externalID,
1749 const xmlChar *systemID) {
1750 pushBoundaryCount++;
1751 xmlSAX2InternalSubset(ctx, name, externalID, systemID);
1752 }
1753
1754 static void
referenceBnd(void * ctx,const xmlChar * name)1755 referenceBnd(void *ctx, const xmlChar *name) {
1756 pushBoundaryRefCount++;
1757 xmlSAX2Reference(ctx, name);
1758 }
1759
1760 static void
charactersBnd(void * ctx,const xmlChar * ch,int len)1761 charactersBnd(void *ctx, const xmlChar *ch, int len) {
1762 pushBoundaryCount++;
1763 pushBoundaryCharsCount++;
1764 xmlSAX2Characters(ctx, ch, len);
1765 }
1766
1767 static void
cdataBlockBnd(void * ctx,const xmlChar * ch,int len)1768 cdataBlockBnd(void *ctx, const xmlChar *ch, int len) {
1769 pushBoundaryCount++;
1770 pushBoundaryCDataCount++;
1771 xmlSAX2CDataBlock(ctx, ch, len);
1772 }
1773
1774 static void
processingInstructionBnd(void * ctx,const xmlChar * target,const xmlChar * data)1775 processingInstructionBnd(void *ctx, const xmlChar *target,
1776 const xmlChar *data) {
1777 pushBoundaryCount++;
1778 xmlSAX2ProcessingInstruction(ctx, target, data);
1779 }
1780
1781 static void
commentBnd(void * ctx,const xmlChar * value)1782 commentBnd(void *ctx, const xmlChar *value) {
1783 xmlParserCtxtPtr ctxt = ctx;
1784 if (ctxt->inSubset == 0)
1785 pushBoundaryCount++;
1786 xmlSAX2Comment(ctx, value);
1787 }
1788
1789 static void
startElementBnd(void * ctx,const xmlChar * xname,const xmlChar ** atts)1790 startElementBnd(void *ctx, const xmlChar *xname, const xmlChar **atts) {
1791 const char *name = (const char *)xname;
1792
1793 /* Some elements might be created automatically. */
1794 if ((strcmp(name, "html") != 0) &&
1795 (strcmp(name, "body") != 0) &&
1796 (strcmp(name, "head") != 0) &&
1797 (strcmp(name, "p") != 0)) {
1798 pushBoundaryCount++;
1799 }
1800 xmlSAX2StartElement(ctx, xname, atts);
1801 }
1802
1803 static void
endElementBnd(void * ctx,const xmlChar * name)1804 endElementBnd(void *ctx, const xmlChar *name) {
1805 /*pushBoundaryCount++;*/
1806 xmlSAX2EndElement(ctx, name);
1807 }
1808
1809 static void
startElementNsBnd(void * ctx,const xmlChar * localname,const xmlChar * prefix,const xmlChar * URI,int nb_namespaces,const xmlChar ** namespaces,int nb_attributes,int nb_defaulted,const xmlChar ** attributes)1810 startElementNsBnd(void *ctx, const xmlChar *localname, const xmlChar *prefix,
1811 const xmlChar *URI, int nb_namespaces,
1812 const xmlChar **namespaces, int nb_attributes,
1813 int nb_defaulted, const xmlChar **attributes) {
1814 pushBoundaryCount++;
1815 xmlSAX2StartElementNs(ctx, localname, prefix, URI, nb_namespaces,
1816 namespaces, nb_attributes, nb_defaulted, attributes);
1817 }
1818
1819 static void
endElementNsBnd(void * ctx,const xmlChar * localname,const xmlChar * prefix,const xmlChar * URI)1820 endElementNsBnd(void *ctx, const xmlChar *localname, const xmlChar *prefix,
1821 const xmlChar *URI) {
1822 /*pushBoundaryCount++;*/
1823 xmlSAX2EndElementNs(ctx, localname, prefix, URI);
1824 }
1825
1826 /**
1827 * pushBoundaryTest:
1828 * @filename: the file to parse
1829 * @result: the file with expected result
1830 * @err: the file with error messages: unused
1831 *
1832 * Test whether the push parser detects boundaries between syntactical
1833 * elements correctly.
1834 *
1835 * Returns 0 in case of success, an error code otherwise
1836 */
1837 static int
pushBoundaryTest(const char * filename,const char * result,const char * err ATTRIBUTE_UNUSED,int options)1838 pushBoundaryTest(const char *filename, const char *result,
1839 const char *err ATTRIBUTE_UNUSED,
1840 int options) {
1841 xmlParserCtxtPtr ctxt;
1842 xmlDocPtr doc;
1843 xmlSAXHandler bndSAX;
1844 const char *base;
1845 int size, res, numCallbacks;
1846 int cur = 0;
1847 unsigned long avail, oldConsumed, consumed;
1848
1849 /*
1850 * HTML encoding detection doesn't work when data is fed bytewise.
1851 */
1852 if (strcmp(filename, "./test/HTML/xml-declaration-1.html") == 0)
1853 return(0);
1854
1855 /*
1856 * If the parser made progress, check that exactly one construct was
1857 * processed and that the input buffer is (almost) empty.
1858 * Since we use a chunk size of 1, this tests whether content is
1859 * processed as early as possible.
1860 */
1861
1862 nb_tests++;
1863
1864 memset(&bndSAX, 0, sizeof(bndSAX));
1865 #ifdef LIBXML_HTML_ENABLED
1866 if (options & XML_PARSE_HTML) {
1867 xmlSAX2InitHtmlDefaultSAXHandler(&bndSAX);
1868 bndSAX.startElement = startElementBnd;
1869 bndSAX.endElement = endElementBnd;
1870 } else
1871 #endif
1872 {
1873 xmlSAXVersion(&bndSAX, 2);
1874 bndSAX.startElementNs = startElementNsBnd;
1875 bndSAX.endElementNs = endElementNsBnd;
1876 }
1877
1878 bndSAX.internalSubset = internalSubsetBnd;
1879 bndSAX.reference = referenceBnd;
1880 bndSAX.characters = charactersBnd;
1881 bndSAX.cdataBlock = cdataBlockBnd;
1882 bndSAX.processingInstruction = processingInstructionBnd;
1883 bndSAX.comment = commentBnd;
1884
1885 /*
1886 * load the document in memory and work from there.
1887 */
1888 if (loadMem(filename, &base, &size) != 0) {
1889 fprintf(stderr, "Failed to load %s\n", filename);
1890 return(-1);
1891 }
1892
1893 #ifdef LIBXML_HTML_ENABLED
1894 if (options & XML_PARSE_HTML)
1895 ctxt = htmlCreatePushParserCtxt(&bndSAX, NULL, base, 1, filename,
1896 XML_CHAR_ENCODING_NONE);
1897 else
1898 #endif
1899 ctxt = xmlCreatePushParserCtxt(&bndSAX, NULL, base, 1, filename);
1900 xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
1901 xmlCtxtUseOptions(ctxt, options);
1902 cur = 1;
1903 consumed = 0;
1904 numCallbacks = 0;
1905 avail = 0;
1906 while ((cur < size) && (numCallbacks <= 1) && (avail <= 0)) {
1907 int terminate = (cur + 1 >= size);
1908 int isText = 0;
1909
1910 if (ctxt->instate == XML_PARSER_CONTENT) {
1911 int firstChar = (ctxt->input->end > ctxt->input->cur) ?
1912 *ctxt->input->cur :
1913 base[cur];
1914
1915 if ((firstChar != '<') &&
1916 ((options & XML_PARSE_HTML) || (firstChar != '&')))
1917 isText = 1;
1918 }
1919
1920 oldConsumed = ctxt->input->consumed +
1921 (unsigned long) (ctxt->input->cur - ctxt->input->base);
1922
1923 pushBoundaryCount = 0;
1924 pushBoundaryRefCount = 0;
1925 pushBoundaryCharsCount = 0;
1926 pushBoundaryCDataCount = 0;
1927
1928 #ifdef LIBXML_HTML_ENABLED
1929 if (options & XML_PARSE_HTML)
1930 htmlParseChunk(ctxt, base + cur, 1, terminate);
1931 else
1932 #endif
1933 xmlParseChunk(ctxt, base + cur, 1, terminate);
1934 cur += 1;
1935
1936 /*
1937 * Callback check: Check that only a single construct was parsed.
1938 */
1939 if (pushBoundaryRefCount > 0) {
1940 numCallbacks = 1;
1941 } else {
1942 numCallbacks = pushBoundaryCount;
1943 if (pushBoundaryCharsCount > 1) {
1944 if (options & XML_PARSE_HTML) {
1945 /*
1946 * The HTML parser can generate a mix of chars and
1947 * references.
1948 */
1949 numCallbacks -= pushBoundaryCharsCount - 1;
1950 } else {
1951 /*
1952 * Allow two chars callbacks. This can happen when
1953 * multi-byte chars are split across buffer boundaries.
1954 */
1955 numCallbacks -= 1;
1956 }
1957 }
1958 if (options & XML_PARSE_HTML) {
1959 /*
1960 * Allow multiple cdata callbacks in HTML mode.
1961 */
1962 if (pushBoundaryCDataCount > 1)
1963 numCallbacks -= pushBoundaryCDataCount - 1;
1964 }
1965 }
1966
1967 /*
1968 * Buffer check: If input was consumed, check that the input
1969 * buffer is (almost) empty.
1970 */
1971 consumed = ctxt->input->consumed +
1972 (unsigned long) (ctxt->input->cur - ctxt->input->base);
1973 if ((ctxt->instate != XML_PARSER_DTD) &&
1974 (consumed >= 4) &&
1975 (consumed != oldConsumed)) {
1976 size_t max = 0;
1977
1978 avail = ctxt->input->end - ctxt->input->cur;
1979
1980 if ((options & XML_PARSE_HTML) &&
1981 (ctxt->instate == XML_PARSER_END_TAG)) {
1982 /* Something related to script parsing. */
1983 max = 3;
1984 } else if (isText) {
1985 int c = *ctxt->input->cur;
1986
1987 /* 3 bytes for partial UTF-8 */
1988 max = ((c == '<') || (c == '&')) ? 1 : 3;
1989 } else if (ctxt->instate == XML_PARSER_CDATA_SECTION) {
1990 /* 2 bytes for terminator, 3 bytes for UTF-8 */
1991 max = 5;
1992 }
1993
1994 if (avail <= max)
1995 avail = 0;
1996 }
1997 }
1998 doc = ctxt->myDoc;
1999 #ifdef LIBXML_HTML_ENABLED
2000 if (options & XML_PARSE_HTML)
2001 res = 1;
2002 else
2003 #endif
2004 res = ctxt->wellFormed;
2005 xmlFreeParserCtxt(ctxt);
2006 free((char *)base);
2007 if (numCallbacks > 1) {
2008 xmlFreeDoc(doc);
2009 fprintf(stderr, "Failed push boundary callback test (%d@%lu-%lu): %s\n",
2010 numCallbacks, oldConsumed, consumed, filename);
2011 return(-1);
2012 }
2013 if (avail > 0) {
2014 xmlFreeDoc(doc);
2015 fprintf(stderr, "Failed push boundary buffer test (%lu@%lu): %s\n",
2016 avail, consumed, filename);
2017 return(-1);
2018 }
2019 if (!res) {
2020 xmlFreeDoc(doc);
2021 fprintf(stderr, "Failed to parse %s\n", filename);
2022 return(-1);
2023 }
2024 #ifdef LIBXML_HTML_ENABLED
2025 if (options & XML_PARSE_HTML)
2026 htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2027 else
2028 #endif
2029 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2030 xmlFreeDoc(doc);
2031 res = compareFileMem(result, base, size);
2032 if ((base == NULL) || (res != 0)) {
2033 if (base != NULL)
2034 xmlFree((char *)base);
2035 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
2036 return(-1);
2037 }
2038 xmlFree((char *)base);
2039 if (err != NULL) {
2040 res = compareFileMem(err, testErrors, testErrorsSize);
2041 if (res != 0) {
2042 fprintf(stderr, "Error for %s failed\n", filename);
2043 return(-1);
2044 }
2045 }
2046 return(0);
2047 }
2048 #endif
2049
2050 /**
2051 * memParseTest:
2052 * @filename: the file to parse
2053 * @result: the file with expected result
2054 * @err: the file with error messages: unused
2055 *
2056 * Parse a file using the old xmlReadMemory API, then serialize back
2057 * reparse the result and serialize again, then check for deviation
2058 * in serialization.
2059 *
2060 * Returns 0 in case of success, an error code otherwise
2061 */
2062 static int
memParseTest(const char * filename,const char * result,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)2063 memParseTest(const char *filename, const char *result,
2064 const char *err ATTRIBUTE_UNUSED,
2065 int options ATTRIBUTE_UNUSED) {
2066 xmlDocPtr doc;
2067 const char *base;
2068 int size, res;
2069
2070 nb_tests++;
2071 /*
2072 * load and parse the memory
2073 */
2074 if (loadMem(filename, &base, &size) != 0) {
2075 fprintf(stderr, "Failed to load %s\n", filename);
2076 return(-1);
2077 }
2078
2079 doc = xmlReadMemory(base, size, filename, NULL, XML_PARSE_NOWARNING);
2080 unloadMem(base);
2081 if (doc == NULL) {
2082 return(1);
2083 }
2084 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2085 xmlFreeDoc(doc);
2086 res = compareFileMem(result, base, size);
2087 if ((base == NULL) || (res != 0)) {
2088 if (base != NULL)
2089 xmlFree((char *)base);
2090 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
2091 return(-1);
2092 }
2093 xmlFree((char *)base);
2094 return(0);
2095 }
2096
2097 /**
2098 * noentParseTest:
2099 * @filename: the file to parse
2100 * @result: the file with expected result
2101 * @err: the file with error messages: unused
2102 *
2103 * Parse a file with entity resolution, then serialize back
2104 * reparse the result and serialize again, then check for deviation
2105 * in serialization.
2106 *
2107 * Returns 0 in case of success, an error code otherwise
2108 */
2109 static int
noentParseTest(const char * filename,const char * result,const char * err ATTRIBUTE_UNUSED,int options)2110 noentParseTest(const char *filename, const char *result,
2111 const char *err ATTRIBUTE_UNUSED,
2112 int options) {
2113 xmlDocPtr doc;
2114 char *temp;
2115 int res = 0;
2116
2117 nb_tests++;
2118 /*
2119 * base of the test, parse with the old API
2120 */
2121 doc = xmlReadFile(filename, NULL,
2122 options | XML_PARSE_NOWARNING | XML_PARSE_NOERROR);
2123 if (doc == NULL)
2124 return(1);
2125 temp = resultFilename(filename, temp_directory, ".res");
2126 if (temp == NULL) {
2127 fprintf(stderr, "Out of memory\n");
2128 fatalError();
2129 }
2130 xmlSaveFile(temp, doc);
2131 if (compareFiles(temp, result)) {
2132 res = 1;
2133 }
2134 xmlFreeDoc(doc);
2135
2136 /*
2137 * Parse the saved result to make sure the round trip is okay
2138 */
2139 doc = xmlReadFile(filename, NULL,
2140 options | XML_PARSE_NOWARNING | XML_PARSE_NOERROR);
2141 if (doc == NULL)
2142 return(1);
2143 xmlSaveFile(temp, doc);
2144 if (compareFiles(temp, result)) {
2145 res = 1;
2146 }
2147 xmlFreeDoc(doc);
2148
2149 if (temp != NULL) {
2150 unlink(temp);
2151 free(temp);
2152 }
2153 return(res);
2154 }
2155
2156 /**
2157 * errParseTest:
2158 * @filename: the file to parse
2159 * @result: the file with expected result
2160 * @err: the file with error messages
2161 *
2162 * Parse a file using the xmlReadFile API and check for errors.
2163 *
2164 * Returns 0 in case of success, an error code otherwise
2165 */
2166 static int
errParseTest(const char * filename,const char * result,const char * err,int options)2167 errParseTest(const char *filename, const char *result, const char *err,
2168 int options) {
2169 xmlParserCtxtPtr ctxt;
2170 xmlDocPtr doc;
2171 const char *base = NULL;
2172 int size, res = 0;
2173
2174 nb_tests++;
2175 #ifdef LIBXML_HTML_ENABLED
2176 if (options & XML_PARSE_HTML) {
2177 ctxt = htmlNewParserCtxt();
2178 xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
2179 doc = htmlCtxtReadFile(ctxt, filename, NULL, options);
2180 htmlFreeParserCtxt(ctxt);
2181 } else
2182 #endif
2183 {
2184 ctxt = xmlNewParserCtxt();
2185 xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
2186 doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
2187 xmlFreeParserCtxt(ctxt);
2188 #ifdef LIBXML_XINCLUDE_ENABLED
2189 if (options & XML_PARSE_XINCLUDE) {
2190 xmlXIncludeCtxtPtr xinc = NULL;
2191
2192 xinc = xmlXIncludeNewContext(doc);
2193 xmlXIncludeSetErrorHandler(xinc, testStructuredErrorHandler, NULL);
2194 xmlXIncludeSetFlags(xinc, options);
2195 if (xmlXIncludeProcessNode(xinc, (xmlNodePtr) doc) < 0) {
2196 testErrorHandler(NULL, "%s : failed to parse\n", filename);
2197 xmlFreeDoc(doc);
2198 doc = NULL;
2199 }
2200 xmlXIncludeFreeContext(xinc);
2201 }
2202 #endif
2203 }
2204 if (result) {
2205 if (doc == NULL) {
2206 base = "";
2207 size = 0;
2208 } else {
2209 #ifdef LIBXML_HTML_ENABLED
2210 if (options & XML_PARSE_HTML) {
2211 htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2212 } else
2213 #endif
2214 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2215 }
2216 res = compareFileMem(result, base, size);
2217 }
2218 if (doc != NULL) {
2219 if (base != NULL)
2220 xmlFree((char *)base);
2221 xmlFreeDoc(doc);
2222 }
2223 if (res != 0) {
2224 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
2225 return(-1);
2226 }
2227 if (err != NULL) {
2228 res = compareFileMem(err, testErrors, testErrorsSize);
2229 if (res != 0) {
2230 fprintf(stderr, "Error for %s failed\n", filename);
2231 return(-1);
2232 }
2233 } else if (options & XML_PARSE_DTDVALID) {
2234 if (testErrorsSize != 0)
2235 fprintf(stderr, "Validation for %s failed\n", filename);
2236 }
2237
2238 return(0);
2239 }
2240
2241 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_HTML_ENABLED)
2242 /**
2243 * fdParseTest:
2244 * @filename: the file to parse
2245 * @result: the file with expected result
2246 * @err: the file with error messages
2247 *
2248 * Parse a file using the xmlReadFd API and check for errors.
2249 *
2250 * Returns 0 in case of success, an error code otherwise
2251 */
2252 static int
fdParseTest(const char * filename,const char * result,const char * err,int options)2253 fdParseTest(const char *filename, const char *result, const char *err,
2254 int options) {
2255 xmlParserCtxtPtr ctxt;
2256 xmlDocPtr doc;
2257 const char *base = NULL;
2258 int size, res = 0, fd;
2259
2260 nb_tests++;
2261 fd = open(filename, RD_FLAGS);
2262 #ifdef LIBXML_HTML_ENABLED
2263 if (options & XML_PARSE_HTML) {
2264 ctxt = htmlNewParserCtxt();
2265 xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
2266 doc = htmlCtxtReadFd(ctxt, fd, filename, NULL, options);
2267 htmlFreeParserCtxt(ctxt);
2268 } else
2269 #endif
2270 {
2271 ctxt = xmlNewParserCtxt();
2272 xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
2273 doc = xmlCtxtReadFd(ctxt, fd, filename, NULL, options);
2274 xmlFreeParserCtxt(ctxt);
2275 }
2276 close(fd);
2277 if (result) {
2278 if (doc == NULL) {
2279 base = "";
2280 size = 0;
2281 } else {
2282 #ifdef LIBXML_HTML_ENABLED
2283 if (options & XML_PARSE_HTML) {
2284 htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2285 } else
2286 #endif
2287 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2288 }
2289 res = compareFileMem(result, base, size);
2290 }
2291 if (doc != NULL) {
2292 if (base != NULL)
2293 xmlFree((char *)base);
2294 xmlFreeDoc(doc);
2295 }
2296 if (res != 0) {
2297 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
2298 return(-1);
2299 }
2300 if (err != NULL) {
2301 res = compareFileMem(err, testErrors, testErrorsSize);
2302 if (res != 0) {
2303 fprintf(stderr, "Error for %s failed\n", filename);
2304 return(-1);
2305 }
2306 } else if (options & XML_PARSE_DTDVALID) {
2307 if (testErrorsSize != 0)
2308 fprintf(stderr, "Validation for %s failed\n", filename);
2309 }
2310
2311 return(0);
2312 }
2313 #endif
2314
2315
2316 #ifdef LIBXML_READER_ENABLED
2317 /************************************************************************
2318 * *
2319 * Reader based tests *
2320 * *
2321 ************************************************************************/
2322
processNode(FILE * out,xmlTextReaderPtr reader)2323 static void processNode(FILE *out, xmlTextReaderPtr reader) {
2324 const xmlChar *name, *value;
2325 int type, empty;
2326
2327 type = xmlTextReaderNodeType(reader);
2328 empty = xmlTextReaderIsEmptyElement(reader);
2329
2330 name = xmlTextReaderConstName(reader);
2331 if (name == NULL)
2332 name = BAD_CAST "--";
2333
2334 value = xmlTextReaderConstValue(reader);
2335
2336
2337 fprintf(out, "%d %d %s %d %d",
2338 xmlTextReaderDepth(reader),
2339 type,
2340 name,
2341 empty,
2342 xmlTextReaderHasValue(reader));
2343 if (value == NULL)
2344 fprintf(out, "\n");
2345 else {
2346 fprintf(out, " %s\n", value);
2347 }
2348 }
2349 static int
streamProcessTest(const char * filename,const char * result,const char * err,xmlTextReaderPtr reader,const char * rng,int options ATTRIBUTE_UNUSED)2350 streamProcessTest(const char *filename, const char *result, const char *err,
2351 xmlTextReaderPtr reader, const char *rng,
2352 int options ATTRIBUTE_UNUSED) {
2353 int ret;
2354 char *temp = NULL;
2355 FILE *t = NULL;
2356
2357 if (reader == NULL)
2358 return(-1);
2359
2360 nb_tests++;
2361 if (result != NULL) {
2362 temp = resultFilename(filename, temp_directory, ".res");
2363 if (temp == NULL) {
2364 fprintf(stderr, "Out of memory\n");
2365 fatalError();
2366 }
2367 t = fopen(temp, "wb");
2368 if (t == NULL) {
2369 fprintf(stderr, "Can't open temp file %s\n", temp);
2370 free(temp);
2371 return(-1);
2372 }
2373 }
2374 #ifdef LIBXML_SCHEMAS_ENABLED
2375 if (rng != NULL) {
2376 ret = xmlTextReaderRelaxNGValidate(reader, rng);
2377 if (ret < 0) {
2378 testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n",
2379 rng);
2380 fclose(t);
2381 if (temp != NULL) {
2382 unlink(temp);
2383 free(temp);
2384 }
2385 return(0);
2386 }
2387 }
2388 #endif
2389 ret = xmlTextReaderRead(reader);
2390 while (ret == 1) {
2391 if ((t != NULL) && (rng == NULL))
2392 processNode(t, reader);
2393 ret = xmlTextReaderRead(reader);
2394 }
2395 if (ret != 0) {
2396 testErrorHandler(NULL, "%s : failed to parse\n", filename);
2397 }
2398 if (rng != NULL) {
2399 if (xmlTextReaderIsValid(reader) != 1) {
2400 testErrorHandler(NULL, "%s fails to validate\n", filename);
2401 } else {
2402 testErrorHandler(NULL, "%s validates\n", filename);
2403 }
2404 }
2405 if (t != NULL) {
2406 fclose(t);
2407 ret = compareFiles(temp, result);
2408 if (temp != NULL) {
2409 unlink(temp);
2410 free(temp);
2411 }
2412 if (ret) {
2413 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
2414 return(-1);
2415 }
2416 }
2417 if (err != NULL) {
2418 ret = compareFileMem(err, testErrors, testErrorsSize);
2419 if (ret != 0) {
2420 fprintf(stderr, "Error for %s failed\n", filename);
2421 printf("%s", testErrors);
2422 return(-1);
2423 }
2424 }
2425
2426 return(0);
2427 }
2428
2429 /**
2430 * streamParseTest:
2431 * @filename: the file to parse
2432 * @result: the file with expected result
2433 * @err: the file with error messages
2434 *
2435 * Parse a file using the reader API and check for errors.
2436 *
2437 * Returns 0 in case of success, an error code otherwise
2438 */
2439 static int
streamParseTest(const char * filename,const char * result,const char * err,int options)2440 streamParseTest(const char *filename, const char *result, const char *err,
2441 int options) {
2442 xmlTextReaderPtr reader;
2443 int ret;
2444
2445 reader = xmlReaderForFile(filename, NULL, options);
2446 xmlTextReaderSetStructuredErrorHandler(reader, testStructuredErrorHandler,
2447 NULL);
2448 ret = streamProcessTest(filename, result, err, reader, NULL, options);
2449 xmlFreeTextReader(reader);
2450 return(ret);
2451 }
2452
2453 /**
2454 * walkerParseTest:
2455 * @filename: the file to parse
2456 * @result: the file with expected result
2457 * @err: the file with error messages
2458 *
2459 * Parse a file using the walker, i.e. a reader built from a atree.
2460 *
2461 * Returns 0 in case of success, an error code otherwise
2462 */
2463 static int
walkerParseTest(const char * filename,const char * result,const char * err,int options)2464 walkerParseTest(const char *filename, const char *result, const char *err,
2465 int options) {
2466 xmlDocPtr doc;
2467 xmlTextReaderPtr reader;
2468 int ret;
2469
2470 doc = xmlReadFile(filename, NULL, options | XML_PARSE_NOWARNING);
2471 if (doc == NULL) {
2472 fprintf(stderr, "Failed to parse %s\n", filename);
2473 return(-1);
2474 }
2475 reader = xmlReaderWalker(doc);
2476 ret = streamProcessTest(filename, result, err, reader, NULL, options);
2477 xmlFreeTextReader(reader);
2478 xmlFreeDoc(doc);
2479 return(ret);
2480 }
2481
2482 /**
2483 * streamMemParseTest:
2484 * @filename: the file to parse
2485 * @result: the file with expected result
2486 * @err: the file with error messages
2487 *
2488 * Parse a file using the reader API from memory and check for errors.
2489 *
2490 * Returns 0 in case of success, an error code otherwise
2491 */
2492 static int
streamMemParseTest(const char * filename,const char * result,const char * err,int options)2493 streamMemParseTest(const char *filename, const char *result, const char *err,
2494 int options) {
2495 xmlTextReaderPtr reader;
2496 int ret;
2497 const char *base;
2498 int size;
2499
2500 /*
2501 * load and parse the memory
2502 */
2503 if (loadMem(filename, &base, &size) != 0) {
2504 fprintf(stderr, "Failed to load %s\n", filename);
2505 return(-1);
2506 }
2507 reader = xmlReaderForMemory(base, size, filename, NULL, options);
2508 xmlTextReaderSetStructuredErrorHandler(reader, testStructuredErrorHandler,
2509 NULL);
2510 ret = streamProcessTest(filename, result, err, reader, NULL, options);
2511 free((char *)base);
2512 xmlFreeTextReader(reader);
2513 return(ret);
2514 }
2515 #endif
2516
2517 #ifdef LIBXML_XPATH_ENABLED
2518 #ifdef LIBXML_DEBUG_ENABLED
2519 /************************************************************************
2520 * *
2521 * XPath and XPointer based tests *
2522 * *
2523 ************************************************************************/
2524
2525 static FILE *xpathOutput;
2526 static xmlDocPtr xpathDocument;
2527
2528 static void
testXPath(const char * str,int xptr,int expr)2529 testXPath(const char *str, int xptr, int expr) {
2530 xmlXPathObjectPtr res;
2531 xmlXPathContextPtr ctxt;
2532
2533 nb_tests++;
2534 #if defined(LIBXML_XPTR_ENABLED)
2535 if (xptr) {
2536 ctxt = xmlXPathNewContext(xpathDocument);
2537 xmlXPathSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
2538 res = xmlXPtrEval(BAD_CAST str, ctxt);
2539 } else {
2540 #endif
2541 ctxt = xmlXPathNewContext(xpathDocument);
2542 xmlXPathSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
2543 ctxt->node = xmlDocGetRootElement(xpathDocument);
2544 if (expr)
2545 res = xmlXPathEvalExpression(BAD_CAST str, ctxt);
2546 else {
2547 /* res = xmlXPathEval(BAD_CAST str, ctxt); */
2548 xmlXPathCompExprPtr comp;
2549
2550 comp = xmlXPathCompile(BAD_CAST str);
2551 if (comp != NULL) {
2552 res = xmlXPathCompiledEval(comp, ctxt);
2553 xmlXPathFreeCompExpr(comp);
2554 } else
2555 res = NULL;
2556 }
2557 #if defined(LIBXML_XPTR_ENABLED)
2558 }
2559 #endif
2560 xmlXPathDebugDumpObject(xpathOutput, res, 0);
2561 xmlXPathFreeObject(res);
2562 xmlXPathFreeContext(ctxt);
2563 }
2564
2565 /**
2566 * xpathExprTest:
2567 * @filename: the file to parse
2568 * @result: the file with expected result
2569 * @err: the file with error messages
2570 *
2571 * Parse a file containing XPath standalone expressions and evaluate them
2572 *
2573 * Returns 0 in case of success, an error code otherwise
2574 */
2575 static int
xpathCommonTest(const char * filename,const char * result,int xptr,int expr)2576 xpathCommonTest(const char *filename, const char *result,
2577 int xptr, int expr) {
2578 FILE *input;
2579 char expression[5000];
2580 int len, ret = 0;
2581 char *temp;
2582
2583 temp = resultFilename(filename, temp_directory, ".res");
2584 if (temp == NULL) {
2585 fprintf(stderr, "Out of memory\n");
2586 fatalError();
2587 }
2588 xpathOutput = fopen(temp, "wb");
2589 if (xpathOutput == NULL) {
2590 fprintf(stderr, "failed to open output file %s\n", temp);
2591 free(temp);
2592 return(-1);
2593 }
2594
2595 input = fopen(filename, "rb");
2596 if (input == NULL) {
2597 fprintf(stderr,
2598 "Cannot open %s for reading\n", filename);
2599 free(temp);
2600 return(-1);
2601 }
2602 while (fgets(expression, 4500, input) != NULL) {
2603 len = strlen(expression);
2604 len--;
2605 while ((len >= 0) &&
2606 ((expression[len] == '\n') || (expression[len] == '\t') ||
2607 (expression[len] == '\r') || (expression[len] == ' '))) len--;
2608 expression[len + 1] = 0;
2609 if (len >= 0) {
2610 fprintf(xpathOutput,
2611 "\n========================\nExpression: %s\n",
2612 expression) ;
2613 testXPath(expression, xptr, expr);
2614 }
2615 }
2616
2617 fclose(input);
2618 fclose(xpathOutput);
2619 if (result != NULL) {
2620 ret = compareFiles(temp, result);
2621 if (ret) {
2622 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
2623 }
2624 }
2625
2626 if (temp != NULL) {
2627 unlink(temp);
2628 free(temp);
2629 }
2630 return(ret);
2631 }
2632
2633 /**
2634 * xpathExprTest:
2635 * @filename: the file to parse
2636 * @result: the file with expected result
2637 * @err: the file with error messages
2638 *
2639 * Parse a file containing XPath standalone expressions and evaluate them
2640 *
2641 * Returns 0 in case of success, an error code otherwise
2642 */
2643 static int
xpathExprTest(const char * filename,const char * result,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)2644 xpathExprTest(const char *filename, const char *result,
2645 const char *err ATTRIBUTE_UNUSED,
2646 int options ATTRIBUTE_UNUSED) {
2647 return(xpathCommonTest(filename, result, 0, 1));
2648 }
2649
2650 /**
2651 * xpathDocTest:
2652 * @filename: the file to parse
2653 * @result: the file with expected result
2654 * @err: the file with error messages
2655 *
2656 * Parse a file containing XPath expressions and evaluate them against
2657 * a set of corresponding documents.
2658 *
2659 * Returns 0 in case of success, an error code otherwise
2660 */
2661 static int
xpathDocTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options)2662 xpathDocTest(const char *filename,
2663 const char *resul ATTRIBUTE_UNUSED,
2664 const char *err ATTRIBUTE_UNUSED,
2665 int options) {
2666
2667 char pattern[500];
2668 char result[500];
2669 glob_t globbuf;
2670 size_t i;
2671 int ret = 0, res;
2672
2673 xpathDocument = xmlReadFile(filename, NULL,
2674 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2675 if (xpathDocument == NULL) {
2676 fprintf(stderr, "Failed to load %s\n", filename);
2677 return(-1);
2678 }
2679
2680 res = snprintf(pattern, 499, "./test/XPath/tests/%s*",
2681 baseFilename(filename));
2682 if (res >= 499)
2683 pattern[499] = 0;
2684 globbuf.gl_offs = 0;
2685 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2686 for (i = 0;i < globbuf.gl_pathc;i++) {
2687 res = snprintf(result, 499, "result/XPath/tests/%s",
2688 baseFilename(globbuf.gl_pathv[i]));
2689 if (res >= 499)
2690 result[499] = 0;
2691 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 0, 0);
2692 if (res != 0)
2693 ret = res;
2694 }
2695 globfree(&globbuf);
2696
2697 xmlFreeDoc(xpathDocument);
2698 return(ret);
2699 }
2700
2701 #ifdef LIBXML_XPTR_ENABLED
2702 /**
2703 * xptrDocTest:
2704 * @filename: the file to parse
2705 * @result: the file with expected result
2706 * @err: the file with error messages
2707 *
2708 * Parse a file containing XPath expressions and evaluate them against
2709 * a set of corresponding documents.
2710 *
2711 * Returns 0 in case of success, an error code otherwise
2712 */
2713 static int
xptrDocTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)2714 xptrDocTest(const char *filename,
2715 const char *resul ATTRIBUTE_UNUSED,
2716 const char *err ATTRIBUTE_UNUSED,
2717 int options ATTRIBUTE_UNUSED) {
2718
2719 char pattern[500];
2720 char result[500];
2721 glob_t globbuf;
2722 size_t i;
2723 int ret = 0, res;
2724
2725 xpathDocument = xmlReadFile(filename, NULL,
2726 XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2727 if (xpathDocument == NULL) {
2728 fprintf(stderr, "Failed to load %s\n", filename);
2729 return(-1);
2730 }
2731
2732 res = snprintf(pattern, 499, "./test/XPath/xptr/%s*",
2733 baseFilename(filename));
2734 if (res >= 499)
2735 pattern[499] = 0;
2736 globbuf.gl_offs = 0;
2737 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2738 for (i = 0;i < globbuf.gl_pathc;i++) {
2739 res = snprintf(result, 499, "result/XPath/xptr/%s",
2740 baseFilename(globbuf.gl_pathv[i]));
2741 if (res >= 499)
2742 result[499] = 0;
2743 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 1, 0);
2744 if (res != 0)
2745 ret = res;
2746 }
2747 globfree(&globbuf);
2748
2749 xmlFreeDoc(xpathDocument);
2750 return(ret);
2751 }
2752 #endif /* LIBXML_XPTR_ENABLED */
2753
2754 #ifdef LIBXML_VALID_ENABLED
2755 /**
2756 * xmlidDocTest:
2757 * @filename: the file to parse
2758 * @result: the file with expected result
2759 * @err: the file with error messages
2760 *
2761 * Parse a file containing xml:id and check for errors and verify
2762 * that XPath queries will work on them as expected.
2763 *
2764 * Returns 0 in case of success, an error code otherwise
2765 */
2766 static int
xmlidDocTest(const char * filename,const char * result,const char * err,int options)2767 xmlidDocTest(const char *filename,
2768 const char *result,
2769 const char *err,
2770 int options) {
2771 xmlParserCtxtPtr ctxt;
2772 int res = 0;
2773 int ret = 0;
2774 char *temp;
2775
2776 ctxt = xmlNewParserCtxt();
2777 xmlCtxtSetErrorHandler(ctxt, testStructuredErrorHandler, NULL);
2778 xpathDocument = xmlCtxtReadFile(ctxt, filename, NULL,
2779 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2780 xmlFreeParserCtxt(ctxt);
2781 if (xpathDocument == NULL) {
2782 fprintf(stderr, "Failed to load %s\n", filename);
2783 return(-1);
2784 }
2785
2786 temp = resultFilename(filename, temp_directory, ".res");
2787 if (temp == NULL) {
2788 fprintf(stderr, "Out of memory\n");
2789 fatalError();
2790 }
2791 xpathOutput = fopen(temp, "wb");
2792 if (xpathOutput == NULL) {
2793 fprintf(stderr, "failed to open output file %s\n", temp);
2794 xmlFreeDoc(xpathDocument);
2795 free(temp);
2796 return(-1);
2797 }
2798
2799 testXPath("id('bar')", 0, 0);
2800
2801 fclose(xpathOutput);
2802 if (result != NULL) {
2803 ret = compareFiles(temp, result);
2804 if (ret) {
2805 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
2806 res = 1;
2807 }
2808 }
2809
2810 if (temp != NULL) {
2811 unlink(temp);
2812 free(temp);
2813 }
2814 xmlFreeDoc(xpathDocument);
2815
2816 if (err != NULL) {
2817 ret = compareFileMem(err, testErrors, testErrorsSize);
2818 if (ret != 0) {
2819 fprintf(stderr, "Error for %s failed\n", filename);
2820 res = 1;
2821 }
2822 }
2823 return(res);
2824 }
2825 #endif /* LIBXML_VALID_ENABLED */
2826
2827 #endif /* LIBXML_DEBUG_ENABLED */
2828 #endif /* XPATH */
2829 /************************************************************************
2830 * *
2831 * URI based tests *
2832 * *
2833 ************************************************************************/
2834
2835 static void
handleURI(const char * str,const char * base,FILE * o)2836 handleURI(const char *str, const char *base, FILE *o) {
2837 int ret;
2838 xmlURIPtr uri;
2839 xmlChar *res = NULL;
2840
2841 uri = xmlCreateURI();
2842
2843 if (base == NULL) {
2844 ret = xmlParseURIReference(uri, str);
2845 if (ret != 0)
2846 fprintf(o, "%s : error %d\n", str, ret);
2847 else {
2848 xmlNormalizeURIPath(uri->path);
2849 xmlPrintURI(o, uri);
2850 fprintf(o, "\n");
2851 }
2852 } else {
2853 res = xmlBuildURI((xmlChar *)str, (xmlChar *) base);
2854 if (res != NULL) {
2855 fprintf(o, "%s\n", (char *) res);
2856 }
2857 else
2858 fprintf(o, "::ERROR::\n");
2859 }
2860 if (res != NULL)
2861 xmlFree(res);
2862 xmlFreeURI(uri);
2863 }
2864
2865 /**
2866 * uriCommonTest:
2867 * @filename: the file to parse
2868 * @result: the file with expected result
2869 * @err: the file with error messages
2870 *
2871 * Parse a file containing URI and check for errors
2872 *
2873 * Returns 0 in case of success, an error code otherwise
2874 */
2875 static int
uriCommonTest(const char * filename,const char * result,const char * err,const char * base)2876 uriCommonTest(const char *filename,
2877 const char *result,
2878 const char *err,
2879 const char *base) {
2880 char *temp;
2881 FILE *o, *f;
2882 char str[1024];
2883 int res = 0, i, ret;
2884
2885 temp = resultFilename(filename, temp_directory, ".res");
2886 if (temp == NULL) {
2887 fprintf(stderr, "Out of memory\n");
2888 fatalError();
2889 }
2890 o = fopen(temp, "wb");
2891 if (o == NULL) {
2892 fprintf(stderr, "failed to open output file %s\n", temp);
2893 free(temp);
2894 return(-1);
2895 }
2896 f = fopen(filename, "rb");
2897 if (f == NULL) {
2898 fprintf(stderr, "failed to open input file %s\n", filename);
2899 fclose(o);
2900 if (temp != NULL) {
2901 unlink(temp);
2902 free(temp);
2903 }
2904 return(-1);
2905 }
2906
2907 while (1) {
2908 /*
2909 * read one line in string buffer.
2910 */
2911 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
2912 break;
2913
2914 /*
2915 * remove the ending spaces
2916 */
2917 i = strlen(str);
2918 while ((i > 0) &&
2919 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
2920 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
2921 i--;
2922 str[i] = 0;
2923 }
2924 nb_tests++;
2925 handleURI(str, base, o);
2926 }
2927
2928 fclose(f);
2929 fclose(o);
2930
2931 if (result != NULL) {
2932 ret = compareFiles(temp, result);
2933 if (ret) {
2934 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
2935 res = 1;
2936 }
2937 }
2938 if (err != NULL) {
2939 ret = compareFileMem(err, testErrors, testErrorsSize);
2940 if (ret != 0) {
2941 fprintf(stderr, "Error for %s failed\n", filename);
2942 res = 1;
2943 }
2944 }
2945
2946 if (temp != NULL) {
2947 unlink(temp);
2948 free(temp);
2949 }
2950 return(res);
2951 }
2952
2953 /**
2954 * uriParseTest:
2955 * @filename: the file to parse
2956 * @result: the file with expected result
2957 * @err: the file with error messages
2958 *
2959 * Parse a file containing URI and check for errors
2960 *
2961 * Returns 0 in case of success, an error code otherwise
2962 */
2963 static int
uriParseTest(const char * filename,const char * result,const char * err,int options ATTRIBUTE_UNUSED)2964 uriParseTest(const char *filename,
2965 const char *result,
2966 const char *err,
2967 int options ATTRIBUTE_UNUSED) {
2968 return(uriCommonTest(filename, result, err, NULL));
2969 }
2970
2971 /**
2972 * uriBaseTest:
2973 * @filename: the file to parse
2974 * @result: the file with expected result
2975 * @err: the file with error messages
2976 *
2977 * Parse a file containing URI, compose them against a fixed base and
2978 * check for errors
2979 *
2980 * Returns 0 in case of success, an error code otherwise
2981 */
2982 static int
uriBaseTest(const char * filename,const char * result,const char * err,int options ATTRIBUTE_UNUSED)2983 uriBaseTest(const char *filename,
2984 const char *result,
2985 const char *err,
2986 int options ATTRIBUTE_UNUSED) {
2987 return(uriCommonTest(filename, result, err,
2988 "http://foo.com/path/to/index.html?orig#help"));
2989 }
2990
2991 static int urip_success = 1;
2992 static int urip_current = 0;
2993 static const char *urip_testURLs[] = {
2994 "urip://example.com/a b.html",
2995 "urip://example.com/a%20b.html",
2996 "file:///path/to/a b.html",
2997 "file:///path/to/a%20b.html",
2998 "/path/to/a b.html",
2999 "/path/to/a%20b.html",
3000 "urip://example.com/r" "\xe9" "sum" "\xe9" ".html",
3001 "urip://example.com/test?a=1&b=2%263&c=4#foo",
3002 NULL
3003 };
3004 static const char *urip_rcvsURLs[] = {
3005 /* it is an URI the strings must be escaped */
3006 "urip://example.com/a%20b.html",
3007 /* check that % escaping is not broken */
3008 "urip://example.com/a%20b.html",
3009 /* it's an URI path the strings must be escaped */
3010 "file:///path/to/a%20b.html",
3011 /* check that % escaping is not broken */
3012 "file:///path/to/a%20b.html",
3013 /* this is not an URI, this is a path, so this should not be escaped */
3014 "/path/to/a b.html",
3015 /* check that paths with % are not broken */
3016 "/path/to/a%20b.html",
3017 /* out of context the encoding can't be guessed byte by byte conversion */
3018 "urip://example.com/r%E9sum%E9.html",
3019 /* verify we don't destroy URIs especially the query part */
3020 "urip://example.com/test?a=1&b=2%263&c=4#foo",
3021 NULL
3022 };
3023 static const char *urip_res = "<list/>";
3024 static const char *urip_cur = NULL;
3025 static int urip_rlen;
3026
3027 /**
3028 * uripMatch:
3029 * @URI: an URI to test
3030 *
3031 * Check for an urip: query
3032 *
3033 * Returns 1 if yes and 0 if another Input module should be used
3034 */
3035 static int
uripMatch(const char * URI)3036 uripMatch(const char * URI) {
3037 if ((URI == NULL) || (!strcmp(URI, "file://" SYSCONFDIR "/xml/catalog")))
3038 return(0);
3039 /* Verify we received the escaped URL */
3040 if (strcmp(urip_rcvsURLs[urip_current], URI))
3041 urip_success = 0;
3042 return(1);
3043 }
3044
3045 /**
3046 * uripOpen:
3047 * @URI: an URI to test
3048 *
3049 * Return a pointer to the urip: query handler, in this example simply
3050 * the urip_current pointer...
3051 *
3052 * Returns an Input context or NULL in case or error
3053 */
3054 static void *
uripOpen(const char * URI)3055 uripOpen(const char * URI) {
3056 if ((URI == NULL) || (!strcmp(URI, "file://" SYSCONFDIR "/xml/catalog")))
3057 return(NULL);
3058 /* Verify we received the escaped URL */
3059 if (strcmp(urip_rcvsURLs[urip_current], URI))
3060 urip_success = 0;
3061 urip_cur = urip_res;
3062 urip_rlen = strlen(urip_res);
3063 return((void *) urip_cur);
3064 }
3065
3066 /**
3067 * uripClose:
3068 * @context: the read context
3069 *
3070 * Close the urip: query handler
3071 *
3072 * Returns 0 or -1 in case of error
3073 */
3074 static int
uripClose(void * context)3075 uripClose(void * context) {
3076 if (context == NULL) return(-1);
3077 urip_cur = NULL;
3078 urip_rlen = 0;
3079 return(0);
3080 }
3081
3082 /**
3083 * uripRead:
3084 * @context: the read context
3085 * @buffer: where to store data
3086 * @len: number of bytes to read
3087 *
3088 * Implement an urip: query read.
3089 *
3090 * Returns the number of bytes read or -1 in case of error
3091 */
3092 static int
uripRead(void * context,char * buffer,int len)3093 uripRead(void * context, char * buffer, int len) {
3094 const char *ptr = (const char *) context;
3095
3096 if ((context == NULL) || (buffer == NULL) || (len < 0))
3097 return(-1);
3098
3099 if (len > urip_rlen) len = urip_rlen;
3100 memcpy(buffer, ptr, len);
3101 urip_rlen -= len;
3102 return(len);
3103 }
3104
3105 static int
urip_checkURL(const char * URL)3106 urip_checkURL(const char *URL) {
3107 xmlDocPtr doc;
3108
3109 doc = xmlReadFile(URL, NULL, 0);
3110 if (doc == NULL)
3111 return(-1);
3112 xmlFreeDoc(doc);
3113 return(1);
3114 }
3115
3116 /**
3117 * uriPathTest:
3118 * @filename: ignored
3119 * @result: ignored
3120 * @err: ignored
3121 *
3122 * Run a set of tests to check how Path and URI are handled before
3123 * being passed to the I/O layer
3124 *
3125 * Returns 0 in case of success, an error code otherwise
3126 */
3127 static int
uriPathTest(const char * filename ATTRIBUTE_UNUSED,const char * result ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)3128 uriPathTest(const char *filename ATTRIBUTE_UNUSED,
3129 const char *result ATTRIBUTE_UNUSED,
3130 const char *err ATTRIBUTE_UNUSED,
3131 int options ATTRIBUTE_UNUSED) {
3132 int parsed;
3133 int failures = 0;
3134
3135 /*
3136 * register the new I/O handlers
3137 */
3138 if (xmlRegisterInputCallbacks(uripMatch, uripOpen, uripRead, uripClose) < 0)
3139 {
3140 fprintf(stderr, "failed to register HTTP handler\n");
3141 return(-1);
3142 }
3143
3144 for (urip_current = 0;urip_testURLs[urip_current] != NULL;urip_current++) {
3145 urip_success = 1;
3146 parsed = urip_checkURL(urip_testURLs[urip_current]);
3147 if (urip_success != 1) {
3148 fprintf(stderr, "failed the URL passing test for %s",
3149 urip_testURLs[urip_current]);
3150 failures++;
3151 } else if (parsed != 1) {
3152 fprintf(stderr, "failed the parsing test for %s",
3153 urip_testURLs[urip_current]);
3154 failures++;
3155 }
3156 nb_tests++;
3157 }
3158
3159 xmlPopInputCallbacks();
3160 return(failures);
3161 }
3162
3163 #ifdef LIBXML_SCHEMAS_ENABLED
3164 /************************************************************************
3165 * *
3166 * Schemas tests *
3167 * *
3168 ************************************************************************/
3169 static int
schemasOneTest(const char * sch,const char * filename,const char * result,const char * err,int options,xmlSchemaPtr schemas)3170 schemasOneTest(const char *sch,
3171 const char *filename,
3172 const char *result,
3173 const char *err,
3174 int options,
3175 xmlSchemaPtr schemas) {
3176 int ret = 0;
3177 int i;
3178 char *temp;
3179 int parseErrorsSize = testErrorsSize;
3180
3181 temp = resultFilename(result, temp_directory, ".res");
3182 if (temp == NULL) {
3183 fprintf(stderr, "Out of memory\n");
3184 fatalError();
3185 return(-1);
3186 }
3187
3188 /*
3189 * Test both memory and streaming validation.
3190 */
3191 for (i = 0; i < 2; i++) {
3192 xmlSchemaValidCtxtPtr ctxt;
3193 int validResult = 0;
3194 FILE *schemasOutput;
3195
3196 testErrorsSize = parseErrorsSize;
3197 testErrors[parseErrorsSize] = 0;
3198
3199 if (schemas == NULL)
3200 goto done;
3201
3202 ctxt = xmlSchemaNewValidCtxt(schemas);
3203 xmlSchemaSetValidStructuredErrors(ctxt, testStructuredErrorHandler,
3204 NULL);
3205
3206 schemasOutput = fopen(temp, "wb");
3207 if (schemasOutput == NULL) {
3208 fprintf(stderr, "failed to open output file %s\n", temp);
3209 free(temp);
3210 return(-1);
3211 }
3212
3213 if (i == 0) {
3214 xmlDocPtr doc;
3215
3216 doc = xmlReadFile(filename, NULL, options);
3217 if (doc == NULL) {
3218 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
3219 return(-1);
3220 }
3221 validResult = xmlSchemaValidateDoc(ctxt, doc);
3222 xmlFreeDoc(doc);
3223 } else {
3224 validResult = xmlSchemaValidateFile(ctxt, filename, options);
3225 }
3226
3227 if (validResult == 0) {
3228 fprintf(schemasOutput, "%s validates\n", filename);
3229 } else if (validResult > 0) {
3230 fprintf(schemasOutput, "%s fails to validate\n", filename);
3231 } else {
3232 fprintf(schemasOutput, "%s validation generated an internal error\n",
3233 filename);
3234 }
3235 fclose(schemasOutput);
3236
3237 if (result) {
3238 if (compareFiles(temp, result)) {
3239 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
3240 ret = 1;
3241 }
3242 }
3243
3244 xmlSchemaFreeValidCtxt(ctxt);
3245
3246 done:
3247 if (compareFileMem(err, testErrors, testErrorsSize)) {
3248 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
3249 ret = 1;
3250 }
3251
3252 unlink(temp);
3253 }
3254
3255 free(temp);
3256 return(ret);
3257 }
3258 /**
3259 * schemasTest:
3260 * @filename: the schemas file
3261 * @result: the file with expected result
3262 * @err: the file with error messages
3263 *
3264 * Parse a file containing URI, compose them against a fixed base and
3265 * check for errors
3266 *
3267 * Returns 0 in case of success, an error code otherwise
3268 */
3269 static int
schemasTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * errr ATTRIBUTE_UNUSED,int options)3270 schemasTest(const char *filename,
3271 const char *resul ATTRIBUTE_UNUSED,
3272 const char *errr ATTRIBUTE_UNUSED,
3273 int options) {
3274 const char *base = baseFilename(filename);
3275 const char *base2;
3276 const char *instance;
3277 xmlSchemaParserCtxtPtr ctxt;
3278 xmlSchemaPtr schemas;
3279 int res = 0, len, ret;
3280 int parseErrorsSize;
3281 char pattern[500];
3282 char prefix[500];
3283 char result[500];
3284 char err[500];
3285 glob_t globbuf;
3286 size_t i;
3287 char count = 0;
3288
3289 /* first compile the schemas if possible */
3290 ctxt = xmlSchemaNewParserCtxt(filename);
3291 xmlSchemaSetParserStructuredErrors(ctxt, testStructuredErrorHandler, NULL);
3292 schemas = xmlSchemaParse(ctxt);
3293 xmlSchemaFreeParserCtxt(ctxt);
3294 parseErrorsSize = testErrorsSize;
3295
3296 /*
3297 * most of the mess is about the output filenames generated by the Makefile
3298 */
3299 len = strlen(base);
3300 if ((len > 499) || (len < 5)) {
3301 xmlSchemaFree(schemas);
3302 return(-1);
3303 }
3304 len -= 4; /* remove trailing .xsd */
3305 if (base[len - 2] == '_') {
3306 len -= 2; /* remove subtest number */
3307 }
3308 if (base[len - 2] == '_') {
3309 len -= 2; /* remove subtest number */
3310 }
3311 memcpy(prefix, base, len);
3312 prefix[len] = 0;
3313
3314 if (snprintf(pattern, 499, "./test/schemas/%s_*.xml", prefix) >= 499)
3315 pattern[499] = 0;
3316
3317 if (base[len] == '_') {
3318 len += 2;
3319 memcpy(prefix, base, len);
3320 prefix[len] = 0;
3321 }
3322
3323 globbuf.gl_offs = 0;
3324 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3325 for (i = 0;i < globbuf.gl_pathc;i++) {
3326 testErrorsSize = parseErrorsSize;
3327 testErrors[parseErrorsSize] = 0;
3328 instance = globbuf.gl_pathv[i];
3329 base2 = baseFilename(instance);
3330 len = strlen(base2);
3331 if ((len > 6) && (base2[len - 6] == '_')) {
3332 count = base2[len - 5];
3333 ret = snprintf(result, 499, "result/schemas/%s_%c",
3334 prefix, count);
3335 if (ret >= 499)
3336 result[499] = 0;
3337 ret = snprintf(err, 499, "result/schemas/%s_%c.err",
3338 prefix, count);
3339 if (ret >= 499)
3340 err[499] = 0;
3341 } else {
3342 fprintf(stderr, "don't know how to process %s\n", instance);
3343 continue;
3344 }
3345
3346 nb_tests++;
3347 ret = schemasOneTest(filename, instance, result, err,
3348 options, schemas);
3349 if (ret != 0)
3350 res = ret;
3351 }
3352 globfree(&globbuf);
3353 xmlSchemaFree(schemas);
3354
3355 return(res);
3356 }
3357
3358 /************************************************************************
3359 * *
3360 * Schemas tests *
3361 * *
3362 ************************************************************************/
3363 static int
rngOneTest(const char * sch,const char * filename,const char * result,int options,xmlRelaxNGPtr schemas)3364 rngOneTest(const char *sch,
3365 const char *filename,
3366 const char *result,
3367 int options,
3368 xmlRelaxNGPtr schemas) {
3369 xmlDocPtr doc;
3370 xmlRelaxNGValidCtxtPtr ctxt;
3371 int ret = 0;
3372 char *temp;
3373 FILE *schemasOutput;
3374
3375 doc = xmlReadFile(filename, NULL, options);
3376 if (doc == NULL) {
3377 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
3378 return(-1);
3379 }
3380
3381 temp = resultFilename(result, temp_directory, ".res");
3382 if (temp == NULL) {
3383 fprintf(stderr, "Out of memory\n");
3384 fatalError();
3385 }
3386 schemasOutput = fopen(temp, "wb");
3387 if (schemasOutput == NULL) {
3388 fprintf(stderr, "failed to open output file %s\n", temp);
3389 xmlFreeDoc(doc);
3390 free(temp);
3391 return(-1);
3392 }
3393
3394 ctxt = xmlRelaxNGNewValidCtxt(schemas);
3395 xmlRelaxNGSetValidStructuredErrors(ctxt, testStructuredErrorHandler, NULL);
3396 ret = xmlRelaxNGValidateDoc(ctxt, doc);
3397 if (ret == 0) {
3398 testErrorHandler(NULL, "%s validates\n", filename);
3399 } else if (ret > 0) {
3400 testErrorHandler(NULL, "%s fails to validate\n", filename);
3401 } else {
3402 testErrorHandler(NULL, "%s validation generated an internal error\n",
3403 filename);
3404 }
3405 fclose(schemasOutput);
3406 ret = 0;
3407 if (result) {
3408 if (compareFiles(temp, result)) {
3409 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
3410 ret = 1;
3411 }
3412 }
3413 if (temp != NULL) {
3414 unlink(temp);
3415 free(temp);
3416 }
3417
3418 xmlRelaxNGFreeValidCtxt(ctxt);
3419 xmlFreeDoc(doc);
3420 return(ret);
3421 }
3422 /**
3423 * rngTest:
3424 * @filename: the schemas file
3425 * @result: the file with expected result
3426 * @err: the file with error messages
3427 *
3428 * Parse an RNG schemas and then apply it to the related .xml
3429 *
3430 * Returns 0 in case of success, an error code otherwise
3431 */
3432 static int
rngTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * errr ATTRIBUTE_UNUSED,int options)3433 rngTest(const char *filename,
3434 const char *resul ATTRIBUTE_UNUSED,
3435 const char *errr ATTRIBUTE_UNUSED,
3436 int options) {
3437 const char *base = baseFilename(filename);
3438 const char *base2;
3439 const char *instance;
3440 xmlRelaxNGParserCtxtPtr ctxt;
3441 xmlRelaxNGPtr schemas;
3442 int res = 0, len, ret = 0;
3443 int parseErrorsSize;
3444 char pattern[500];
3445 char prefix[500];
3446 char result[500];
3447 char err[500];
3448 glob_t globbuf;
3449 size_t i;
3450 char count = 0;
3451
3452 /* first compile the schemas if possible */
3453 ctxt = xmlRelaxNGNewParserCtxt(filename);
3454 xmlRelaxNGSetParserStructuredErrors(ctxt, testStructuredErrorHandler,
3455 NULL);
3456 schemas = xmlRelaxNGParse(ctxt);
3457 xmlRelaxNGFreeParserCtxt(ctxt);
3458 if (schemas == NULL)
3459 testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n",
3460 filename);
3461 parseErrorsSize = testErrorsSize;
3462
3463 /*
3464 * most of the mess is about the output filenames generated by the Makefile
3465 */
3466 len = strlen(base);
3467 if ((len > 499) || (len < 5)) {
3468 xmlRelaxNGFree(schemas);
3469 return(-1);
3470 }
3471 len -= 4; /* remove trailing .rng */
3472 memcpy(prefix, base, len);
3473 prefix[len] = 0;
3474
3475 if (snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix) >= 499)
3476 pattern[499] = 0;
3477
3478 globbuf.gl_offs = 0;
3479 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3480 for (i = 0;i < globbuf.gl_pathc;i++) {
3481 testErrorsSize = parseErrorsSize;
3482 testErrors[parseErrorsSize] = 0;
3483 instance = globbuf.gl_pathv[i];
3484 base2 = baseFilename(instance);
3485 len = strlen(base2);
3486 if ((len > 6) && (base2[len - 6] == '_')) {
3487 count = base2[len - 5];
3488 res = snprintf(result, 499, "result/relaxng/%s_%c",
3489 prefix, count);
3490 if (res >= 499)
3491 result[499] = 0;
3492 res = snprintf(err, 499, "result/relaxng/%s_%c.err",
3493 prefix, count);
3494 if (res >= 499)
3495 err[499] = 0;
3496 } else {
3497 fprintf(stderr, "don't know how to process %s\n", instance);
3498 continue;
3499 }
3500 if (schemas != NULL) {
3501 nb_tests++;
3502 res = rngOneTest(filename, instance, result, options, schemas);
3503 if (res != 0)
3504 ret = res;
3505 }
3506 if (compareFileMem(err, testErrors, testErrorsSize)) {
3507 fprintf(stderr, "Error for %s on %s failed\n", instance,
3508 filename);
3509 ret = 1;
3510 }
3511 }
3512 globfree(&globbuf);
3513 xmlRelaxNGFree(schemas);
3514
3515 return(ret);
3516 }
3517
3518 #ifdef LIBXML_READER_ENABLED
3519 /**
3520 * rngStreamTest:
3521 * @filename: the schemas file
3522 * @result: the file with expected result
3523 * @err: the file with error messages
3524 *
3525 * Parse a set of files with streaming, applying an RNG schemas
3526 *
3527 * Returns 0 in case of success, an error code otherwise
3528 */
3529 static int
rngStreamTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * errr ATTRIBUTE_UNUSED,int options)3530 rngStreamTest(const char *filename,
3531 const char *resul ATTRIBUTE_UNUSED,
3532 const char *errr ATTRIBUTE_UNUSED,
3533 int options) {
3534 const char *base = baseFilename(filename);
3535 const char *base2;
3536 const char *instance;
3537 int res = 0, len, ret;
3538 char pattern[500];
3539 char prefix[500];
3540 char result[500];
3541 char err[500];
3542 glob_t globbuf;
3543 size_t i;
3544 char count = 0;
3545 xmlTextReaderPtr reader;
3546 int disable_err = 0;
3547
3548 /*
3549 * most of the mess is about the output filenames generated by the Makefile
3550 */
3551 len = strlen(base);
3552 if ((len > 499) || (len < 5)) {
3553 fprintf(stderr, "len(base) == %d !\n", len);
3554 return(-1);
3555 }
3556 len -= 4; /* remove trailing .rng */
3557 memcpy(prefix, base, len);
3558 prefix[len] = 0;
3559
3560 /*
3561 * strictly unifying the error messages is nearly impossible this
3562 * hack is also done in the Makefile
3563 */
3564 if ((!strcmp(prefix, "tutor10_1")) || (!strcmp(prefix, "tutor10_2")) ||
3565 (!strcmp(prefix, "tutor3_2")) || (!strcmp(prefix, "307377")) ||
3566 (!strcmp(prefix, "tutor8_2")))
3567 disable_err = 1;
3568
3569 if (snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix) >= 499)
3570 pattern[499] = 0;
3571
3572 globbuf.gl_offs = 0;
3573 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3574 for (i = 0;i < globbuf.gl_pathc;i++) {
3575 testErrorsSize = 0;
3576 testErrors[0] = 0;
3577 instance = globbuf.gl_pathv[i];
3578 base2 = baseFilename(instance);
3579 len = strlen(base2);
3580 if ((len > 6) && (base2[len - 6] == '_')) {
3581 count = base2[len - 5];
3582 ret = snprintf(result, 499, "result/relaxng/%s_%c",
3583 prefix, count);
3584 if (ret >= 499)
3585 result[499] = 0;
3586 ret = snprintf(err, 499, "result/relaxng/%s_%c.err",
3587 prefix, count);
3588 if (ret >= 499)
3589 err[499] = 0;
3590 } else {
3591 fprintf(stderr, "don't know how to process %s\n", instance);
3592 continue;
3593 }
3594 reader = xmlReaderForFile(instance, NULL, options);
3595 xmlTextReaderSetStructuredErrorHandler(reader,
3596 testStructuredErrorHandler, NULL);
3597 if (reader == NULL) {
3598 fprintf(stderr, "Failed to build reader for %s\n", instance);
3599 }
3600 if (disable_err == 1)
3601 ret = streamProcessTest(instance, result, NULL, reader, filename,
3602 options);
3603 else
3604 ret = streamProcessTest(instance, result, err, reader, filename,
3605 options);
3606 xmlFreeTextReader(reader);
3607 if (ret != 0) {
3608 fprintf(stderr, "instance %s failed\n", instance);
3609 res = ret;
3610 }
3611 }
3612 globfree(&globbuf);
3613
3614 return(res);
3615 }
3616 #endif /* READER */
3617
3618 #endif
3619
3620 #ifdef LIBXML_PATTERN_ENABLED
3621 #ifdef LIBXML_READER_ENABLED
3622 /************************************************************************
3623 * *
3624 * Patterns tests *
3625 * *
3626 ************************************************************************/
patternNode(FILE * out,xmlTextReaderPtr reader,const char * pattern,xmlPatternPtr patternc,xmlStreamCtxtPtr patstream)3627 static void patternNode(FILE *out, xmlTextReaderPtr reader,
3628 const char *pattern, xmlPatternPtr patternc,
3629 xmlStreamCtxtPtr patstream) {
3630 xmlChar *path = NULL;
3631 int match = -1;
3632 int type, empty;
3633
3634 type = xmlTextReaderNodeType(reader);
3635 empty = xmlTextReaderIsEmptyElement(reader);
3636
3637 if (type == XML_READER_TYPE_ELEMENT) {
3638 /* do the check only on element start */
3639 match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader));
3640
3641 if (match) {
3642 path = xmlGetNodePath(xmlTextReaderCurrentNode(reader));
3643 fprintf(out, "Node %s matches pattern %s\n", path, pattern);
3644 }
3645 }
3646 if (patstream != NULL) {
3647 int ret;
3648
3649 if (type == XML_READER_TYPE_ELEMENT) {
3650 ret = xmlStreamPush(patstream,
3651 xmlTextReaderConstLocalName(reader),
3652 xmlTextReaderConstNamespaceUri(reader));
3653 if (ret < 0) {
3654 fprintf(out, "xmlStreamPush() failure\n");
3655 xmlFreeStreamCtxt(patstream);
3656 patstream = NULL;
3657 } else if (ret != match) {
3658 if (path == NULL) {
3659 path = xmlGetNodePath(
3660 xmlTextReaderCurrentNode(reader));
3661 }
3662 fprintf(out,
3663 "xmlPatternMatch and xmlStreamPush disagree\n");
3664 fprintf(out,
3665 " pattern %s node %s\n",
3666 pattern, path);
3667 }
3668
3669
3670 }
3671 if ((type == XML_READER_TYPE_END_ELEMENT) ||
3672 ((type == XML_READER_TYPE_ELEMENT) && (empty))) {
3673 ret = xmlStreamPop(patstream);
3674 if (ret < 0) {
3675 fprintf(out, "xmlStreamPop() failure\n");
3676 xmlFreeStreamCtxt(patstream);
3677 patstream = NULL;
3678 }
3679 }
3680 }
3681 if (path != NULL)
3682 xmlFree(path);
3683 }
3684
3685 /**
3686 * patternTest:
3687 * @filename: the schemas file
3688 * @result: the file with expected result
3689 * @err: the file with error messages
3690 *
3691 * Parse a set of files with streaming, applying an RNG schemas
3692 *
3693 * Returns 0 in case of success, an error code otherwise
3694 */
3695 static int
patternTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options)3696 patternTest(const char *filename,
3697 const char *resul ATTRIBUTE_UNUSED,
3698 const char *err ATTRIBUTE_UNUSED,
3699 int options) {
3700 xmlPatternPtr patternc = NULL;
3701 xmlStreamCtxtPtr patstream = NULL;
3702 FILE *o, *f;
3703 char str[1024];
3704 char xml[500];
3705 char result[500];
3706 int len, i;
3707 int ret = 0, res;
3708 char *temp;
3709 xmlTextReaderPtr reader;
3710 xmlDocPtr doc;
3711
3712 len = strlen(filename);
3713 len -= 4;
3714 memcpy(xml, filename, len);
3715 xml[len] = 0;
3716 if (snprintf(result, 499, "result/pattern/%s", baseFilename(xml)) >= 499)
3717 result[499] = 0;
3718 memcpy(xml + len, ".xml", 5);
3719
3720 if (!checkTestFile(xml) && !update_results) {
3721 fprintf(stderr, "Missing xml file %s\n", xml);
3722 return(-1);
3723 }
3724 f = fopen(filename, "rb");
3725 if (f == NULL) {
3726 fprintf(stderr, "Failed to open %s\n", filename);
3727 return(-1);
3728 }
3729 temp = resultFilename(filename, temp_directory, ".res");
3730 if (temp == NULL) {
3731 fprintf(stderr, "Out of memory\n");
3732 fatalError();
3733 }
3734 o = fopen(temp, "wb");
3735 if (o == NULL) {
3736 fprintf(stderr, "failed to open output file %s\n", temp);
3737 fclose(f);
3738 free(temp);
3739 return(-1);
3740 }
3741 while (1) {
3742 /*
3743 * read one line in string buffer.
3744 */
3745 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
3746 break;
3747
3748 /*
3749 * remove the ending spaces
3750 */
3751 i = strlen(str);
3752 while ((i > 0) &&
3753 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
3754 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
3755 i--;
3756 str[i] = 0;
3757 }
3758 doc = xmlReadFile(xml, NULL, options);
3759 if (doc == NULL) {
3760 fprintf(stderr, "Failed to parse %s\n", xml);
3761 ret = 1;
3762 } else {
3763 xmlNodePtr root;
3764 const xmlChar *namespaces[22];
3765 int j;
3766 xmlNsPtr ns;
3767
3768 root = xmlDocGetRootElement(doc);
3769 for (ns = root->nsDef, j = 0;ns != NULL && j < 20;ns=ns->next) {
3770 namespaces[j++] = ns->href;
3771 namespaces[j++] = ns->prefix;
3772 }
3773 namespaces[j++] = NULL;
3774 namespaces[j] = NULL;
3775
3776 patternc = xmlPatterncompile((const xmlChar *) str, doc->dict,
3777 0, &namespaces[0]);
3778 if (patternc == NULL) {
3779 testErrorHandler(NULL,
3780 "Pattern %s failed to compile\n", str);
3781 xmlFreeDoc(doc);
3782 ret = 1;
3783 continue;
3784 }
3785 patstream = xmlPatternGetStreamCtxt(patternc);
3786 if (patstream != NULL) {
3787 ret = xmlStreamPush(patstream, NULL, NULL);
3788 if (ret < 0) {
3789 fprintf(stderr, "xmlStreamPush() failure\n");
3790 xmlFreeStreamCtxt(patstream);
3791 patstream = NULL;
3792 }
3793 }
3794 nb_tests++;
3795
3796 reader = xmlReaderWalker(doc);
3797 res = xmlTextReaderRead(reader);
3798 while (res == 1) {
3799 patternNode(o, reader, str, patternc, patstream);
3800 res = xmlTextReaderRead(reader);
3801 }
3802 if (res != 0) {
3803 fprintf(o, "%s : failed to parse\n", filename);
3804 }
3805 xmlFreeTextReader(reader);
3806 xmlFreeDoc(doc);
3807 xmlFreeStreamCtxt(patstream);
3808 patstream = NULL;
3809 xmlFreePattern(patternc);
3810
3811 }
3812 }
3813
3814 fclose(f);
3815 fclose(o);
3816
3817 ret = compareFiles(temp, result);
3818 if (ret) {
3819 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
3820 ret = 1;
3821 }
3822 if (temp != NULL) {
3823 unlink(temp);
3824 free(temp);
3825 }
3826 return(ret);
3827 }
3828 #endif /* READER */
3829 #endif /* PATTERN */
3830 #ifdef LIBXML_C14N_ENABLED
3831 /************************************************************************
3832 * *
3833 * Canonicalization tests *
3834 * *
3835 ************************************************************************/
3836 static xmlXPathObjectPtr
load_xpath_expr(xmlDocPtr parent_doc,const char * filename)3837 load_xpath_expr (xmlDocPtr parent_doc, const char* filename) {
3838 xmlXPathObjectPtr xpath;
3839 xmlDocPtr doc;
3840 xmlChar *expr;
3841 xmlXPathContextPtr ctx;
3842 xmlNodePtr node;
3843 xmlNsPtr ns;
3844
3845 /*
3846 * load XPath expr as a file
3847 */
3848 doc = xmlReadFile(filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
3849 if (doc == NULL) {
3850 fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
3851 return(NULL);
3852 }
3853
3854 /*
3855 * Check the document is of the right kind
3856 */
3857 if(xmlDocGetRootElement(doc) == NULL) {
3858 fprintf(stderr,"Error: empty document for file \"%s\"\n", filename);
3859 xmlFreeDoc(doc);
3860 return(NULL);
3861 }
3862
3863 node = doc->children;
3864 while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) {
3865 node = node->next;
3866 }
3867
3868 if(node == NULL) {
3869 fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename);
3870 xmlFreeDoc(doc);
3871 return(NULL);
3872 }
3873
3874 expr = xmlNodeGetContent(node);
3875 if(expr == NULL) {
3876 fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename);
3877 xmlFreeDoc(doc);
3878 return(NULL);
3879 }
3880
3881 ctx = xmlXPathNewContext(parent_doc);
3882 if(ctx == NULL) {
3883 fprintf(stderr,"Error: unable to create new context\n");
3884 xmlFree(expr);
3885 xmlFreeDoc(doc);
3886 return(NULL);
3887 }
3888
3889 /*
3890 * Register namespaces
3891 */
3892 ns = node->nsDef;
3893 while(ns != NULL) {
3894 if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) {
3895 fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", ns->prefix, ns->href);
3896 xmlFree(expr);
3897 xmlXPathFreeContext(ctx);
3898 xmlFreeDoc(doc);
3899 return(NULL);
3900 }
3901 ns = ns->next;
3902 }
3903
3904 /*
3905 * Evaluate xpath
3906 */
3907 xpath = xmlXPathEvalExpression(expr, ctx);
3908 if(xpath == NULL) {
3909 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3910 xmlFree(expr);
3911 xmlXPathFreeContext(ctx);
3912 xmlFreeDoc(doc);
3913 return(NULL);
3914 }
3915
3916 /* print_xpath_nodes(xpath->nodesetval); */
3917
3918 xmlFree(expr);
3919 xmlXPathFreeContext(ctx);
3920 xmlFreeDoc(doc);
3921 return(xpath);
3922 }
3923
3924 /*
3925 * Macro used to grow the current buffer.
3926 */
3927 #define xxx_growBufferReentrant() { \
3928 buffer_size *= 2; \
3929 buffer = (xmlChar **) \
3930 xmlRealloc(buffer, buffer_size * sizeof(xmlChar*)); \
3931 if (buffer == NULL) { \
3932 perror("realloc failed"); \
3933 return(NULL); \
3934 } \
3935 }
3936
3937 static xmlChar **
parse_list(xmlChar * str)3938 parse_list(xmlChar *str) {
3939 xmlChar **buffer;
3940 xmlChar **out = NULL;
3941 int buffer_size = 0;
3942 int len;
3943
3944 if(str == NULL) {
3945 return(NULL);
3946 }
3947
3948 len = xmlStrlen(str);
3949 if((str[0] == '\'') && (str[len - 1] == '\'')) {
3950 str[len - 1] = '\0';
3951 str++;
3952 }
3953 /*
3954 * allocate an translation buffer.
3955 */
3956 buffer_size = 1000;
3957 buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*));
3958 if (buffer == NULL) {
3959 perror("malloc failed");
3960 return(NULL);
3961 }
3962 out = buffer;
3963
3964 while(*str != '\0') {
3965 if (out - buffer > buffer_size - 10) {
3966 int indx = out - buffer;
3967
3968 xxx_growBufferReentrant();
3969 out = &buffer[indx];
3970 }
3971 (*out++) = str;
3972 while(*str != ',' && *str != '\0') ++str;
3973 if(*str == ',') *(str++) = '\0';
3974 }
3975 (*out) = NULL;
3976 return buffer;
3977 }
3978
3979 static int
c14nRunTest(const char * xml_filename,int with_comments,int mode,const char * xpath_filename,const char * ns_filename,const char * result_file)3980 c14nRunTest(const char* xml_filename, int with_comments, int mode,
3981 const char* xpath_filename, const char *ns_filename,
3982 const char* result_file) {
3983 xmlDocPtr doc;
3984 xmlXPathObjectPtr xpath = NULL;
3985 xmlChar *result = NULL;
3986 int ret;
3987 xmlChar **inclusive_namespaces = NULL;
3988 const char *nslist = NULL;
3989 int nssize;
3990
3991
3992 /*
3993 * build an XML tree from a the file; we need to add default
3994 * attributes and resolve all character and entities references
3995 */
3996 doc = xmlReadFile(xml_filename, NULL,
3997 XML_PARSE_DTDATTR | XML_PARSE_NOENT | XML_PARSE_NOWARNING);
3998 if (doc == NULL) {
3999 fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename);
4000 return(-1);
4001 }
4002
4003 /*
4004 * Check the document is of the right kind
4005 */
4006 if(xmlDocGetRootElement(doc) == NULL) {
4007 fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename);
4008 xmlFreeDoc(doc);
4009 return(-1);
4010 }
4011
4012 /*
4013 * load xpath file if specified
4014 */
4015 if(xpath_filename) {
4016 xpath = load_xpath_expr(doc, xpath_filename);
4017 if(xpath == NULL) {
4018 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
4019 xmlFreeDoc(doc);
4020 return(-1);
4021 }
4022 }
4023
4024 if (ns_filename != NULL) {
4025 if (loadMem(ns_filename, &nslist, &nssize)) {
4026 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
4027 if(xpath != NULL) xmlXPathFreeObject(xpath);
4028 xmlFreeDoc(doc);
4029 return(-1);
4030 }
4031 inclusive_namespaces = parse_list((xmlChar *) nslist);
4032 }
4033
4034 /*
4035 * Canonical form
4036 */
4037 /* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */
4038 ret = xmlC14NDocDumpMemory(doc,
4039 (xpath) ? xpath->nodesetval : NULL,
4040 mode, inclusive_namespaces,
4041 with_comments, &result);
4042 if (ret >= 0) {
4043 if(result != NULL) {
4044 if (compareFileMem(result_file, (const char *) result, ret)) {
4045 fprintf(stderr, "Result mismatch for %s\n", xml_filename);
4046 fprintf(stderr, "RESULT:\n%s\n", (const char*)result);
4047 ret = -1;
4048 }
4049 }
4050 } else {
4051 fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret);
4052 ret = -1;
4053 }
4054
4055 /*
4056 * Cleanup
4057 */
4058 if (result != NULL) xmlFree(result);
4059 if(xpath != NULL) xmlXPathFreeObject(xpath);
4060 if (inclusive_namespaces != NULL) xmlFree(inclusive_namespaces);
4061 if (nslist != NULL) free((char *) nslist);
4062 xmlFreeDoc(doc);
4063
4064 return(ret);
4065 }
4066
4067 static int
c14nCommonTest(const char * filename,int with_comments,int mode,const char * subdir)4068 c14nCommonTest(const char *filename, int with_comments, int mode,
4069 const char *subdir) {
4070 char buf[500];
4071 char prefix[500];
4072 const char *base;
4073 int len;
4074 char *result = NULL;
4075 char *xpath = NULL;
4076 char *ns = NULL;
4077 int ret = 0;
4078
4079 base = baseFilename(filename);
4080 len = strlen(base);
4081 len -= 4;
4082 memcpy(prefix, base, len);
4083 prefix[len] = 0;
4084
4085 if (snprintf(buf, 499, "result/c14n/%s/%s", subdir, prefix) >= 499)
4086 buf[499] = 0;
4087 result = strdup(buf);
4088 if (snprintf(buf, 499, "test/c14n/%s/%s.xpath", subdir, prefix) >= 499)
4089 buf[499] = 0;
4090 if (checkTestFile(buf)) {
4091 xpath = strdup(buf);
4092 }
4093 if (snprintf(buf, 499, "test/c14n/%s/%s.ns", subdir, prefix) >= 499)
4094 buf[499] = 0;
4095 if (checkTestFile(buf)) {
4096 ns = strdup(buf);
4097 }
4098
4099 nb_tests++;
4100 if (c14nRunTest(filename, with_comments, mode,
4101 xpath, ns, result) < 0)
4102 ret = 1;
4103
4104 if (result != NULL) free(result);
4105 if (xpath != NULL) free(xpath);
4106 if (ns != NULL) free(ns);
4107 return(ret);
4108 }
4109
4110 static int
c14nWithCommentTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)4111 c14nWithCommentTest(const char *filename,
4112 const char *resul ATTRIBUTE_UNUSED,
4113 const char *err ATTRIBUTE_UNUSED,
4114 int options ATTRIBUTE_UNUSED) {
4115 return(c14nCommonTest(filename, 1, XML_C14N_1_0, "with-comments"));
4116 }
4117 static int
c14nWithoutCommentTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)4118 c14nWithoutCommentTest(const char *filename,
4119 const char *resul ATTRIBUTE_UNUSED,
4120 const char *err ATTRIBUTE_UNUSED,
4121 int options ATTRIBUTE_UNUSED) {
4122 return(c14nCommonTest(filename, 0, XML_C14N_1_0, "without-comments"));
4123 }
4124 static int
c14nExcWithoutCommentTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)4125 c14nExcWithoutCommentTest(const char *filename,
4126 const char *resul ATTRIBUTE_UNUSED,
4127 const char *err ATTRIBUTE_UNUSED,
4128 int options ATTRIBUTE_UNUSED) {
4129 return(c14nCommonTest(filename, 0, XML_C14N_EXCLUSIVE_1_0, "exc-without-comments"));
4130 }
4131 static int
c14n11WithoutCommentTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)4132 c14n11WithoutCommentTest(const char *filename,
4133 const char *resul ATTRIBUTE_UNUSED,
4134 const char *err ATTRIBUTE_UNUSED,
4135 int options ATTRIBUTE_UNUSED) {
4136 return(c14nCommonTest(filename, 0, XML_C14N_1_1, "1-1-without-comments"));
4137 }
4138 #endif
4139 #if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
4140 /************************************************************************
4141 * *
4142 * Catalog and threads test *
4143 * *
4144 ************************************************************************/
4145
4146 /*
4147 * mostly a cut and paste from testThreads.c
4148 */
4149 #define MAX_ARGC 20
4150
4151 typedef struct {
4152 const char *filename;
4153 int okay;
4154 } xmlThreadParams;
4155
4156 static const char *catalog = "test/threads/complex.xml";
4157 static xmlThreadParams threadParams[] = {
4158 { "test/threads/abc.xml", 0 },
4159 { "test/threads/acb.xml", 0 },
4160 { "test/threads/bac.xml", 0 },
4161 { "test/threads/bca.xml", 0 },
4162 { "test/threads/cab.xml", 0 },
4163 { "test/threads/cba.xml", 0 },
4164 { "test/threads/invalid.xml", 0 }
4165 };
4166 static const unsigned int num_threads = sizeof(threadParams) /
4167 sizeof(threadParams[0]);
4168
4169 static void *
thread_specific_data(void * private_data)4170 thread_specific_data(void *private_data)
4171 {
4172 xmlDocPtr myDoc;
4173 xmlThreadParams *params = (xmlThreadParams *) private_data;
4174 const char *filename = params->filename;
4175 int okay = 1;
4176
4177 #ifdef LIBXML_THREAD_ALLOC_ENABLED
4178 xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
4179 #endif
4180
4181 myDoc = xmlReadFile(filename, NULL, XML_PARSE_NOENT | XML_PARSE_DTDLOAD);
4182 if (myDoc) {
4183 xmlFreeDoc(myDoc);
4184 } else {
4185 printf("parse failed\n");
4186 okay = 0;
4187 }
4188 params->okay = okay;
4189 return(NULL);
4190 }
4191
4192 #if defined(_WIN32)
4193 #include <windows.h>
4194 #include <string.h>
4195
4196 #define TEST_REPEAT_COUNT 500
4197
4198 static HANDLE tid[MAX_ARGC];
4199
4200 static DWORD WINAPI
win32_thread_specific_data(void * private_data)4201 win32_thread_specific_data(void *private_data)
4202 {
4203 thread_specific_data(private_data);
4204 return(0);
4205 }
4206
4207 static int
testThread(void)4208 testThread(void)
4209 {
4210 unsigned int i, repeat;
4211 BOOL ret;
4212 int res = 0;
4213
4214 xmlInitParser();
4215 for (repeat = 0; repeat < TEST_REPEAT_COUNT; repeat++) {
4216 xmlLoadCatalog(catalog);
4217 nb_tests++;
4218
4219 for (i = 0; i < num_threads; i++) {
4220 tid[i] = (HANDLE) - 1;
4221 }
4222
4223 for (i = 0; i < num_threads; i++) {
4224 DWORD useless;
4225
4226 tid[i] = CreateThread(NULL, 0,
4227 win32_thread_specific_data,
4228 (void *) &threadParams[i], 0,
4229 &useless);
4230 if (tid[i] == NULL) {
4231 fprintf(stderr, "CreateThread failed\n");
4232 return(1);
4233 }
4234 }
4235
4236 if (WaitForMultipleObjects(num_threads, tid, TRUE, INFINITE) ==
4237 WAIT_FAILED) {
4238 fprintf(stderr, "WaitForMultipleObjects failed\n");
4239 return(1);
4240 }
4241
4242 for (i = 0; i < num_threads; i++) {
4243 DWORD exitCode;
4244 ret = GetExitCodeThread(tid[i], &exitCode);
4245 if (ret == 0) {
4246 fprintf(stderr, "GetExitCodeThread failed\n");
4247 return(1);
4248 }
4249 CloseHandle(tid[i]);
4250 }
4251
4252 xmlCatalogCleanup();
4253 for (i = 0; i < num_threads; i++) {
4254 if (threadParams[i].okay == 0) {
4255 fprintf(stderr, "Thread %d handling %s failed\n",
4256 i, threadParams[i].filename);
4257 res = 1;
4258 }
4259 }
4260 }
4261
4262 return (res);
4263 }
4264
4265 #elif defined HAVE_PTHREAD_H
4266 #include <pthread.h>
4267
4268 static pthread_t tid[MAX_ARGC];
4269
4270 static int
testThread(void)4271 testThread(void)
4272 {
4273 unsigned int i, repeat;
4274 int ret;
4275 int res = 0;
4276
4277 xmlInitParser();
4278
4279 for (repeat = 0; repeat < 500; repeat++) {
4280 xmlLoadCatalog(catalog);
4281 nb_tests++;
4282
4283 for (i = 0; i < num_threads; i++) {
4284 tid[i] = (pthread_t) - 1;
4285 }
4286
4287 for (i = 0; i < num_threads; i++) {
4288 ret = pthread_create(&tid[i], 0, thread_specific_data,
4289 (void *) &threadParams[i]);
4290 if (ret != 0) {
4291 fprintf(stderr, "pthread_create failed\n");
4292 return (1);
4293 }
4294 }
4295 for (i = 0; i < num_threads; i++) {
4296 void *result;
4297 ret = pthread_join(tid[i], &result);
4298 if (ret != 0) {
4299 fprintf(stderr, "pthread_join failed\n");
4300 return (1);
4301 }
4302 }
4303
4304 xmlCatalogCleanup();
4305 for (i = 0; i < num_threads; i++)
4306 if (threadParams[i].okay == 0) {
4307 fprintf(stderr, "Thread %d handling %s failed\n",
4308 i, threadParams[i].filename);
4309 res = 1;
4310 }
4311 }
4312 return (res);
4313 }
4314
4315 #else
4316 static int
testThread(void)4317 testThread(void)
4318 {
4319 fprintf(stderr,
4320 "Specific platform thread support not detected\n");
4321 return (-1);
4322 }
4323 #endif
4324 static int
threadsTest(const char * filename ATTRIBUTE_UNUSED,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)4325 threadsTest(const char *filename ATTRIBUTE_UNUSED,
4326 const char *resul ATTRIBUTE_UNUSED,
4327 const char *err ATTRIBUTE_UNUSED,
4328 int options ATTRIBUTE_UNUSED) {
4329 int ret;
4330
4331 xmlCatalogSetDefaults(XML_CATA_ALLOW_ALL);
4332 ret = testThread();
4333 xmlCatalogSetDefaults(XML_CATA_ALLOW_NONE);
4334
4335 return(ret);
4336 }
4337 #endif
4338
4339 #if defined(LIBXML_REGEXP_ENABLED)
4340 /************************************************************************
4341 * *
4342 * Regexp tests *
4343 * *
4344 ************************************************************************/
4345
testRegexp(FILE * output,xmlRegexpPtr comp,const char * value)4346 static void testRegexp(FILE *output, xmlRegexpPtr comp, const char *value) {
4347 int ret;
4348
4349 ret = xmlRegexpExec(comp, (const xmlChar *) value);
4350 if (ret == 1)
4351 fprintf(output, "%s: Ok\n", value);
4352 else if (ret == 0)
4353 fprintf(output, "%s: Fail\n", value);
4354 else
4355 fprintf(output, "%s: Error: %d\n", value, ret);
4356 }
4357
4358 static int
regexpTest(const char * filename,const char * result,const char * err,int options ATTRIBUTE_UNUSED)4359 regexpTest(const char *filename, const char *result, const char *err,
4360 int options ATTRIBUTE_UNUSED) {
4361 xmlRegexpPtr comp = NULL;
4362 FILE *input, *output;
4363 char *temp;
4364 char expression[5000];
4365 int len, ret, res = 0;
4366
4367 /*
4368 * TODO: Custom error handler for regexp
4369 */
4370 xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
4371
4372 nb_tests++;
4373
4374 input = fopen(filename, "rb");
4375 if (input == NULL) {
4376 fprintf(stderr,
4377 "Cannot open %s for reading\n", filename);
4378 ret = -1;
4379 goto done;
4380 }
4381 temp = resultFilename(filename, "", ".res");
4382 if (temp == NULL) {
4383 fprintf(stderr, "Out of memory\n");
4384 fatalError();
4385 }
4386 output = fopen(temp, "wb");
4387 if (output == NULL) {
4388 fprintf(stderr, "failed to open output file %s\n", temp);
4389 free(temp);
4390 ret = -1;
4391 goto done;
4392 }
4393 while (fgets(expression, 4500, input) != NULL) {
4394 len = strlen(expression);
4395 len--;
4396 while ((len >= 0) &&
4397 ((expression[len] == '\n') || (expression[len] == '\t') ||
4398 (expression[len] == '\r') || (expression[len] == ' '))) len--;
4399 expression[len + 1] = 0;
4400 if (len >= 0) {
4401 if (expression[0] == '#')
4402 continue;
4403 if ((expression[0] == '=') && (expression[1] == '>')) {
4404 char *pattern = &expression[2];
4405
4406 if (comp != NULL) {
4407 xmlRegFreeRegexp(comp);
4408 comp = NULL;
4409 }
4410 fprintf(output, "Regexp: %s\n", pattern) ;
4411 comp = xmlRegexpCompile((const xmlChar *) pattern);
4412 if (comp == NULL) {
4413 fprintf(output, " failed to compile\n");
4414 break;
4415 }
4416 } else if (comp == NULL) {
4417 fprintf(output, "Regexp: %s\n", expression) ;
4418 comp = xmlRegexpCompile((const xmlChar *) expression);
4419 if (comp == NULL) {
4420 fprintf(output, " failed to compile\n");
4421 break;
4422 }
4423 } else if (comp != NULL) {
4424 testRegexp(output, comp, expression);
4425 }
4426 }
4427 }
4428 fclose(output);
4429 fclose(input);
4430 if (comp != NULL)
4431 xmlRegFreeRegexp(comp);
4432
4433 ret = compareFiles(temp, result);
4434 if (ret) {
4435 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
4436 res = 1;
4437 }
4438 if (temp != NULL) {
4439 unlink(temp);
4440 free(temp);
4441 }
4442
4443 ret = compareFileMem(err, testErrors, testErrorsSize);
4444 if (ret != 0) {
4445 fprintf(stderr, "Error for %s failed\n", filename);
4446 res = 1;
4447 }
4448
4449 done:
4450 xmlSetStructuredErrorFunc(NULL, NULL);
4451
4452 return(res);
4453 }
4454
4455 #endif /* LIBXML_REGEXPS_ENABLED */
4456
4457 #ifdef LIBXML_AUTOMATA_ENABLED
4458 /************************************************************************
4459 * *
4460 * Automata tests *
4461 * *
4462 ************************************************************************/
4463
scanNumber(char ** ptr)4464 static int scanNumber(char **ptr) {
4465 int ret = 0;
4466 char *cur;
4467
4468 cur = *ptr;
4469 while ((*cur >= '0') && (*cur <= '9')) {
4470 ret = ret * 10 + (*cur - '0');
4471 cur++;
4472 }
4473 *ptr = cur;
4474 return(ret);
4475 }
4476
4477 static int
automataTest(const char * filename,const char * result,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)4478 automataTest(const char *filename, const char *result,
4479 const char *err ATTRIBUTE_UNUSED, int options ATTRIBUTE_UNUSED) {
4480 FILE *input, *output;
4481 char *temp;
4482 char expr[5000];
4483 int len;
4484 int ret;
4485 int i;
4486 int res = 0;
4487 xmlAutomataPtr am;
4488 xmlAutomataStatePtr states[1000];
4489 xmlRegexpPtr regexp = NULL;
4490 xmlRegExecCtxtPtr exec = NULL;
4491
4492 nb_tests++;
4493
4494 for (i = 0;i<1000;i++)
4495 states[i] = NULL;
4496
4497 input = fopen(filename, "rb");
4498 if (input == NULL) {
4499 fprintf(stderr,
4500 "Cannot open %s for reading\n", filename);
4501 return(-1);
4502 }
4503 temp = resultFilename(filename, "", ".res");
4504 if (temp == NULL) {
4505 fprintf(stderr, "Out of memory\n");
4506 fatalError();
4507 }
4508 output = fopen(temp, "wb");
4509 if (output == NULL) {
4510 fprintf(stderr, "failed to open output file %s\n", temp);
4511 free(temp);
4512 return(-1);
4513 }
4514
4515 am = xmlNewAutomata();
4516 if (am == NULL) {
4517 fprintf(stderr,
4518 "Cannot create automata\n");
4519 fclose(input);
4520 return(-1);
4521 }
4522 states[0] = xmlAutomataGetInitState(am);
4523 if (states[0] == NULL) {
4524 fprintf(stderr,
4525 "Cannot get start state\n");
4526 xmlFreeAutomata(am);
4527 fclose(input);
4528 return(-1);
4529 }
4530 ret = 0;
4531
4532 while (fgets(expr, 4500, input) != NULL) {
4533 if (expr[0] == '#')
4534 continue;
4535 len = strlen(expr);
4536 len--;
4537 while ((len >= 0) &&
4538 ((expr[len] == '\n') || (expr[len] == '\t') ||
4539 (expr[len] == '\r') || (expr[len] == ' '))) len--;
4540 expr[len + 1] = 0;
4541 if (len >= 0) {
4542 if ((am != NULL) && (expr[0] == 't') && (expr[1] == ' ')) {
4543 char *ptr = &expr[2];
4544 int from, to;
4545
4546 from = scanNumber(&ptr);
4547 if (*ptr != ' ') {
4548 fprintf(stderr,
4549 "Bad line %s\n", expr);
4550 break;
4551 }
4552 if (states[from] == NULL)
4553 states[from] = xmlAutomataNewState(am);
4554 ptr++;
4555 to = scanNumber(&ptr);
4556 if (*ptr != ' ') {
4557 fprintf(stderr,
4558 "Bad line %s\n", expr);
4559 break;
4560 }
4561 if (states[to] == NULL)
4562 states[to] = xmlAutomataNewState(am);
4563 ptr++;
4564 xmlAutomataNewTransition(am, states[from], states[to],
4565 BAD_CAST ptr, NULL);
4566 } else if ((am != NULL) && (expr[0] == 'e') && (expr[1] == ' ')) {
4567 char *ptr = &expr[2];
4568 int from, to;
4569
4570 from = scanNumber(&ptr);
4571 if (*ptr != ' ') {
4572 fprintf(stderr,
4573 "Bad line %s\n", expr);
4574 break;
4575 }
4576 if (states[from] == NULL)
4577 states[from] = xmlAutomataNewState(am);
4578 ptr++;
4579 to = scanNumber(&ptr);
4580 if (states[to] == NULL)
4581 states[to] = xmlAutomataNewState(am);
4582 xmlAutomataNewEpsilon(am, states[from], states[to]);
4583 } else if ((am != NULL) && (expr[0] == 'f') && (expr[1] == ' ')) {
4584 char *ptr = &expr[2];
4585 int state;
4586
4587 state = scanNumber(&ptr);
4588 if (states[state] == NULL) {
4589 fprintf(stderr,
4590 "Bad state %d : %s\n", state, expr);
4591 break;
4592 }
4593 xmlAutomataSetFinalState(am, states[state]);
4594 } else if ((am != NULL) && (expr[0] == 'c') && (expr[1] == ' ')) {
4595 char *ptr = &expr[2];
4596 int from, to;
4597 int min, max;
4598
4599 from = scanNumber(&ptr);
4600 if (*ptr != ' ') {
4601 fprintf(stderr,
4602 "Bad line %s\n", expr);
4603 break;
4604 }
4605 if (states[from] == NULL)
4606 states[from] = xmlAutomataNewState(am);
4607 ptr++;
4608 to = scanNumber(&ptr);
4609 if (*ptr != ' ') {
4610 fprintf(stderr,
4611 "Bad line %s\n", expr);
4612 break;
4613 }
4614 if (states[to] == NULL)
4615 states[to] = xmlAutomataNewState(am);
4616 ptr++;
4617 min = scanNumber(&ptr);
4618 if (*ptr != ' ') {
4619 fprintf(stderr,
4620 "Bad line %s\n", expr);
4621 break;
4622 }
4623 ptr++;
4624 max = scanNumber(&ptr);
4625 if (*ptr != ' ') {
4626 fprintf(stderr,
4627 "Bad line %s\n", expr);
4628 break;
4629 }
4630 ptr++;
4631 xmlAutomataNewCountTrans(am, states[from], states[to],
4632 BAD_CAST ptr, min, max, NULL);
4633 } else if ((am != NULL) && (expr[0] == '-') && (expr[1] == '-')) {
4634 /* end of the automata */
4635 regexp = xmlAutomataCompile(am);
4636 xmlFreeAutomata(am);
4637 am = NULL;
4638 if (regexp == NULL) {
4639 fprintf(stderr,
4640 "Failed to compile the automata");
4641 break;
4642 }
4643 } else if ((expr[0] == '=') && (expr[1] == '>')) {
4644 if (regexp == NULL) {
4645 fprintf(output, "=> failed not compiled\n");
4646 } else {
4647 if (exec == NULL)
4648 exec = xmlRegNewExecCtxt(regexp, NULL, NULL);
4649 if (ret == 0) {
4650 ret = xmlRegExecPushString(exec, NULL, NULL);
4651 }
4652 if (ret == 1)
4653 fprintf(output, "=> Passed\n");
4654 else if ((ret == 0) || (ret == -1))
4655 fprintf(output, "=> Failed\n");
4656 else if (ret < 0)
4657 fprintf(output, "=> Error\n");
4658 xmlRegFreeExecCtxt(exec);
4659 exec = NULL;
4660 }
4661 ret = 0;
4662 } else if (regexp != NULL) {
4663 if (exec == NULL)
4664 exec = xmlRegNewExecCtxt(regexp, NULL, NULL);
4665 ret = xmlRegExecPushString(exec, BAD_CAST expr, NULL);
4666 } else {
4667 fprintf(stderr,
4668 "Unexpected line %s\n", expr);
4669 }
4670 }
4671 }
4672 fclose(output);
4673 fclose(input);
4674 if (regexp != NULL)
4675 xmlRegFreeRegexp(regexp);
4676 if (exec != NULL)
4677 xmlRegFreeExecCtxt(exec);
4678 if (am != NULL)
4679 xmlFreeAutomata(am);
4680
4681 ret = compareFiles(temp, result);
4682 if (ret) {
4683 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
4684 res = 1;
4685 }
4686 if (temp != NULL) {
4687 unlink(temp);
4688 free(temp);
4689 }
4690
4691 return(res);
4692 }
4693
4694 #endif /* LIBXML_AUTOMATA_ENABLED */
4695
4696 /************************************************************************
4697 * *
4698 * Tests Descriptions *
4699 * *
4700 ************************************************************************/
4701
4702 static
4703 testDesc testDescriptions[] = {
4704 { "XML regression tests" ,
4705 oldParseTest, "./test/*", "result/", "", NULL,
4706 0 },
4707 { "XML regression tests on memory" ,
4708 memParseTest, "./test/*", "result/", "", NULL,
4709 0 },
4710 { "XML entity subst regression tests" ,
4711 noentParseTest, "./test/*", "result/noent/", "", NULL,
4712 XML_PARSE_NOENT },
4713 { "XML Namespaces regression tests",
4714 errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err",
4715 0 },
4716 #ifdef LIBXML_VALID_ENABLED
4717 { "Error cases regression tests",
4718 errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err",
4719 0 },
4720 { "Error cases regression tests from file descriptor",
4721 fdParseTest, "./test/errors/*.xml", "result/errors/", "", ".err",
4722 0 },
4723 { "Error cases regression tests with entity substitution",
4724 errParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".ent",
4725 XML_PARSE_NOENT },
4726 { "Error cases regression tests (old 1.0)",
4727 errParseTest, "./test/errors10/*.xml", "result/errors10/", "", ".err",
4728 XML_PARSE_OLD10 },
4729 #endif
4730 #ifdef LIBXML_READER_ENABLED
4731 #ifdef LIBXML_VALID_ENABLED
4732 { "Error cases stream regression tests",
4733 streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str",
4734 0 },
4735 #endif
4736 { "Reader regression tests",
4737 streamParseTest, "./test/*", "result/", ".rdr", NULL,
4738 0 },
4739 { "Reader entities substitution regression tests",
4740 streamParseTest, "./test/*", "result/", ".rde", NULL,
4741 XML_PARSE_NOENT },
4742 { "Reader on memory regression tests",
4743 streamMemParseTest, "./test/*", "result/", ".rdr", NULL,
4744 0 },
4745 { "Walker regression tests",
4746 walkerParseTest, "./test/*", "result/", ".rdr", NULL,
4747 0 },
4748 #endif
4749 #ifdef LIBXML_SAX1_ENABLED
4750 { "SAX1 callbacks regression tests" ,
4751 saxParseTest, "./test/*", "result/", ".sax", NULL,
4752 XML_PARSE_SAX1 },
4753 #endif
4754 { "SAX2 callbacks regression tests" ,
4755 saxParseTest, "./test/*", "result/", ".sax2", NULL,
4756 0 },
4757 { "SAX2 callbacks regression tests with entity substitution" ,
4758 saxParseTest, "./test/*", "result/noent/", ".sax2", NULL,
4759 XML_PARSE_NOENT },
4760 #ifdef LIBXML_PUSH_ENABLED
4761 { "XML push regression tests" ,
4762 pushParseTest, "./test/*", "result/", "", NULL,
4763 0 },
4764 { "XML push boundary tests" ,
4765 pushBoundaryTest, "./test/*", "result/", "", NULL,
4766 0 },
4767 #endif
4768 #ifdef LIBXML_HTML_ENABLED
4769 { "HTML regression tests" ,
4770 errParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4771 XML_PARSE_HTML },
4772 { "HTML regression tests from file descriptor",
4773 fdParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4774 XML_PARSE_HTML },
4775 #ifdef LIBXML_PUSH_ENABLED
4776 { "Push HTML regression tests" ,
4777 pushParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4778 XML_PARSE_HTML },
4779 { "Push HTML boundary tests" ,
4780 pushBoundaryTest, "./test/HTML/*", "result/HTML/", "", NULL,
4781 XML_PARSE_HTML },
4782 #endif
4783 { "HTML SAX regression tests" ,
4784 saxParseTest, "./test/HTML/*", "result/HTML/", ".sax", NULL,
4785 XML_PARSE_HTML },
4786 #endif
4787 #ifdef LIBXML_VALID_ENABLED
4788 { "Valid documents regression tests" ,
4789 errParseTest, "./test/VCM/*", NULL, NULL, NULL,
4790 XML_PARSE_DTDVALID },
4791 { "Validity checking regression tests" ,
4792 errParseTest, "./test/VC/*", "result/VC/", NULL, "",
4793 XML_PARSE_DTDVALID },
4794 #ifdef LIBXML_READER_ENABLED
4795 { "Streaming validity checking regression tests" ,
4796 streamParseTest, "./test/valid/*.xml", "result/valid/", NULL, ".err.rdr",
4797 XML_PARSE_DTDVALID },
4798 { "Streaming validity error checking regression tests" ,
4799 streamParseTest, "./test/VC/*", "result/VC/", NULL, ".rdr",
4800 XML_PARSE_DTDVALID },
4801 #endif
4802 { "General documents valid regression tests" ,
4803 errParseTest, "./test/valid/*", "result/valid/", "", ".err",
4804 XML_PARSE_DTDVALID },
4805 #endif
4806 #ifdef LIBXML_XINCLUDE_ENABLED
4807 { "XInclude regression tests" ,
4808 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", ".err",
4809 XML_PARSE_XINCLUDE },
4810 #ifdef LIBXML_READER_ENABLED
4811 { "XInclude xmlReader regression tests",
4812 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4813 ".err", XML_PARSE_XINCLUDE },
4814 #endif
4815 { "XInclude regression tests stripping include nodes" ,
4816 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", ".err",
4817 XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
4818 #ifdef LIBXML_READER_ENABLED
4819 { "XInclude xmlReader regression tests stripping include nodes",
4820 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4821 ".err", XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
4822 #endif
4823 { "XInclude regression tests without reader",
4824 errParseTest, "./test/XInclude/without-reader/*", "result/XInclude/", "",
4825 ".err", XML_PARSE_XINCLUDE },
4826 #endif
4827 #ifdef LIBXML_XPATH_ENABLED
4828 #ifdef LIBXML_DEBUG_ENABLED
4829 { "XPath expressions regression tests" ,
4830 xpathExprTest, "./test/XPath/expr/*", "result/XPath/expr/", "", NULL,
4831 0 },
4832 { "XPath document queries regression tests" ,
4833 xpathDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4834 0 },
4835 #ifdef LIBXML_XPTR_ENABLED
4836 { "XPointer document queries regression tests" ,
4837 xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4838 0 },
4839 #endif
4840 #ifdef LIBXML_VALID_ENABLED
4841 { "xml:id regression tests" ,
4842 xmlidDocTest, "./test/xmlid/*", "result/xmlid/", "", ".err",
4843 0 },
4844 #endif
4845 #endif
4846 #endif
4847 { "URI parsing tests" ,
4848 uriParseTest, "./test/URI/*.uri", "result/URI/", "", NULL,
4849 0 },
4850 { "URI base composition tests" ,
4851 uriBaseTest, "./test/URI/*.data", "result/URI/", "", NULL,
4852 0 },
4853 { "Path URI conversion tests" ,
4854 uriPathTest, NULL, NULL, NULL, NULL,
4855 0 },
4856 #ifdef LIBXML_SCHEMAS_ENABLED
4857 { "Schemas regression tests" ,
4858 schemasTest, "./test/schemas/*_*.xsd", NULL, NULL, NULL,
4859 0 },
4860 { "Relax-NG regression tests" ,
4861 rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4862 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4863 #ifdef LIBXML_READER_ENABLED
4864 { "Relax-NG streaming regression tests" ,
4865 rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4866 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4867 #endif
4868 #endif
4869 #ifdef LIBXML_PATTERN_ENABLED
4870 #ifdef LIBXML_READER_ENABLED
4871 { "Pattern regression tests" ,
4872 patternTest, "./test/pattern/*.pat", "result/pattern/", NULL, NULL,
4873 0 },
4874 #endif
4875 #endif
4876 #ifdef LIBXML_C14N_ENABLED
4877 { "C14N with comments regression tests" ,
4878 c14nWithCommentTest, "./test/c14n/with-comments/*.xml", NULL, NULL, NULL,
4879 0 },
4880 { "C14N without comments regression tests" ,
4881 c14nWithoutCommentTest, "./test/c14n/without-comments/*.xml", NULL, NULL, NULL,
4882 0 },
4883 { "C14N exclusive without comments regression tests" ,
4884 c14nExcWithoutCommentTest, "./test/c14n/exc-without-comments/*.xml", NULL, NULL, NULL,
4885 0 },
4886 { "C14N 1.1 without comments regression tests" ,
4887 c14n11WithoutCommentTest, "./test/c14n/1-1-without-comments/*.xml", NULL, NULL, NULL,
4888 0 },
4889 #endif
4890 #if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
4891 { "Catalog and Threads regression tests" ,
4892 threadsTest, NULL, NULL, NULL, NULL,
4893 0 },
4894 #endif
4895 { "SVG parsing regression tests" ,
4896 oldParseTest, "./test/SVG/*.xml", "result/SVG/", "", NULL,
4897 0 },
4898 #if defined(LIBXML_REGEXP_ENABLED)
4899 { "Regexp regression tests" ,
4900 regexpTest, "./test/regexp/*", "result/regexp/", "", ".err",
4901 0 },
4902 #endif
4903 #if defined(LIBXML_AUTOMATA_ENABLED)
4904 { "Automata regression tests" ,
4905 automataTest, "./test/automata/*", "result/automata/", "", NULL,
4906 0 },
4907 #endif
4908 {NULL, NULL, NULL, NULL, NULL, NULL, 0}
4909 };
4910
4911 /************************************************************************
4912 * *
4913 * The main code driving the tests *
4914 * *
4915 ************************************************************************/
4916
4917 static int
launchTests(testDescPtr tst)4918 launchTests(testDescPtr tst) {
4919 int res = 0, err = 0;
4920 size_t i;
4921 char *result;
4922 char *error;
4923 int mem;
4924 xmlCharEncodingHandlerPtr ebcdicHandler, ibm1141Handler, eucJpHandler;
4925
4926 ebcdicHandler = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_EBCDIC);
4927 ibm1141Handler = xmlFindCharEncodingHandler("IBM-1141");
4928
4929 /*
4930 * When decoding EUC-JP, musl doesn't seem to support 0x8F control
4931 * codes.
4932 */
4933 eucJpHandler = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_EUC_JP);
4934 if (eucJpHandler != NULL) {
4935 xmlBufferPtr in, out;
4936
4937 in = xmlBufferCreateSize(10);
4938 xmlBufferCCat(in, "\x8f\xe9\xae");
4939 out = xmlBufferCreateSize(10);
4940 if (xmlCharEncInFunc(eucJpHandler, out, in) != 3) {
4941 xmlCharEncCloseFunc(eucJpHandler);
4942 eucJpHandler = NULL;
4943 }
4944 xmlBufferFree(out);
4945 xmlBufferFree(in);
4946 }
4947
4948 if (tst == NULL) return(-1);
4949 if (tst->in != NULL) {
4950 glob_t globbuf;
4951
4952 globbuf.gl_offs = 0;
4953 glob(tst->in, GLOB_DOOFFS, NULL, &globbuf);
4954 for (i = 0;i < globbuf.gl_pathc;i++) {
4955 if (!checkTestFile(globbuf.gl_pathv[i]))
4956 continue;
4957 if ((((ebcdicHandler == NULL) || (ibm1141Handler == NULL)) &&
4958 (strstr(globbuf.gl_pathv[i], "ebcdic") != NULL)) ||
4959 ((eucJpHandler == NULL) &&
4960 (strstr(globbuf.gl_pathv[i], "icu_parse_test") != NULL)))
4961 continue;
4962 if (tst->suffix != NULL) {
4963 result = resultFilename(globbuf.gl_pathv[i], tst->out,
4964 tst->suffix);
4965 if (result == NULL) {
4966 fprintf(stderr, "Out of memory !\n");
4967 fatalError();
4968 }
4969 } else {
4970 result = NULL;
4971 }
4972 if (tst->err != NULL) {
4973 error = resultFilename(globbuf.gl_pathv[i], tst->out,
4974 tst->err);
4975 if (error == NULL) {
4976 fprintf(stderr, "Out of memory !\n");
4977 fatalError();
4978 }
4979 } else {
4980 error = NULL;
4981 }
4982 mem = xmlMemUsed();
4983 testErrorsSize = 0;
4984 testErrors[0] = 0;
4985 res = tst->func(globbuf.gl_pathv[i], result, error,
4986 tst->options | XML_PARSE_COMPACT);
4987 xmlResetLastError();
4988 if (res != 0) {
4989 fprintf(stderr, "File %s generated an error\n",
4990 globbuf.gl_pathv[i]);
4991 nb_errors++;
4992 err++;
4993 }
4994 else if (xmlMemUsed() != mem) {
4995 fprintf(stderr, "File %s leaked %d bytes\n",
4996 globbuf.gl_pathv[i], xmlMemUsed() - mem);
4997 nb_leaks++;
4998 err++;
4999 }
5000 testErrorsSize = 0;
5001 if (result)
5002 free(result);
5003 if (error)
5004 free(error);
5005 }
5006 globfree(&globbuf);
5007 } else {
5008 testErrorsSize = 0;
5009 testErrors[0] = 0;
5010 res = tst->func(NULL, NULL, NULL, tst->options);
5011 xmlResetLastError();
5012 if (res != 0) {
5013 nb_errors++;
5014 err++;
5015 }
5016 }
5017
5018 xmlCharEncCloseFunc(ebcdicHandler);
5019 xmlCharEncCloseFunc(ibm1141Handler);
5020 xmlCharEncCloseFunc(eucJpHandler);
5021
5022 return(err);
5023 }
5024
5025 static int verbose = 0;
5026 static int tests_quiet = 0;
5027
5028 static int
runtest(int i)5029 runtest(int i) {
5030 int ret = 0, res;
5031 int old_errors, old_tests, old_leaks;
5032
5033 old_errors = nb_errors;
5034 old_tests = nb_tests;
5035 old_leaks = nb_leaks;
5036 if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
5037 printf("## %s\n", testDescriptions[i].desc);
5038 res = launchTests(&testDescriptions[i]);
5039 if (res != 0)
5040 ret++;
5041 if (verbose) {
5042 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
5043 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
5044 else
5045 printf("Ran %d tests, %d errors, %d leaks\n",
5046 nb_tests - old_tests,
5047 nb_errors - old_errors,
5048 nb_leaks - old_leaks);
5049 }
5050 return(ret);
5051 }
5052
5053 int
main(int argc ATTRIBUTE_UNUSED,char ** argv ATTRIBUTE_UNUSED)5054 main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
5055 int i, a, ret = 0;
5056 int subset = 0;
5057
5058 #if defined(_WIN32)
5059 setvbuf(stdout, NULL, _IONBF, 0);
5060 setvbuf(stderr, NULL, _IONBF, 0);
5061 #endif
5062
5063 #if defined(_MSC_VER) && _MSC_VER >= 1400 && _MSC_VER < 1900
5064 _set_output_format(_TWO_DIGIT_EXPONENT);
5065 #endif
5066
5067 initializeLibxml2();
5068
5069 for (a = 1; a < argc;a++) {
5070 if (!strcmp(argv[a], "-v"))
5071 verbose = 1;
5072 else if (!strcmp(argv[a], "-u"))
5073 update_results = 1;
5074 else if (!strcmp(argv[a], "-quiet"))
5075 tests_quiet = 1;
5076 else if (!strcmp(argv[a], "--out"))
5077 temp_directory = argv[++a];
5078 else {
5079 for (i = 0; testDescriptions[i].func != NULL; i++) {
5080 if (strstr(testDescriptions[i].desc, argv[a])) {
5081 ret += runtest(i);
5082 subset++;
5083 }
5084 }
5085 }
5086 }
5087 if (subset == 0) {
5088 for (i = 0; testDescriptions[i].func != NULL; i++) {
5089 ret += runtest(i);
5090 }
5091 }
5092 if ((nb_errors == 0) && (nb_leaks == 0)) {
5093 ret = 0;
5094 printf("Total %d tests, no errors\n",
5095 nb_tests);
5096 } else {
5097 ret = 1;
5098 printf("Total %d tests, %d errors, %d leaks\n",
5099 nb_tests, nb_errors, nb_leaks);
5100 }
5101 xmlCleanupParser();
5102
5103 return(ret);
5104 }
5105
5106 #else /* ! LIBXML_OUTPUT_ENABLED */
5107 int
main(int argc ATTRIBUTE_UNUSED,char ** argv ATTRIBUTE_UNUSED)5108 main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
5109 fprintf(stderr, "runtest requires output to be enabled in libxml2\n");
5110 return(0);
5111 }
5112 #endif
5113