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