VirtualBox

source: vbox/trunk/src/libs/libxml2-2.13.2/runtest.c@ 105764

最後變更 在這個檔案從105764是 105420,由 vboxsync 提交於 4 月 前

libxml2-2.12.6: Applied and adjusted our libxml2 changes to 2.12.6. bugref:10730

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette