VirtualBox

source: vbox/trunk/src/libs/libxml2-2.12.6/testlimits.c

Last change on this file was 104106, checked in by vboxsync, 8 weeks ago

libxml2-2.9.14: Applied and adjusted our libxml2 changes to 2.9.14. bugref:10640

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

© 2023 Oracle
ContactPrivacy policyTerms of Use