Annotation of embedaddon/libxml2/testlimits.c, revision 1.1.1.1
1.1 misho 1: /*
2: * testlimits.c: C program to run libxml2 regression tests checking various
3: * limits in document size. Will consume a lot of RAM and CPU cycles
4: *
5: * To compile on Unixes:
6: * cc -o testlimits `xml2-config --cflags` testlimits.c `xml2-config --libs` -lpthread
7: *
8: * See Copyright for the status of this software.
9: *
10: * daniel@veillard.com
11: */
12:
13: #ifdef HAVE_CONFIG_H
14: #include "libxml.h"
15: #else
16: #include <stdio.h>
17: #endif
18:
19: #if !defined(_WIN32) || defined(__CYGWIN__)
20: #include <unistd.h>
21: #endif
22: #include <string.h>
23: #include <sys/types.h>
24: #include <sys/stat.h>
25: #include <fcntl.h>
26: #include <time.h>
27:
28: #include <libxml/parser.h>
29: #include <libxml/parserInternals.h>
30: #include <libxml/tree.h>
31: #include <libxml/uri.h>
32: #ifdef LIBXML_READER_ENABLED
33: #include <libxml/xmlreader.h>
34: #endif
35:
36: static int verbose = 0;
37: static int tests_quiet = 0;
38:
39: /************************************************************************
40: * *
41: * time handling *
42: * *
43: ************************************************************************/
44:
45: /* maximum time for one parsing before declaring a timeout */
46: #define MAX_TIME 2 /* seconds */
47:
48: static clock_t t0;
49: int timeout = 0;
50:
51: static void reset_timout(void) {
52: timeout = 0;
53: t0 = clock();
54: }
55:
56: static int check_time(void) {
57: clock_t tnow = clock();
58: if (((tnow - t0) / CLOCKS_PER_SEC) > MAX_TIME) {
59: timeout = 1;
60: return(0);
61: }
62: return(1);
63: }
64:
65: /************************************************************************
66: * *
67: * Huge document generator *
68: * *
69: ************************************************************************/
70:
71: #include <libxml/xmlIO.h>
72:
73: /*
74: * Huge documents are built using fixed start and end chunks
75: * and filling between the two an unconventional amount of char data
76: */
77: typedef struct hugeTest hugeTest;
78: typedef hugeTest *hugeTestPtr;
79: struct hugeTest {
80: const char *description;
81: const char *name;
82: const char *start;
83: const char *end;
84: };
85:
86: static struct hugeTest hugeTests[] = {
87: { "Huge text node", "huge:textNode", "<foo>", "</foo>" },
88: { "Huge attribute node", "huge:attrNode", "<foo bar='", "'/>" },
89: { "Huge comment node", "huge:commentNode", "<foo><!--", "--></foo>" },
90: { "Huge PI node", "huge:piNode", "<foo><?bar ", "?></foo>" },
91: };
92:
93: static const char *current;
94: static int rlen;
95: static unsigned int currentTest = 0;
96: static int instate = 0;
97:
98: /**
99: * hugeMatch:
100: * @URI: an URI to test
101: *
102: * Check for an huge: query
103: *
104: * Returns 1 if yes and 0 if another Input module should be used
105: */
106: static int
107: hugeMatch(const char * URI) {
108: if ((URI != NULL) && (!strncmp(URI, "huge:", 5)))
109: return(1);
110: return(0);
111: }
112:
113: /**
114: * hugeOpen:
115: * @URI: an URI to test
116: *
117: * Return a pointer to the huge: query handler, in this example simply
118: * the current pointer...
119: *
120: * Returns an Input context or NULL in case or error
121: */
122: static void *
123: hugeOpen(const char * URI) {
124: if ((URI == NULL) || (strncmp(URI, "huge:", 5)))
125: return(NULL);
126:
127: for (currentTest = 0;currentTest < sizeof(hugeTests)/sizeof(hugeTests[0]);
128: currentTest++)
129: if (!strcmp(hugeTests[currentTest].name, URI))
130: goto found;
131:
132: return(NULL);
133:
134: found:
135: rlen = strlen(hugeTests[currentTest].start);
136: current = hugeTests[currentTest].start;
137: instate = 0;
138: return((void *) current);
139: }
140:
141: /**
142: * hugeClose:
143: * @context: the read context
144: *
145: * Close the huge: query handler
146: *
147: * Returns 0 or -1 in case of error
148: */
149: static int
150: hugeClose(void * context) {
151: if (context == NULL) return(-1);
152: fprintf(stderr, "\n");
153: return(0);
154: }
155:
156: #define CHUNK 4096
157:
158: char filling[CHUNK + 1];
159:
160: static void fillFilling(void) {
161: int i;
162:
163: for (i = 0;i < CHUNK;i++) {
164: filling[i] = 'a';
165: }
166: filling[CHUNK] = 0;
167: }
168:
169: size_t maxlen = 64 * 1024 * 1024;
170: size_t curlen = 0;
171: size_t dotlen;
172:
173: /**
174: * hugeRead:
175: * @context: the read context
176: * @buffer: where to store data
177: * @len: number of bytes to read
178: *
179: * Implement an huge: query read.
180: *
181: * Returns the number of bytes read or -1 in case of error
182: */
183: static int
184: hugeRead(void *context, char *buffer, int len)
185: {
186: if ((context == NULL) || (buffer == NULL) || (len < 0))
187: return (-1);
188:
189: if (instate == 0) {
190: if (len >= rlen) {
191: len = rlen;
192: rlen = 0;
193: memcpy(buffer, current, len);
194: instate = 1;
195: curlen = 0;
196: dotlen = maxlen / 10;
197: } else {
198: memcpy(buffer, current, len);
199: rlen -= len;
200: current += len;
201: }
202: } else if (instate == 2) {
203: if (len >= rlen) {
204: len = rlen;
205: rlen = 0;
206: memcpy(buffer, current, len);
207: instate = 3;
208: curlen = 0;
209: } else {
210: memcpy(buffer, current, len);
211: rlen -= len;
212: current += len;
213: }
214: } else if (instate == 1) {
215: if (len > CHUNK) len = CHUNK;
216: memcpy(buffer, &filling[0], len);
217: curlen += len;
218: if (curlen >= maxlen) {
219: rlen = strlen(hugeTests[currentTest].end);
220: current = hugeTests[currentTest].end;
221: instate = 2;
222: } else {
223: if (curlen > dotlen) {
224: fprintf(stderr, ".");
225: dotlen += maxlen / 10;
226: }
227: }
228: } else
229: len = 0;
230: return (len);
231: }
232:
233: /************************************************************************
234: * *
235: * Crazy document generator *
236: * *
237: ************************************************************************/
238:
239: unsigned int crazy_indx = 0;
240:
241: const char *crazy = "<?xml version='1.0' encoding='UTF-8'?>\
242: <?tst ?>\
243: <!-- tst -->\
244: <!DOCTYPE foo [\
245: <?tst ?>\
246: <!-- tst -->\
247: <!ELEMENT foo (#PCDATA)>\
248: <!ELEMENT p (#PCDATA|emph)* >\
249: ]>\
250: <?tst ?>\
251: <!-- tst -->\
252: <foo bar='foo'>\
253: <?tst ?>\
254: <!-- tst -->\
255: foo\
256: <![CDATA[ ]]>\
257: </foo>\
258: <?tst ?>\
259: <!-- tst -->";
260:
261: /**
262: * crazyMatch:
263: * @URI: an URI to test
264: *
265: * Check for a crazy: query
266: *
267: * Returns 1 if yes and 0 if another Input module should be used
268: */
269: static int
270: crazyMatch(const char * URI) {
271: if ((URI != NULL) && (!strncmp(URI, "crazy:", 6)))
272: return(1);
273: return(0);
274: }
275:
276: /**
277: * crazyOpen:
278: * @URI: an URI to test
279: *
280: * Return a pointer to the crazy: query handler, in this example simply
281: * the current pointer...
282: *
283: * Returns an Input context or NULL in case or error
284: */
285: static void *
286: crazyOpen(const char * URI) {
287: if ((URI == NULL) || (strncmp(URI, "crazy:", 6)))
288: return(NULL);
289:
290: if (crazy_indx > strlen(crazy))
291: return(NULL);
292: reset_timout();
293: rlen = crazy_indx;
294: current = &crazy[0];
295: instate = 0;
296: return((void *) current);
297: }
298:
299: /**
300: * crazyClose:
301: * @context: the read context
302: *
303: * Close the crazy: query handler
304: *
305: * Returns 0 or -1 in case of error
306: */
307: static int
308: crazyClose(void * context) {
309: if (context == NULL) return(-1);
310: return(0);
311: }
312:
313:
314: /**
315: * crazyRead:
316: * @context: the read context
317: * @buffer: where to store data
318: * @len: number of bytes to read
319: *
320: * Implement an crazy: query read.
321: *
322: * Returns the number of bytes read or -1 in case of error
323: */
324: static int
325: crazyRead(void *context, char *buffer, int len)
326: {
327: if ((context == NULL) || (buffer == NULL) || (len < 0))
328: return (-1);
329:
330: if ((check_time() <= 0) && (instate == 1)) {
331: fprintf(stderr, "\ntimeout in crazy(%d)\n", crazy_indx);
332: rlen = strlen(crazy) - crazy_indx;
333: current = &crazy[crazy_indx];
334: instate = 2;
335: }
336: if (instate == 0) {
337: if (len >= rlen) {
338: len = rlen;
339: rlen = 0;
340: memcpy(buffer, current, len);
341: instate = 1;
342: curlen = 0;
343: } else {
344: memcpy(buffer, current, len);
345: rlen -= len;
346: current += len;
347: }
348: } else if (instate == 2) {
349: if (len >= rlen) {
350: len = rlen;
351: rlen = 0;
352: memcpy(buffer, current, len);
353: instate = 3;
354: curlen = 0;
355: } else {
356: memcpy(buffer, current, len);
357: rlen -= len;
358: current += len;
359: }
360: } else if (instate == 1) {
361: if (len > CHUNK) len = CHUNK;
362: memcpy(buffer, &filling[0], len);
363: curlen += len;
364: if (curlen >= maxlen) {
365: rlen = strlen(crazy) - crazy_indx;
366: current = &crazy[crazy_indx];
367: instate = 2;
368: }
369: } else
370: len = 0;
371: return (len);
372: }
373: /************************************************************************
374: * *
375: * Libxml2 specific routines *
376: * *
377: ************************************************************************/
378:
379: static int nb_tests = 0;
380: static int nb_errors = 0;
381: static int nb_leaks = 0;
382: static int extraMemoryFromResolver = 0;
383:
384: /*
385: * We need to trap calls to the resolver to not account memory for the catalog
386: * which is shared to the current running test. We also don't want to have
387: * network downloads modifying tests.
388: */
389: static xmlParserInputPtr
390: testExternalEntityLoader(const char *URL, const char *ID,
391: xmlParserCtxtPtr ctxt) {
392: xmlParserInputPtr ret;
393: int memused = xmlMemUsed();
394:
395: ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
396: extraMemoryFromResolver += xmlMemUsed() - memused;
397:
398: return(ret);
399: }
400:
401: /*
402: * Trapping the error messages at the generic level to grab the equivalent of
403: * stderr messages on CLI tools.
404: */
405: static char testErrors[32769];
406: static int testErrorsSize = 0;
407:
408: static void XMLCDECL
409: channel(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
410: va_list args;
411: int res;
412:
413: if (testErrorsSize >= 32768)
414: return;
415: va_start(args, msg);
416: res = vsnprintf(&testErrors[testErrorsSize],
417: 32768 - testErrorsSize,
418: msg, args);
419: va_end(args);
420: if (testErrorsSize + res >= 32768) {
421: /* buffer is full */
422: testErrorsSize = 32768;
423: testErrors[testErrorsSize] = 0;
424: } else {
425: testErrorsSize += res;
426: }
427: testErrors[testErrorsSize] = 0;
428: }
429:
430: /**
431: * xmlParserPrintFileContext:
432: * @input: an xmlParserInputPtr input
433: *
434: * Displays current context within the input content for error tracking
435: */
436:
437: static void
438: xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
439: xmlGenericErrorFunc chanl, void *data ) {
440: const xmlChar *cur, *base;
441: unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */
442: xmlChar content[81]; /* space for 80 chars + line terminator */
443: xmlChar *ctnt;
444:
445: if (input == NULL) return;
446: cur = input->cur;
447: base = input->base;
448: /* skip backwards over any end-of-lines */
449: while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
450: cur--;
451: }
452: n = 0;
453: /* search backwards for beginning-of-line (to max buff size) */
454: while ((n++ < (sizeof(content)-1)) && (cur > base) &&
455: (*(cur) != '\n') && (*(cur) != '\r'))
456: cur--;
457: if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
458: /* calculate the error position in terms of the current position */
459: col = input->cur - cur;
460: /* search forward for end-of-line (to max buff size) */
461: n = 0;
462: ctnt = content;
463: /* copy selected text to our buffer */
464: while ((*cur != 0) && (*(cur) != '\n') &&
465: (*(cur) != '\r') && (n < sizeof(content)-1)) {
466: *ctnt++ = *cur++;
467: n++;
468: }
469: *ctnt = 0;
470: /* print out the selected text */
471: chanl(data ,"%s\n", content);
472: /* create blank line with problem pointer */
473: n = 0;
474: ctnt = content;
475: /* (leave buffer space for pointer + line terminator) */
476: while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
477: if (*(ctnt) != '\t')
478: *(ctnt) = ' ';
479: ctnt++;
480: }
481: *ctnt++ = '^';
482: *ctnt = 0;
483: chanl(data ,"%s\n", content);
484: }
485:
486: static void
487: testStructuredErrorHandler(void *ctx ATTRIBUTE_UNUSED, xmlErrorPtr err) {
488: char *file = NULL;
489: int line = 0;
490: int code = -1;
491: int domain;
492: void *data = NULL;
493: const char *str;
494: const xmlChar *name = NULL;
495: xmlNodePtr node;
496: xmlErrorLevel level;
497: xmlParserInputPtr input = NULL;
498: xmlParserInputPtr cur = NULL;
499: xmlParserCtxtPtr ctxt = NULL;
500:
501: if (err == NULL)
502: return;
503:
504: file = err->file;
505: line = err->line;
506: code = err->code;
507: domain = err->domain;
508: level = err->level;
509: node = err->node;
510: if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
511: (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
512: (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
513: ctxt = err->ctxt;
514: }
515: str = err->message;
516:
517: if (code == XML_ERR_OK)
518: return;
519:
520: if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
521: name = node->name;
522:
523: /*
524: * Maintain the compatibility with the legacy error handling
525: */
526: if (ctxt != NULL) {
527: input = ctxt->input;
528: if ((input != NULL) && (input->filename == NULL) &&
529: (ctxt->inputNr > 1)) {
530: cur = input;
531: input = ctxt->inputTab[ctxt->inputNr - 2];
532: }
533: if (input != NULL) {
534: if (input->filename)
535: channel(data, "%s:%d: ", input->filename, input->line);
536: else if ((line != 0) && (domain == XML_FROM_PARSER))
537: channel(data, "Entity: line %d: ", input->line);
538: }
539: } else {
540: if (file != NULL)
541: channel(data, "%s:%d: ", file, line);
542: else if ((line != 0) && (domain == XML_FROM_PARSER))
543: channel(data, "Entity: line %d: ", line);
544: }
545: if (name != NULL) {
546: channel(data, "element %s: ", name);
547: }
548: if (code == XML_ERR_OK)
549: return;
550: switch (domain) {
551: case XML_FROM_PARSER:
552: channel(data, "parser ");
553: break;
554: case XML_FROM_NAMESPACE:
555: channel(data, "namespace ");
556: break;
557: case XML_FROM_DTD:
558: case XML_FROM_VALID:
559: channel(data, "validity ");
560: break;
561: case XML_FROM_HTML:
562: channel(data, "HTML parser ");
563: break;
564: case XML_FROM_MEMORY:
565: channel(data, "memory ");
566: break;
567: case XML_FROM_OUTPUT:
568: channel(data, "output ");
569: break;
570: case XML_FROM_IO:
571: channel(data, "I/O ");
572: break;
573: case XML_FROM_XINCLUDE:
574: channel(data, "XInclude ");
575: break;
576: case XML_FROM_XPATH:
577: channel(data, "XPath ");
578: break;
579: case XML_FROM_XPOINTER:
580: channel(data, "parser ");
581: break;
582: case XML_FROM_REGEXP:
583: channel(data, "regexp ");
584: break;
585: case XML_FROM_MODULE:
586: channel(data, "module ");
587: break;
588: case XML_FROM_SCHEMASV:
589: channel(data, "Schemas validity ");
590: break;
591: case XML_FROM_SCHEMASP:
592: channel(data, "Schemas parser ");
593: break;
594: case XML_FROM_RELAXNGP:
595: channel(data, "Relax-NG parser ");
596: break;
597: case XML_FROM_RELAXNGV:
598: channel(data, "Relax-NG validity ");
599: break;
600: case XML_FROM_CATALOG:
601: channel(data, "Catalog ");
602: break;
603: case XML_FROM_C14N:
604: channel(data, "C14N ");
605: break;
606: case XML_FROM_XSLT:
607: channel(data, "XSLT ");
608: break;
609: default:
610: break;
611: }
612: if (code == XML_ERR_OK)
613: return;
614: switch (level) {
615: case XML_ERR_NONE:
616: channel(data, ": ");
617: break;
618: case XML_ERR_WARNING:
619: channel(data, "warning : ");
620: break;
621: case XML_ERR_ERROR:
622: channel(data, "error : ");
623: break;
624: case XML_ERR_FATAL:
625: channel(data, "error : ");
626: break;
627: }
628: if (code == XML_ERR_OK)
629: return;
630: if (str != NULL) {
631: int len;
632: len = xmlStrlen((const xmlChar *)str);
633: if ((len > 0) && (str[len - 1] != '\n'))
634: channel(data, "%s\n", str);
635: else
636: channel(data, "%s", str);
637: } else {
638: channel(data, "%s\n", "out of memory error");
639: }
640: if (code == XML_ERR_OK)
641: return;
642:
643: if (ctxt != NULL) {
644: xmlParserPrintFileContextInternal(input, channel, data);
645: if (cur != NULL) {
646: if (cur->filename)
647: channel(data, "%s:%d: \n", cur->filename, cur->line);
648: else if ((line != 0) && (domain == XML_FROM_PARSER))
649: channel(data, "Entity: line %d: \n", cur->line);
650: xmlParserPrintFileContextInternal(cur, channel, data);
651: }
652: }
653: if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
654: (err->int1 < 100) &&
655: (err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
656: xmlChar buf[150];
657: int i;
658:
659: channel(data, "%s\n", err->str1);
660: for (i=0;i < err->int1;i++)
661: buf[i] = ' ';
662: buf[i++] = '^';
663: buf[i] = 0;
664: channel(data, "%s\n", buf);
665: }
666: }
667:
668: static void
669: initializeLibxml2(void) {
670: xmlGetWarningsDefaultValue = 0;
671: xmlPedanticParserDefault(0);
672:
673: xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
674: xmlInitParser();
675: xmlSetExternalEntityLoader(testExternalEntityLoader);
676: xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
677: /*
678: * register the new I/O handlers
679: */
680: if (xmlRegisterInputCallbacks(hugeMatch, hugeOpen,
681: hugeRead, hugeClose) < 0) {
682: fprintf(stderr, "failed to register Huge handlers\n");
683: exit(1);
684: }
685: if (xmlRegisterInputCallbacks(crazyMatch, crazyOpen,
686: crazyRead, crazyClose) < 0) {
687: fprintf(stderr, "failed to register Crazy handlers\n");
688: exit(1);
689: }
690: }
691:
692: /************************************************************************
693: * *
694: * SAX empty callbacks *
695: * *
696: ************************************************************************/
697:
698: unsigned long callbacks = 0;
699:
700: /**
701: * isStandaloneCallback:
702: * @ctxt: An XML parser context
703: *
704: * Is this document tagged standalone ?
705: *
706: * Returns 1 if true
707: */
708: static int
709: isStandaloneCallback(void *ctx ATTRIBUTE_UNUSED)
710: {
711: callbacks++;
712: return (0);
713: }
714:
715: /**
716: * hasInternalSubsetCallback:
717: * @ctxt: An XML parser context
718: *
719: * Does this document has an internal subset
720: *
721: * Returns 1 if true
722: */
723: static int
724: hasInternalSubsetCallback(void *ctx ATTRIBUTE_UNUSED)
725: {
726: callbacks++;
727: return (0);
728: }
729:
730: /**
731: * hasExternalSubsetCallback:
732: * @ctxt: An XML parser context
733: *
734: * Does this document has an external subset
735: *
736: * Returns 1 if true
737: */
738: static int
739: hasExternalSubsetCallback(void *ctx ATTRIBUTE_UNUSED)
740: {
741: callbacks++;
742: return (0);
743: }
744:
745: /**
746: * internalSubsetCallback:
747: * @ctxt: An XML parser context
748: *
749: * Does this document has an internal subset
750: */
751: static void
752: internalSubsetCallback(void *ctx ATTRIBUTE_UNUSED,
753: const xmlChar * name ATTRIBUTE_UNUSED,
754: const xmlChar * ExternalID ATTRIBUTE_UNUSED,
755: const xmlChar * SystemID ATTRIBUTE_UNUSED)
756: {
757: callbacks++;
758: return;
759: }
760:
761: /**
762: * externalSubsetCallback:
763: * @ctxt: An XML parser context
764: *
765: * Does this document has an external subset
766: */
767: static void
768: externalSubsetCallback(void *ctx ATTRIBUTE_UNUSED,
769: const xmlChar * name ATTRIBUTE_UNUSED,
770: const xmlChar * ExternalID ATTRIBUTE_UNUSED,
771: const xmlChar * SystemID ATTRIBUTE_UNUSED)
772: {
773: callbacks++;
774: return;
775: }
776:
777: /**
778: * resolveEntityCallback:
779: * @ctxt: An XML parser context
780: * @publicId: The public ID of the entity
781: * @systemId: The system ID of the entity
782: *
783: * Special entity resolver, better left to the parser, it has
784: * more context than the application layer.
785: * The default behaviour is to NOT resolve the entities, in that case
786: * the ENTITY_REF nodes are built in the structure (and the parameter
787: * values).
788: *
789: * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
790: */
791: static xmlParserInputPtr
792: resolveEntityCallback(void *ctx ATTRIBUTE_UNUSED,
793: const xmlChar * publicId ATTRIBUTE_UNUSED,
794: const xmlChar * systemId ATTRIBUTE_UNUSED)
795: {
796: callbacks++;
797: return (NULL);
798: }
799:
800: /**
801: * getEntityCallback:
802: * @ctxt: An XML parser context
803: * @name: The entity name
804: *
805: * Get an entity by name
806: *
807: * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
808: */
809: static xmlEntityPtr
810: getEntityCallback(void *ctx ATTRIBUTE_UNUSED,
811: const xmlChar * name ATTRIBUTE_UNUSED)
812: {
813: callbacks++;
814: return (NULL);
815: }
816:
817: /**
818: * getParameterEntityCallback:
819: * @ctxt: An XML parser context
820: * @name: The entity name
821: *
822: * Get a parameter entity by name
823: *
824: * Returns the xmlParserInputPtr
825: */
826: static xmlEntityPtr
827: getParameterEntityCallback(void *ctx ATTRIBUTE_UNUSED,
828: const xmlChar * name ATTRIBUTE_UNUSED)
829: {
830: callbacks++;
831: return (NULL);
832: }
833:
834:
835: /**
836: * entityDeclCallback:
837: * @ctxt: An XML parser context
838: * @name: the entity name
839: * @type: the entity type
840: * @publicId: The public ID of the entity
841: * @systemId: The system ID of the entity
842: * @content: the entity value (without processing).
843: *
844: * An entity definition has been parsed
845: */
846: static void
847: entityDeclCallback(void *ctx ATTRIBUTE_UNUSED,
848: const xmlChar * name ATTRIBUTE_UNUSED,
849: int type ATTRIBUTE_UNUSED,
850: const xmlChar * publicId ATTRIBUTE_UNUSED,
851: const xmlChar * systemId ATTRIBUTE_UNUSED,
852: xmlChar * content ATTRIBUTE_UNUSED)
853: {
854: callbacks++;
855: return;
856: }
857:
858: /**
859: * attributeDeclCallback:
860: * @ctxt: An XML parser context
861: * @name: the attribute name
862: * @type: the attribute type
863: *
864: * An attribute definition has been parsed
865: */
866: static void
867: attributeDeclCallback(void *ctx ATTRIBUTE_UNUSED,
868: const xmlChar * elem ATTRIBUTE_UNUSED,
869: const xmlChar * name ATTRIBUTE_UNUSED,
870: int type ATTRIBUTE_UNUSED, int def ATTRIBUTE_UNUSED,
871: const xmlChar * defaultValue ATTRIBUTE_UNUSED,
872: xmlEnumerationPtr tree ATTRIBUTE_UNUSED)
873: {
874: callbacks++;
875: return;
876: }
877:
878: /**
879: * elementDeclCallback:
880: * @ctxt: An XML parser context
881: * @name: the element name
882: * @type: the element type
883: * @content: the element value (without processing).
884: *
885: * An element definition has been parsed
886: */
887: static void
888: elementDeclCallback(void *ctx ATTRIBUTE_UNUSED,
889: const xmlChar * name ATTRIBUTE_UNUSED,
890: int type ATTRIBUTE_UNUSED,
891: xmlElementContentPtr content ATTRIBUTE_UNUSED)
892: {
893: callbacks++;
894: return;
895: }
896:
897: /**
898: * notationDeclCallback:
899: * @ctxt: An XML parser context
900: * @name: The name of the notation
901: * @publicId: The public ID of the entity
902: * @systemId: The system ID of the entity
903: *
904: * What to do when a notation declaration has been parsed.
905: */
906: static void
907: notationDeclCallback(void *ctx ATTRIBUTE_UNUSED,
908: const xmlChar * name ATTRIBUTE_UNUSED,
909: const xmlChar * publicId ATTRIBUTE_UNUSED,
910: const xmlChar * systemId ATTRIBUTE_UNUSED)
911: {
912: callbacks++;
913: return;
914: }
915:
916: /**
917: * unparsedEntityDeclCallback:
918: * @ctxt: An XML parser context
919: * @name: The name of the entity
920: * @publicId: The public ID of the entity
921: * @systemId: The system ID of the entity
922: * @notationName: the name of the notation
923: *
924: * What to do when an unparsed entity declaration is parsed
925: */
926: static void
927: unparsedEntityDeclCallback(void *ctx ATTRIBUTE_UNUSED,
928: const xmlChar * name ATTRIBUTE_UNUSED,
929: const xmlChar * publicId ATTRIBUTE_UNUSED,
930: const xmlChar * systemId ATTRIBUTE_UNUSED,
931: const xmlChar * notationName ATTRIBUTE_UNUSED)
932: {
933: callbacks++;
934: return;
935: }
936:
937: /**
938: * setDocumentLocatorCallback:
939: * @ctxt: An XML parser context
940: * @loc: A SAX Locator
941: *
942: * Receive the document locator at startup, actually xmlDefaultSAXLocator
943: * Everything is available on the context, so this is useless in our case.
944: */
945: static void
946: setDocumentLocatorCallback(void *ctx ATTRIBUTE_UNUSED,
947: xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
948: {
949: callbacks++;
950: return;
951: }
952:
953: /**
954: * startDocumentCallback:
955: * @ctxt: An XML parser context
956: *
957: * called when the document start being processed.
958: */
959: static void
960: startDocumentCallback(void *ctx ATTRIBUTE_UNUSED)
961: {
962: callbacks++;
963: return;
964: }
965:
966: /**
967: * endDocumentCallback:
968: * @ctxt: An XML parser context
969: *
970: * called when the document end has been detected.
971: */
972: static void
973: endDocumentCallback(void *ctx ATTRIBUTE_UNUSED)
974: {
975: callbacks++;
976: return;
977: }
978:
979: #if 0
980: /**
981: * startElementCallback:
982: * @ctxt: An XML parser context
983: * @name: The element name
984: *
985: * called when an opening tag has been processed.
986: */
987: static void
988: startElementCallback(void *ctx ATTRIBUTE_UNUSED,
989: const xmlChar * name ATTRIBUTE_UNUSED,
990: const xmlChar ** atts ATTRIBUTE_UNUSED)
991: {
992: callbacks++;
993: return;
994: }
995:
996: /**
997: * endElementCallback:
998: * @ctxt: An XML parser context
999: * @name: The element name
1000: *
1001: * called when the end of an element has been detected.
1002: */
1003: static void
1004: endElementCallback(void *ctx ATTRIBUTE_UNUSED,
1005: const xmlChar * name ATTRIBUTE_UNUSED)
1006: {
1007: callbacks++;
1008: return;
1009: }
1010: #endif
1011:
1012: /**
1013: * charactersCallback:
1014: * @ctxt: An XML parser context
1015: * @ch: a xmlChar string
1016: * @len: the number of xmlChar
1017: *
1018: * receiving some chars from the parser.
1019: * Question: how much at a time ???
1020: */
1021: static void
1022: charactersCallback(void *ctx ATTRIBUTE_UNUSED,
1023: const xmlChar * ch ATTRIBUTE_UNUSED,
1024: int len ATTRIBUTE_UNUSED)
1025: {
1026: callbacks++;
1027: return;
1028: }
1029:
1030: /**
1031: * referenceCallback:
1032: * @ctxt: An XML parser context
1033: * @name: The entity name
1034: *
1035: * called when an entity reference is detected.
1036: */
1037: static void
1038: referenceCallback(void *ctx ATTRIBUTE_UNUSED,
1039: const xmlChar * name ATTRIBUTE_UNUSED)
1040: {
1041: callbacks++;
1042: return;
1043: }
1044:
1045: /**
1046: * ignorableWhitespaceCallback:
1047: * @ctxt: An XML parser context
1048: * @ch: a xmlChar string
1049: * @start: the first char in the string
1050: * @len: the number of xmlChar
1051: *
1052: * receiving some ignorable whitespaces from the parser.
1053: * Question: how much at a time ???
1054: */
1055: static void
1056: ignorableWhitespaceCallback(void *ctx ATTRIBUTE_UNUSED,
1057: const xmlChar * ch ATTRIBUTE_UNUSED,
1058: int len ATTRIBUTE_UNUSED)
1059: {
1060: callbacks++;
1061: return;
1062: }
1063:
1064: /**
1065: * processingInstructionCallback:
1066: * @ctxt: An XML parser context
1067: * @target: the target name
1068: * @data: the PI data's
1069: * @len: the number of xmlChar
1070: *
1071: * A processing instruction has been parsed.
1072: */
1073: static void
1074: processingInstructionCallback(void *ctx ATTRIBUTE_UNUSED,
1075: const xmlChar * target ATTRIBUTE_UNUSED,
1076: const xmlChar * data ATTRIBUTE_UNUSED)
1077: {
1078: callbacks++;
1079: return;
1080: }
1081:
1082: /**
1083: * cdataBlockCallback:
1084: * @ctx: the user data (XML parser context)
1085: * @value: The pcdata content
1086: * @len: the block length
1087: *
1088: * called when a pcdata block has been parsed
1089: */
1090: static void
1091: cdataBlockCallback(void *ctx ATTRIBUTE_UNUSED,
1092: const xmlChar * value ATTRIBUTE_UNUSED,
1093: int len ATTRIBUTE_UNUSED)
1094: {
1095: callbacks++;
1096: return;
1097: }
1098:
1099: /**
1100: * commentCallback:
1101: * @ctxt: An XML parser context
1102: * @value: the comment content
1103: *
1104: * A comment has been parsed.
1105: */
1106: static void
1107: commentCallback(void *ctx ATTRIBUTE_UNUSED,
1108: const xmlChar * value ATTRIBUTE_UNUSED)
1109: {
1110: callbacks++;
1111: return;
1112: }
1113:
1114: /**
1115: * warningCallback:
1116: * @ctxt: An XML parser context
1117: * @msg: the message to display/transmit
1118: * @...: extra parameters for the message display
1119: *
1120: * Display and format a warning messages, gives file, line, position and
1121: * extra parameters.
1122: */
1123: static void XMLCDECL
1124: warningCallback(void *ctx ATTRIBUTE_UNUSED,
1125: const char *msg ATTRIBUTE_UNUSED, ...)
1126: {
1127: callbacks++;
1128: return;
1129: }
1130:
1131: /**
1132: * errorCallback:
1133: * @ctxt: An XML parser context
1134: * @msg: the message to display/transmit
1135: * @...: extra parameters for the message display
1136: *
1137: * Display and format a error messages, gives file, line, position and
1138: * extra parameters.
1139: */
1140: static void XMLCDECL
1141: errorCallback(void *ctx ATTRIBUTE_UNUSED, const char *msg ATTRIBUTE_UNUSED,
1142: ...)
1143: {
1144: callbacks++;
1145: return;
1146: }
1147:
1148: /**
1149: * fatalErrorCallback:
1150: * @ctxt: An XML parser context
1151: * @msg: the message to display/transmit
1152: * @...: extra parameters for the message display
1153: *
1154: * Display and format a fatalError messages, gives file, line, position and
1155: * extra parameters.
1156: */
1157: static void XMLCDECL
1158: fatalErrorCallback(void *ctx ATTRIBUTE_UNUSED,
1159: const char *msg ATTRIBUTE_UNUSED, ...)
1160: {
1161: return;
1162: }
1163:
1164:
1165: /*
1166: * SAX2 specific callbacks
1167: */
1168:
1169: /**
1170: * startElementNsCallback:
1171: * @ctxt: An XML parser context
1172: * @name: The element name
1173: *
1174: * called when an opening tag has been processed.
1175: */
1176: static void
1177: startElementNsCallback(void *ctx ATTRIBUTE_UNUSED,
1178: const xmlChar * localname ATTRIBUTE_UNUSED,
1179: const xmlChar * prefix ATTRIBUTE_UNUSED,
1180: const xmlChar * URI ATTRIBUTE_UNUSED,
1181: int nb_namespaces ATTRIBUTE_UNUSED,
1182: const xmlChar ** namespaces ATTRIBUTE_UNUSED,
1183: int nb_attributes ATTRIBUTE_UNUSED,
1184: int nb_defaulted ATTRIBUTE_UNUSED,
1185: const xmlChar ** attributes ATTRIBUTE_UNUSED)
1186: {
1187: callbacks++;
1188: return;
1189: }
1190:
1191: /**
1192: * endElementCallback:
1193: * @ctxt: An XML parser context
1194: * @name: The element name
1195: *
1196: * called when the end of an element has been detected.
1197: */
1198: static void
1199: endElementNsCallback(void *ctx ATTRIBUTE_UNUSED,
1200: const xmlChar * localname ATTRIBUTE_UNUSED,
1201: const xmlChar * prefix ATTRIBUTE_UNUSED,
1202: const xmlChar * URI ATTRIBUTE_UNUSED)
1203: {
1204: callbacks++;
1205: return;
1206: }
1207:
1208: static xmlSAXHandler callbackSAX2HandlerStruct = {
1209: internalSubsetCallback,
1210: isStandaloneCallback,
1211: hasInternalSubsetCallback,
1212: hasExternalSubsetCallback,
1213: resolveEntityCallback,
1214: getEntityCallback,
1215: entityDeclCallback,
1216: notationDeclCallback,
1217: attributeDeclCallback,
1218: elementDeclCallback,
1219: unparsedEntityDeclCallback,
1220: setDocumentLocatorCallback,
1221: startDocumentCallback,
1222: endDocumentCallback,
1223: NULL,
1224: NULL,
1225: referenceCallback,
1226: charactersCallback,
1227: ignorableWhitespaceCallback,
1228: processingInstructionCallback,
1229: commentCallback,
1230: warningCallback,
1231: errorCallback,
1232: fatalErrorCallback,
1233: getParameterEntityCallback,
1234: cdataBlockCallback,
1235: externalSubsetCallback,
1236: XML_SAX2_MAGIC,
1237: NULL,
1238: startElementNsCallback,
1239: endElementNsCallback,
1240: NULL
1241: };
1242:
1243: static xmlSAXHandlerPtr callbackSAX2Handler = &callbackSAX2HandlerStruct;
1244:
1245: /************************************************************************
1246: * *
1247: * The tests front-ends *
1248: * *
1249: ************************************************************************/
1250:
1251: /**
1252: * readerTest:
1253: * @filename: the file to parse
1254: * @max_size: size of the limit to test
1255: * @options: parsing options
1256: * @fail: should a failure be reported
1257: *
1258: * Parse a memory generated file using SAX
1259: *
1260: * Returns 0 in case of success, an error code otherwise
1261: */
1262: static int
1263: saxTest(const char *filename, size_t limit, int options, int fail) {
1264: int res = 0;
1265: xmlParserCtxtPtr ctxt;
1266: xmlDocPtr doc;
1267: xmlSAXHandlerPtr old_sax;
1268:
1269: nb_tests++;
1270:
1271: maxlen = limit;
1272: ctxt = xmlNewParserCtxt();
1273: if (ctxt == NULL) {
1274: fprintf(stderr, "Failed to create parser context\n");
1275: return(1);
1276: }
1277: old_sax = ctxt->sax;
1278: ctxt->sax = callbackSAX2Handler;
1279: ctxt->userData = NULL;
1280: doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
1281:
1282: if (doc != NULL) {
1283: fprintf(stderr, "SAX parsing generated a document !\n");
1284: xmlFreeDoc(doc);
1285: res = 0;
1286: } else if (ctxt->wellFormed == 0) {
1287: if (fail)
1288: res = 0;
1289: else {
1290: fprintf(stderr, "Failed to parse '%s' %lu\n", filename, limit);
1291: res = 1;
1292: }
1293: } else {
1294: if (fail) {
1295: fprintf(stderr, "Failed to get failure for '%s' %lu\n",
1296: filename, limit);
1297: res = 1;
1298: } else
1299: res = 0;
1300: }
1301: ctxt->sax = old_sax;
1302: xmlFreeParserCtxt(ctxt);
1303:
1304: return(res);
1305: }
1306: #ifdef LIBXML_READER_ENABLED
1307: /**
1308: * readerTest:
1309: * @filename: the file to parse
1310: * @max_size: size of the limit to test
1311: * @options: parsing options
1312: * @fail: should a failure be reported
1313: *
1314: * Parse a memory generated file using the xmlReader
1315: *
1316: * Returns 0 in case of success, an error code otherwise
1317: */
1318: static int
1319: readerTest(const char *filename, size_t limit, int options, int fail) {
1320: xmlTextReaderPtr reader;
1321: int res = 0;
1322: int ret;
1323:
1324: nb_tests++;
1325:
1326: maxlen = limit;
1327: reader = xmlReaderForFile(filename , NULL, options);
1328: if (reader == NULL) {
1329: fprintf(stderr, "Failed to open '%s' test\n", filename);
1330: return(1);
1331: }
1332: ret = xmlTextReaderRead(reader);
1333: while (ret == 1) {
1334: ret = xmlTextReaderRead(reader);
1335: }
1336: if (ret != 0) {
1337: if (fail)
1338: res = 0;
1339: else {
1340: if (strncmp(filename, "crazy:", 6) == 0)
1341: fprintf(stderr, "Failed to parse '%s' %u\n",
1342: filename, crazy_indx);
1343: else
1344: fprintf(stderr, "Failed to parse '%s' %lu\n",
1345: filename, limit);
1346: res = 1;
1347: }
1348: } else {
1349: if (fail) {
1350: if (strncmp(filename, "crazy:", 6) == 0)
1351: fprintf(stderr, "Failed to get failure for '%s' %u\n",
1352: filename, crazy_indx);
1353: else
1354: fprintf(stderr, "Failed to get failure for '%s' %lu\n",
1355: filename, limit);
1356: res = 1;
1357: } else
1358: res = 0;
1359: }
1360: if (timeout)
1361: res = 1;
1362: xmlFreeTextReader(reader);
1363:
1364: return(res);
1365: }
1366: #endif
1367:
1368: /************************************************************************
1369: * *
1370: * Tests descriptions *
1371: * *
1372: ************************************************************************/
1373:
1374: typedef int (*functest) (const char *filename, size_t limit, int options,
1375: int fail);
1376:
1377: typedef struct limitDesc limitDesc;
1378: typedef limitDesc *limitDescPtr;
1379: struct limitDesc {
1380: const char *name; /* the huge generator name */
1381: size_t limit; /* the limit to test */
1382: int options; /* extra parser options */
1383: int fail; /* whether the test should fail */
1384: };
1385:
1386: static limitDesc limitDescriptions[] = {
1387: /* max length of a text node in content */
1388: {"huge:textNode", XML_MAX_TEXT_LENGTH - CHUNK, 0, 0},
1389: {"huge:textNode", XML_MAX_TEXT_LENGTH + CHUNK, 0, 1},
1390: {"huge:textNode", XML_MAX_TEXT_LENGTH + CHUNK, XML_PARSE_HUGE, 0},
1391: /* max length of a text node in content */
1392: {"huge:attrNode", XML_MAX_TEXT_LENGTH - CHUNK, 0, 0},
1393: {"huge:attrNode", XML_MAX_TEXT_LENGTH + CHUNK, 0, 1},
1394: {"huge:attrNode", XML_MAX_TEXT_LENGTH + CHUNK, XML_PARSE_HUGE, 0},
1395: /* max length of a comment node */
1396: {"huge:commentNode", XML_MAX_TEXT_LENGTH - CHUNK, 0, 0},
1397: {"huge:commentNode", XML_MAX_TEXT_LENGTH + CHUNK, 0, 1},
1398: {"huge:commentNode", XML_MAX_TEXT_LENGTH + CHUNK, XML_PARSE_HUGE, 0},
1399: /* max length of a PI node */
1400: {"huge:piNode", XML_MAX_TEXT_LENGTH - CHUNK, 0, 0},
1401: {"huge:piNode", XML_MAX_TEXT_LENGTH + CHUNK, 0, 1},
1402: {"huge:piNode", XML_MAX_TEXT_LENGTH + CHUNK, XML_PARSE_HUGE, 0},
1403: };
1404:
1405: typedef struct testDesc testDesc;
1406: typedef testDesc *testDescPtr;
1407: struct testDesc {
1408: const char *desc; /* descripton of the test */
1409: functest func; /* function implementing the test */
1410: };
1411:
1412: static
1413: testDesc testDescriptions[] = {
1414: { "Parsing of huge files with the sax parser", saxTest},
1415: /* { "Parsing of huge files with the tree parser", treeTest}, */
1416: #ifdef LIBXML_READER_ENABLED
1417: { "Parsing of huge files with the reader", readerTest},
1418: #endif
1419: {NULL, NULL}
1420: };
1421:
1422: typedef struct testException testException;
1423: typedef testException *testExceptionPtr;
1424: struct testException {
1425: unsigned int test; /* the parser test number */
1426: unsigned int limit; /* the limit test number */
1427: int fail; /* new fail value or -1*/
1428: size_t size; /* new limit value or 0 */
1429: };
1430:
1431: static
1432: testException testExceptions[] = {
1433: /* the SAX parser doesn't hit a limit of XML_MAX_TEXT_LENGTH text nodes */
1434: { 0, 1, 0, 0},
1435: };
1436:
1437: static int
1438: launchTests(testDescPtr tst, unsigned int test) {
1439: int res = 0, err = 0;
1440: unsigned int i, j;
1441: size_t limit;
1442: int fail;
1443:
1444: if (tst == NULL) return(-1);
1445:
1446: for (i = 0;i < sizeof(limitDescriptions)/sizeof(limitDescriptions[0]);i++) {
1447: limit = limitDescriptions[i].limit;
1448: fail = limitDescriptions[i].fail;
1449: /*
1450: * Handle exceptions if any
1451: */
1452: for (j = 0;j < sizeof(testExceptions)/sizeof(testExceptions[0]);j++) {
1453: if ((testExceptions[j].test == test) &&
1454: (testExceptions[j].limit == i)) {
1455: if (testExceptions[j].fail != -1)
1456: fail = testExceptions[j].fail;
1457: if (testExceptions[j].size != 0)
1458: limit = testExceptions[j].size;
1459: break;
1460: }
1461: }
1462: res = tst->func(limitDescriptions[i].name, limit,
1463: limitDescriptions[i].options, fail);
1464: if (res != 0) {
1465: nb_errors++;
1466: err++;
1467: }
1468: }
1469: return(err);
1470: }
1471:
1472:
1473: static int
1474: runtest(unsigned int i) {
1475: int ret = 0, res;
1476: int old_errors, old_tests, old_leaks;
1477:
1478: old_errors = nb_errors;
1479: old_tests = nb_tests;
1480: old_leaks = nb_leaks;
1481: if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
1482: printf("## %s\n", testDescriptions[i].desc);
1483: res = launchTests(&testDescriptions[i], i);
1484: if (res != 0)
1485: ret++;
1486: if (verbose) {
1487: if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1488: printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1489: else
1490: printf("Ran %d tests, %d errors, %d leaks\n",
1491: nb_tests - old_tests,
1492: nb_errors - old_errors,
1493: nb_leaks - old_leaks);
1494: }
1495: return(ret);
1496: }
1497:
1498: static int
1499: launchCrazySAX(unsigned int test, int fail) {
1500: int res = 0, err = 0;
1501:
1502: crazy_indx = test;
1503:
1504: res = saxTest("crazy::test", XML_MAX_LOOKUP_LIMIT - CHUNK, 0, fail);
1505: if (res != 0) {
1506: nb_errors++;
1507: err++;
1508: }
1509: if (tests_quiet == 0)
1510: fprintf(stderr, "%c", crazy[test]);
1511:
1512: return(err);
1513: }
1514:
1515: static int
1516: launchCrazy(unsigned int test, int fail) {
1517: int res = 0, err = 0;
1518:
1519: crazy_indx = test;
1520:
1521: res = readerTest("crazy::test", XML_MAX_LOOKUP_LIMIT - CHUNK, 0, fail);
1522: if (res != 0) {
1523: nb_errors++;
1524: err++;
1525: }
1526: if (tests_quiet == 0)
1527: fprintf(stderr, "%c", crazy[test]);
1528:
1529: return(err);
1530: }
1531:
1532: static int get_crazy_fail(int test) {
1533: /*
1534: * adding 1000000 of character 'a' leads to parser failure mostly
1535: * everywhere except in those special spots. Need to be updated
1536: * each time crazy is updated
1537: */
1538: int fail = 1;
1539: if ((test == 44) || /* PI in Misc */
1540: ((test >= 50) && (test <= 55)) || /* Comment in Misc */
1541: (test == 79) || /* PI in DTD */
1542: ((test >= 85) && (test <= 90)) || /* Comment in DTD */
1543: (test == 154) || /* PI in Misc */
1544: ((test >= 160) && (test <= 165)) || /* Comment in Misc */
1545: ((test >= 178) && (test <= 181)) || /* attribute value */
1546: (test == 183) || /* Text */
1547: (test == 189) || /* PI in Content */
1548: (test == 191) || /* Text */
1549: ((test >= 195) && (test <= 200)) || /* Comment in Content */
1550: ((test >= 203) && (test <= 206)) || /* Text */
1551: (test == 215) || (test == 216) || /* in CDATA */
1552: (test == 219) || /* Text */
1553: (test == 231) || /* PI in Misc */
1554: ((test >= 237) && (test <= 242))) /* Comment in Misc */
1555: fail = 0;
1556: return(fail);
1557: }
1558:
1559: static int
1560: runcrazy(void) {
1561: int ret = 0, res = 0;
1562: int old_errors, old_tests, old_leaks;
1563: unsigned int i;
1564:
1565: old_errors = nb_errors;
1566: old_tests = nb_tests;
1567: old_leaks = nb_leaks;
1568: if (tests_quiet == 0) {
1569: printf("## Crazy tests on reader\n");
1570: }
1571: for (i = 0;i < strlen(crazy);i++) {
1572: res += launchCrazy(i, get_crazy_fail(i));
1573: if (res != 0)
1574: ret++;
1575: }
1576: if (tests_quiet == 0) {
1577: printf("\n## Crazy tests on SAX\n");
1578: }
1579: for (i = 0;i < strlen(crazy);i++) {
1580: res += launchCrazySAX(i, get_crazy_fail(i));
1581: if (res != 0)
1582: ret++;
1583: }
1584: if (tests_quiet == 0)
1585: fprintf(stderr, "\n");
1586: if (verbose) {
1587: if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1588: printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1589: else
1590: printf("Ran %d tests, %d errors, %d leaks\n",
1591: nb_tests - old_tests,
1592: nb_errors - old_errors,
1593: nb_leaks - old_leaks);
1594: }
1595: return(ret);
1596: }
1597:
1598:
1599: int
1600: main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
1601: int i, a, ret = 0;
1602: int subset = 0;
1603:
1604: fillFilling();
1605: initializeLibxml2();
1606:
1607: for (a = 1; a < argc;a++) {
1608: if (!strcmp(argv[a], "-v"))
1609: verbose = 1;
1610: else if (!strcmp(argv[a], "-quiet"))
1611: tests_quiet = 1;
1612: else if (!strcmp(argv[a], "-crazy"))
1613: subset = 1;
1614: }
1615: if (subset == 0) {
1616: for (i = 0; testDescriptions[i].func != NULL; i++) {
1617: ret += runtest(i);
1618: }
1619: }
1620: ret += runcrazy();
1621: if ((nb_errors == 0) && (nb_leaks == 0)) {
1622: ret = 0;
1623: printf("Total %d tests, no errors\n",
1624: nb_tests);
1625: } else {
1626: ret = 1;
1627: printf("Total %d tests, %d errors, %d leaks\n",
1628: nb_tests, nb_errors, nb_leaks);
1629: }
1630: xmlCleanupParser();
1631: xmlMemoryDump();
1632:
1633: return(ret);
1634: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>