2012-07-18 13:43:34 +04:00
/*
* testlimits . c : C program to run libxml2 regression tests checking various
* limits in document size . Will consume a lot of RAM and CPU cycles
*
* To compile on Unixes :
* cc - o testlimits ` xml2 - config - - cflags ` testlimits . c ` xml2 - config - - libs ` - lpthread
*
* See Copyright for the status of this software .
*
* daniel @ veillard . com
*/
# include "libxml.h"
# include <stdio.h>
2022-03-01 00:42:10 +03:00
# if !defined(_WIN32)
2012-07-18 13:43:34 +04:00
# include <unistd.h>
# endif
# include <string.h>
# include <sys/stat.h>
# include <fcntl.h>
2012-08-15 10:30:10 +04:00
# include <time.h>
2012-07-18 13:43:34 +04:00
# include <libxml/parser.h>
# include <libxml/parserInternals.h>
# include <libxml/tree.h>
# include <libxml/uri.h>
# ifdef LIBXML_READER_ENABLED
# include <libxml/xmlreader.h>
# endif
static int verbose = 0 ;
static int tests_quiet = 0 ;
2012-08-03 08:04:09 +04:00
/************************************************************************
* *
* time handling *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-08-15 10:30:10 +04:00
/* maximum time for one parsing before declaring a timeout */
2012-08-03 08:04:09 +04:00
# define MAX_TIME 2 /* seconds */
2012-08-15 10:30:10 +04:00
static clock_t t0 ;
2012-08-03 08:04:09 +04:00
int timeout = 0 ;
static void reset_timout ( void ) {
timeout = 0 ;
2012-08-15 10:30:10 +04:00
t0 = clock ( ) ;
2012-08-03 08:04:09 +04:00
}
static int check_time ( void ) {
2012-08-15 10:30:10 +04:00
clock_t tnow = clock ( ) ;
if ( ( ( tnow - t0 ) / CLOCKS_PER_SEC ) > MAX_TIME ) {
2012-08-03 08:04:09 +04:00
timeout = 1 ;
return ( 0 ) ;
}
return ( 1 ) ;
}
2012-07-18 13:43:34 +04:00
/************************************************************************
* *
* Huge document generator *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <libxml/xmlIO.h>
/*
* Huge documents are built using fixed start and end chunks
* and filling between the two an unconventional amount of char data
*/
typedef struct hugeTest hugeTest ;
typedef hugeTest * hugeTestPtr ;
struct hugeTest {
const char * description ;
const char * name ;
const char * start ;
const char * end ;
} ;
static struct hugeTest hugeTests [ ] = {
{ " Huge text node " , " huge:textNode " , " <foo> " , " </foo> " } ,
{ " Huge attribute node " , " huge:attrNode " , " <foo bar=' " , " '/> " } ,
{ " Huge comment node " , " huge:commentNode " , " <foo><!-- " , " --></foo> " } ,
2012-07-19 16:36:43 +04:00
{ " Huge PI node " , " huge:piNode " , " <foo><?bar " , " ?></foo> " } ,
2012-07-18 13:43:34 +04:00
} ;
static const char * current ;
static int rlen ;
static unsigned int currentTest = 0 ;
static int instate = 0 ;
/**
* hugeMatch :
* @ URI : an URI to test
*
* Check for an huge : query
*
* Returns 1 if yes and 0 if another Input module should be used
*/
static int
hugeMatch ( const char * URI ) {
if ( ( URI ! = NULL ) & & ( ! strncmp ( URI , " huge: " , 5 ) ) )
return ( 1 ) ;
return ( 0 ) ;
}
/**
* hugeOpen :
* @ URI : an URI to test
*
* Return a pointer to the huge : query handler , in this example simply
* the current pointer . . .
*
* Returns an Input context or NULL in case or error
*/
static void *
hugeOpen ( const char * URI ) {
if ( ( URI = = NULL ) | | ( strncmp ( URI , " huge: " , 5 ) ) )
return ( NULL ) ;
for ( currentTest = 0 ; currentTest < sizeof ( hugeTests ) / sizeof ( hugeTests [ 0 ] ) ;
currentTest + + )
if ( ! strcmp ( hugeTests [ currentTest ] . name , URI ) )
goto found ;
return ( NULL ) ;
found :
rlen = strlen ( hugeTests [ currentTest ] . start ) ;
current = hugeTests [ currentTest ] . start ;
instate = 0 ;
return ( ( void * ) current ) ;
}
/**
* hugeClose :
* @ context : the read context
*
* Close the huge : query handler
*
* Returns 0 or - 1 in case of error
*/
static int
hugeClose ( void * context ) {
if ( context = = NULL ) return ( - 1 ) ;
2012-08-03 08:04:09 +04:00
fprintf ( stderr , " \n " ) ;
2012-07-18 13:43:34 +04:00
return ( 0 ) ;
}
# define CHUNK 4096
char filling [ CHUNK + 1 ] ;
static void fillFilling ( void ) {
int i ;
for ( i = 0 ; i < CHUNK ; i + + ) {
filling [ i ] = ' a ' ;
}
filling [ CHUNK ] = 0 ;
}
size_t maxlen = 64 * 1024 * 1024 ;
size_t curlen = 0 ;
size_t dotlen ;
/**
* hugeRead :
* @ context : the read context
* @ buffer : where to store data
* @ len : number of bytes to read
*
* Implement an huge : query read .
*
* Returns the number of bytes read or - 1 in case of error
*/
static int
hugeRead ( void * context , char * buffer , int len )
{
if ( ( context = = NULL ) | | ( buffer = = NULL ) | | ( len < 0 ) )
return ( - 1 ) ;
if ( instate = = 0 ) {
if ( len > = rlen ) {
len = rlen ;
rlen = 0 ;
memcpy ( buffer , current , len ) ;
instate = 1 ;
curlen = 0 ;
dotlen = maxlen / 10 ;
} else {
memcpy ( buffer , current , len ) ;
rlen - = len ;
current + = len ;
}
} else if ( instate = = 2 ) {
if ( len > = rlen ) {
len = rlen ;
rlen = 0 ;
memcpy ( buffer , current , len ) ;
instate = 3 ;
curlen = 0 ;
} else {
memcpy ( buffer , current , len ) ;
rlen - = len ;
current + = len ;
}
} else if ( instate = = 1 ) {
if ( len > CHUNK ) len = CHUNK ;
memcpy ( buffer , & filling [ 0 ] , len ) ;
curlen + = len ;
if ( curlen > = maxlen ) {
rlen = strlen ( hugeTests [ currentTest ] . end ) ;
current = hugeTests [ currentTest ] . end ;
instate = 2 ;
} else {
if ( curlen > dotlen ) {
fprintf ( stderr , " . " ) ;
dotlen + = maxlen / 10 ;
}
}
} else
len = 0 ;
return ( len ) ;
}
2012-08-03 08:04:09 +04:00
/************************************************************************
* *
* Crazy document generator *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
unsigned int crazy_indx = 0 ;
const char * crazy = " <?xml version='1.0' encoding='UTF-8'?> \
< ? tst ? > \
< ! - - tst - - > \
< ! DOCTYPE foo [ \
< ? tst ? > \
< ! - - tst - - > \
< ! ELEMENT foo ( # PCDATA ) > \
< ! ELEMENT p ( # PCDATA | emph ) * > \
] > \
< ? tst ? > \
< ! - - tst - - > \
< foo bar = ' foo ' > \
< ? tst ? > \
< ! - - tst - - > \
foo \
< ! [ CDATA [ ] ] > \
< / foo > \
< ? tst ? > \
< ! - - tst - - > " ;
/**
* crazyMatch :
* @ URI : an URI to test
*
* Check for a crazy : query
*
* Returns 1 if yes and 0 if another Input module should be used
*/
static int
crazyMatch ( const char * URI ) {
if ( ( URI ! = NULL ) & & ( ! strncmp ( URI , " crazy: " , 6 ) ) )
return ( 1 ) ;
return ( 0 ) ;
}
/**
* crazyOpen :
* @ URI : an URI to test
*
* Return a pointer to the crazy : query handler , in this example simply
* the current pointer . . .
*
* Returns an Input context or NULL in case or error
*/
static void *
crazyOpen ( const char * URI ) {
if ( ( URI = = NULL ) | | ( strncmp ( URI , " crazy: " , 6 ) ) )
return ( NULL ) ;
if ( crazy_indx > strlen ( crazy ) )
return ( NULL ) ;
reset_timout ( ) ;
rlen = crazy_indx ;
current = & crazy [ 0 ] ;
instate = 0 ;
return ( ( void * ) current ) ;
}
/**
* crazyClose :
* @ context : the read context
*
* Close the crazy : query handler
*
* Returns 0 or - 1 in case of error
*/
static int
crazyClose ( void * context ) {
if ( context = = NULL ) return ( - 1 ) ;
return ( 0 ) ;
}
/**
* crazyRead :
* @ context : the read context
* @ buffer : where to store data
* @ len : number of bytes to read
*
* Implement an crazy : query read .
*
* Returns the number of bytes read or - 1 in case of error
*/
static int
crazyRead ( void * context , char * buffer , int len )
{
if ( ( context = = NULL ) | | ( buffer = = NULL ) | | ( len < 0 ) )
return ( - 1 ) ;
if ( ( check_time ( ) < = 0 ) & & ( instate = = 1 ) ) {
fprintf ( stderr , " \n timeout in crazy(%d) \n " , crazy_indx ) ;
rlen = strlen ( crazy ) - crazy_indx ;
current = & crazy [ crazy_indx ] ;
instate = 2 ;
}
if ( instate = = 0 ) {
if ( len > = rlen ) {
len = rlen ;
rlen = 0 ;
memcpy ( buffer , current , len ) ;
instate = 1 ;
curlen = 0 ;
} else {
memcpy ( buffer , current , len ) ;
rlen - = len ;
current + = len ;
}
} else if ( instate = = 2 ) {
if ( len > = rlen ) {
len = rlen ;
rlen = 0 ;
memcpy ( buffer , current , len ) ;
instate = 3 ;
curlen = 0 ;
} else {
memcpy ( buffer , current , len ) ;
rlen - = len ;
current + = len ;
}
} else if ( instate = = 1 ) {
if ( len > CHUNK ) len = CHUNK ;
memcpy ( buffer , & filling [ 0 ] , len ) ;
curlen + = len ;
if ( curlen > = maxlen ) {
rlen = strlen ( crazy ) - crazy_indx ;
current = & crazy [ crazy_indx ] ;
instate = 2 ;
}
} else
len = 0 ;
return ( len ) ;
}
2012-07-18 13:43:34 +04:00
/************************************************************************
* *
* Libxml2 specific routines *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int nb_tests = 0 ;
static int nb_errors = 0 ;
static int nb_leaks = 0 ;
static int extraMemoryFromResolver = 0 ;
/*
* We need to trap calls to the resolver to not account memory for the catalog
* which is shared to the current running test . We also don ' t want to have
* network downloads modifying tests .
*/
static xmlParserInputPtr
testExternalEntityLoader ( const char * URL , const char * ID ,
xmlParserCtxtPtr ctxt ) {
xmlParserInputPtr ret ;
int memused = xmlMemUsed ( ) ;
ret = xmlNoNetExternalEntityLoader ( URL , ID , ctxt ) ;
extraMemoryFromResolver + = xmlMemUsed ( ) - memused ;
return ( ret ) ;
}
/*
* Trapping the error messages at the generic level to grab the equivalent of
* stderr messages on CLI tools .
*/
static char testErrors [ 32769 ] ;
static int testErrorsSize = 0 ;
static void XMLCDECL
channel ( void * ctx ATTRIBUTE_UNUSED , const char * msg , . . . ) {
va_list args ;
int res ;
if ( testErrorsSize > = 32768 )
return ;
va_start ( args , msg ) ;
res = vsnprintf ( & testErrors [ testErrorsSize ] ,
32768 - testErrorsSize ,
msg , args ) ;
va_end ( args ) ;
if ( testErrorsSize + res > = 32768 ) {
/* buffer is full */
testErrorsSize = 32768 ;
testErrors [ testErrorsSize ] = 0 ;
} else {
testErrorsSize + = res ;
}
testErrors [ testErrorsSize ] = 0 ;
}
/**
* xmlParserPrintFileContext :
* @ input : an xmlParserInputPtr input
*
* Displays current context within the input content for error tracking
*/
static void
xmlParserPrintFileContextInternal ( xmlParserInputPtr input ,
xmlGenericErrorFunc chanl , void * data ) {
const xmlChar * cur , * base ;
unsigned int n , col ; /* GCC warns if signed, because compared with sizeof() */
xmlChar content [ 81 ] ; /* space for 80 chars + line terminator */
xmlChar * ctnt ;
if ( input = = NULL ) return ;
cur = input - > cur ;
base = input - > base ;
/* skip backwards over any end-of-lines */
while ( ( cur > base ) & & ( ( * ( cur ) = = ' \n ' ) | | ( * ( cur ) = = ' \r ' ) ) ) {
cur - - ;
}
n = 0 ;
/* search backwards for beginning-of-line (to max buff size) */
while ( ( n + + < ( sizeof ( content ) - 1 ) ) & & ( cur > base ) & &
( * ( cur ) ! = ' \n ' ) & & ( * ( cur ) ! = ' \r ' ) )
cur - - ;
if ( ( * ( cur ) = = ' \n ' ) | | ( * ( cur ) = = ' \r ' ) ) cur + + ;
/* calculate the error position in terms of the current position */
col = input - > cur - cur ;
/* search forward for end-of-line (to max buff size) */
n = 0 ;
ctnt = content ;
/* copy selected text to our buffer */
while ( ( * cur ! = 0 ) & & ( * ( cur ) ! = ' \n ' ) & &
( * ( cur ) ! = ' \r ' ) & & ( n < sizeof ( content ) - 1 ) ) {
* ctnt + + = * cur + + ;
n + + ;
}
* ctnt = 0 ;
/* print out the selected text */
chanl ( data , " %s \n " , content ) ;
/* create blank line with problem pointer */
n = 0 ;
ctnt = content ;
/* (leave buffer space for pointer + line terminator) */
while ( ( n < col ) & & ( n + + < sizeof ( content ) - 2 ) & & ( * ctnt ! = 0 ) ) {
if ( * ( ctnt ) ! = ' \t ' )
* ( ctnt ) = ' ' ;
ctnt + + ;
}
* ctnt + + = ' ^ ' ;
* ctnt = 0 ;
chanl ( data , " %s \n " , content ) ;
}
static void
testStructuredErrorHandler ( void * ctx ATTRIBUTE_UNUSED , xmlErrorPtr err ) {
char * file = NULL ;
int line = 0 ;
int code = - 1 ;
int domain ;
void * data = NULL ;
const char * str ;
const xmlChar * name = NULL ;
xmlNodePtr node ;
xmlErrorLevel level ;
xmlParserInputPtr input = NULL ;
xmlParserInputPtr cur = NULL ;
xmlParserCtxtPtr ctxt = NULL ;
if ( err = = NULL )
return ;
file = err - > file ;
line = err - > line ;
code = err - > code ;
domain = err - > domain ;
level = err - > level ;
node = err - > node ;
if ( ( domain = = XML_FROM_PARSER ) | | ( domain = = XML_FROM_HTML ) | |
( domain = = XML_FROM_DTD ) | | ( domain = = XML_FROM_NAMESPACE ) | |
( domain = = XML_FROM_IO ) | | ( domain = = XML_FROM_VALID ) ) {
ctxt = err - > ctxt ;
}
str = err - > message ;
if ( code = = XML_ERR_OK )
return ;
if ( ( node ! = NULL ) & & ( node - > type = = XML_ELEMENT_NODE ) )
name = node - > name ;
/*
* Maintain the compatibility with the legacy error handling
*/
if ( ctxt ! = NULL ) {
input = ctxt - > input ;
if ( ( input ! = NULL ) & & ( input - > filename = = NULL ) & &
( ctxt - > inputNr > 1 ) ) {
cur = input ;
input = ctxt - > inputTab [ ctxt - > inputNr - 2 ] ;
}
if ( input ! = NULL ) {
if ( input - > filename )
channel ( data , " %s:%d: " , input - > filename , input - > line ) ;
else if ( ( line ! = 0 ) & & ( domain = = XML_FROM_PARSER ) )
channel ( data , " Entity: line %d: " , input - > line ) ;
}
} else {
if ( file ! = NULL )
channel ( data , " %s:%d: " , file , line ) ;
else if ( ( line ! = 0 ) & & ( domain = = XML_FROM_PARSER ) )
channel ( data , " Entity: line %d: " , line ) ;
}
if ( name ! = NULL ) {
channel ( data , " element %s: " , name ) ;
}
if ( code = = XML_ERR_OK )
return ;
switch ( domain ) {
case XML_FROM_PARSER :
channel ( data , " parser " ) ;
break ;
case XML_FROM_NAMESPACE :
channel ( data , " namespace " ) ;
break ;
case XML_FROM_DTD :
case XML_FROM_VALID :
channel ( data , " validity " ) ;
break ;
case XML_FROM_HTML :
channel ( data , " HTML parser " ) ;
break ;
case XML_FROM_MEMORY :
channel ( data , " memory " ) ;
break ;
case XML_FROM_OUTPUT :
channel ( data , " output " ) ;
break ;
case XML_FROM_IO :
channel ( data , " I/O " ) ;
break ;
case XML_FROM_XINCLUDE :
channel ( data , " XInclude " ) ;
break ;
case XML_FROM_XPATH :
channel ( data , " XPath " ) ;
break ;
case XML_FROM_XPOINTER :
channel ( data , " parser " ) ;
break ;
case XML_FROM_REGEXP :
channel ( data , " regexp " ) ;
break ;
case XML_FROM_MODULE :
channel ( data , " module " ) ;
break ;
case XML_FROM_SCHEMASV :
channel ( data , " Schemas validity " ) ;
break ;
case XML_FROM_SCHEMASP :
channel ( data , " Schemas parser " ) ;
break ;
case XML_FROM_RELAXNGP :
channel ( data , " Relax-NG parser " ) ;
break ;
case XML_FROM_RELAXNGV :
channel ( data , " Relax-NG validity " ) ;
break ;
case XML_FROM_CATALOG :
channel ( data , " Catalog " ) ;
break ;
case XML_FROM_C14N :
channel ( data , " C14N " ) ;
break ;
case XML_FROM_XSLT :
channel ( data , " XSLT " ) ;
break ;
default :
break ;
}
if ( code = = XML_ERR_OK )
return ;
switch ( level ) {
case XML_ERR_NONE :
channel ( data , " : " ) ;
break ;
case XML_ERR_WARNING :
channel ( data , " warning : " ) ;
break ;
case XML_ERR_ERROR :
channel ( data , " error : " ) ;
break ;
case XML_ERR_FATAL :
channel ( data , " error : " ) ;
break ;
}
if ( code = = XML_ERR_OK )
return ;
if ( str ! = NULL ) {
int len ;
len = xmlStrlen ( ( const xmlChar * ) str ) ;
if ( ( len > 0 ) & & ( str [ len - 1 ] ! = ' \n ' ) )
channel ( data , " %s \n " , str ) ;
else
channel ( data , " %s " , str ) ;
} else {
channel ( data , " %s \n " , " out of memory error " ) ;
}
if ( code = = XML_ERR_OK )
return ;
if ( ctxt ! = NULL ) {
xmlParserPrintFileContextInternal ( input , channel , data ) ;
if ( cur ! = NULL ) {
if ( cur - > filename )
channel ( data , " %s:%d: \n " , cur - > filename , cur - > line ) ;
else if ( ( line ! = 0 ) & & ( domain = = XML_FROM_PARSER ) )
channel ( data , " Entity: line %d: \n " , cur - > line ) ;
xmlParserPrintFileContextInternal ( cur , channel , data ) ;
}
}
if ( ( domain = = XML_FROM_XPATH ) & & ( err - > str1 ! = NULL ) & &
( err - > int1 < 100 ) & &
( err - > int1 < xmlStrlen ( ( const xmlChar * ) err - > str1 ) ) ) {
xmlChar buf [ 150 ] ;
int i ;
channel ( data , " %s \n " , err - > str1 ) ;
for ( i = 0 ; i < err - > int1 ; i + + )
buf [ i ] = ' ' ;
buf [ i + + ] = ' ^ ' ;
buf [ i ] = 0 ;
channel ( data , " %s \n " , buf ) ;
}
}
static void
initializeLibxml2 ( void ) {
xmlGetWarningsDefaultValue = 0 ;
xmlPedanticParserDefault ( 0 ) ;
xmlMemSetup ( xmlMemFree , xmlMemMalloc , xmlMemRealloc , xmlMemoryStrdup ) ;
xmlInitParser ( ) ;
xmlSetExternalEntityLoader ( testExternalEntityLoader ) ;
xmlSetStructuredErrorFunc ( NULL , testStructuredErrorHandler ) ;
/*
* register the new I / O handlers
*/
if ( xmlRegisterInputCallbacks ( hugeMatch , hugeOpen ,
hugeRead , hugeClose ) < 0 ) {
fprintf ( stderr , " failed to register Huge handlers \n " ) ;
exit ( 1 ) ;
}
2012-08-03 08:04:09 +04:00
if ( xmlRegisterInputCallbacks ( crazyMatch , crazyOpen ,
crazyRead , crazyClose ) < 0 ) {
fprintf ( stderr , " failed to register Crazy handlers \n " ) ;
exit ( 1 ) ;
}
2012-07-18 13:43:34 +04:00
}
/************************************************************************
* *
* SAX empty callbacks *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
unsigned long callbacks = 0 ;
/**
* isStandaloneCallback :
* @ ctxt : An XML parser context
*
* Is this document tagged standalone ?
*
* Returns 1 if true
*/
static int
isStandaloneCallback ( void * ctx ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ( 0 ) ;
}
/**
* hasInternalSubsetCallback :
* @ ctxt : An XML parser context
*
* Does this document has an internal subset
*
* Returns 1 if true
*/
static int
hasInternalSubsetCallback ( void * ctx ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ( 0 ) ;
}
/**
* hasExternalSubsetCallback :
* @ ctxt : An XML parser context
*
* Does this document has an external subset
*
* Returns 1 if true
*/
static int
hasExternalSubsetCallback ( void * ctx ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ( 0 ) ;
}
/**
* internalSubsetCallback :
* @ ctxt : An XML parser context
*
* Does this document has an internal subset
*/
static void
internalSubsetCallback ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * name ATTRIBUTE_UNUSED ,
const xmlChar * ExternalID ATTRIBUTE_UNUSED ,
const xmlChar * SystemID ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ;
}
/**
* externalSubsetCallback :
* @ ctxt : An XML parser context
*
* Does this document has an external subset
*/
static void
externalSubsetCallback ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * name ATTRIBUTE_UNUSED ,
const xmlChar * ExternalID ATTRIBUTE_UNUSED ,
const xmlChar * SystemID ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ;
}
/**
* resolveEntityCallback :
* @ ctxt : An XML parser context
* @ publicId : The public ID of the entity
* @ systemId : The system ID of the entity
*
* Special entity resolver , better left to the parser , it has
* more context than the application layer .
* The default behaviour is to NOT resolve the entities , in that case
* the ENTITY_REF nodes are built in the structure ( and the parameter
* values ) .
*
* Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour .
*/
static xmlParserInputPtr
resolveEntityCallback ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * publicId ATTRIBUTE_UNUSED ,
const xmlChar * systemId ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ( NULL ) ;
}
/**
* getEntityCallback :
* @ ctxt : An XML parser context
* @ name : The entity name
*
* Get an entity by name
*
* Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour .
*/
static xmlEntityPtr
getEntityCallback ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * name ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ( NULL ) ;
}
/**
* getParameterEntityCallback :
* @ ctxt : An XML parser context
* @ name : The entity name
*
* Get a parameter entity by name
*
* Returns the xmlParserInputPtr
*/
static xmlEntityPtr
getParameterEntityCallback ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * name ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ( NULL ) ;
}
/**
* entityDeclCallback :
* @ ctxt : An XML parser context
2012-09-11 09:26:36 +04:00
* @ name : the entity name
* @ type : the entity type
2012-07-18 13:43:34 +04:00
* @ publicId : The public ID of the entity
* @ systemId : The system ID of the entity
* @ content : the entity value ( without processing ) .
*
* An entity definition has been parsed
*/
static void
entityDeclCallback ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * name ATTRIBUTE_UNUSED ,
int type ATTRIBUTE_UNUSED ,
const xmlChar * publicId ATTRIBUTE_UNUSED ,
const xmlChar * systemId ATTRIBUTE_UNUSED ,
xmlChar * content ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ;
}
/**
* attributeDeclCallback :
* @ ctxt : An XML parser context
2012-09-11 09:26:36 +04:00
* @ name : the attribute name
* @ type : the attribute type
2012-07-18 13:43:34 +04:00
*
* An attribute definition has been parsed
*/
static void
attributeDeclCallback ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * elem ATTRIBUTE_UNUSED ,
const xmlChar * name ATTRIBUTE_UNUSED ,
int type ATTRIBUTE_UNUSED , int def ATTRIBUTE_UNUSED ,
const xmlChar * defaultValue ATTRIBUTE_UNUSED ,
xmlEnumerationPtr tree ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ;
}
/**
* elementDeclCallback :
* @ ctxt : An XML parser context
2012-09-11 09:26:36 +04:00
* @ name : the element name
* @ type : the element type
2012-07-18 13:43:34 +04:00
* @ content : the element value ( without processing ) .
*
* An element definition has been parsed
*/
static void
elementDeclCallback ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * name ATTRIBUTE_UNUSED ,
int type ATTRIBUTE_UNUSED ,
xmlElementContentPtr content ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ;
}
/**
* notationDeclCallback :
* @ ctxt : An XML parser context
* @ name : The name of the notation
* @ publicId : The public ID of the entity
* @ systemId : The system ID of the entity
*
* What to do when a notation declaration has been parsed .
*/
static void
notationDeclCallback ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * name ATTRIBUTE_UNUSED ,
const xmlChar * publicId ATTRIBUTE_UNUSED ,
const xmlChar * systemId ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ;
}
/**
* unparsedEntityDeclCallback :
* @ ctxt : An XML parser context
* @ name : The name of the entity
* @ publicId : The public ID of the entity
* @ systemId : The system ID of the entity
* @ notationName : the name of the notation
*
* What to do when an unparsed entity declaration is parsed
*/
static void
unparsedEntityDeclCallback ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * name ATTRIBUTE_UNUSED ,
const xmlChar * publicId ATTRIBUTE_UNUSED ,
const xmlChar * systemId ATTRIBUTE_UNUSED ,
const xmlChar * notationName ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ;
}
/**
* setDocumentLocatorCallback :
* @ ctxt : An XML parser context
* @ loc : A SAX Locator
*
* Receive the document locator at startup , actually xmlDefaultSAXLocator
* Everything is available on the context , so this is useless in our case .
*/
static void
setDocumentLocatorCallback ( void * ctx ATTRIBUTE_UNUSED ,
xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ;
}
/**
* startDocumentCallback :
* @ ctxt : An XML parser context
*
* called when the document start being processed .
*/
static void
startDocumentCallback ( void * ctx ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ;
}
/**
* endDocumentCallback :
* @ ctxt : An XML parser context
*
* called when the document end has been detected .
*/
static void
endDocumentCallback ( void * ctx ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ;
}
#if 0
/**
* startElementCallback :
* @ ctxt : An XML parser context
* @ name : The element name
*
* called when an opening tag has been processed .
*/
static void
startElementCallback ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * name ATTRIBUTE_UNUSED ,
const xmlChar * * atts ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ;
}
/**
* endElementCallback :
* @ ctxt : An XML parser context
* @ name : The element name
*
* called when the end of an element has been detected .
*/
static void
endElementCallback ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * name ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ;
}
# endif
/**
* charactersCallback :
* @ ctxt : An XML parser context
* @ ch : a xmlChar string
* @ len : the number of xmlChar
*
* receiving some chars from the parser .
* Question : how much at a time ? ? ?
*/
static void
charactersCallback ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * ch ATTRIBUTE_UNUSED ,
int len ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ;
}
/**
* referenceCallback :
* @ ctxt : An XML parser context
* @ name : The entity name
*
2012-09-11 09:26:36 +04:00
* called when an entity reference is detected .
2012-07-18 13:43:34 +04:00
*/
static void
referenceCallback ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * name ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ;
}
/**
* ignorableWhitespaceCallback :
* @ ctxt : An XML parser context
* @ ch : a xmlChar string
* @ start : the first char in the string
* @ len : the number of xmlChar
*
* receiving some ignorable whitespaces from the parser .
* Question : how much at a time ? ? ?
*/
static void
ignorableWhitespaceCallback ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * ch ATTRIBUTE_UNUSED ,
int len ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ;
}
/**
* processingInstructionCallback :
* @ ctxt : An XML parser context
* @ target : the target name
* @ data : the PI data ' s
* @ len : the number of xmlChar
*
* A processing instruction has been parsed .
*/
static void
processingInstructionCallback ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * target ATTRIBUTE_UNUSED ,
const xmlChar * data ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ;
}
/**
* cdataBlockCallback :
* @ ctx : the user data ( XML parser context )
* @ value : The pcdata content
* @ len : the block length
*
* called when a pcdata block has been parsed
*/
static void
cdataBlockCallback ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * value ATTRIBUTE_UNUSED ,
int len ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ;
}
/**
* commentCallback :
* @ ctxt : An XML parser context
* @ value : the comment content
*
* A comment has been parsed .
*/
static void
commentCallback ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * value ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ;
}
/**
* warningCallback :
* @ ctxt : An XML parser context
* @ msg : the message to display / transmit
* @ . . . : extra parameters for the message display
*
* Display and format a warning messages , gives file , line , position and
* extra parameters .
*/
static void XMLCDECL
warningCallback ( void * ctx ATTRIBUTE_UNUSED ,
const char * msg ATTRIBUTE_UNUSED , . . . )
{
callbacks + + ;
return ;
}
/**
* errorCallback :
* @ ctxt : An XML parser context
* @ msg : the message to display / transmit
* @ . . . : extra parameters for the message display
*
* Display and format a error messages , gives file , line , position and
* extra parameters .
*/
static void XMLCDECL
errorCallback ( void * ctx ATTRIBUTE_UNUSED , const char * msg ATTRIBUTE_UNUSED ,
. . . )
{
callbacks + + ;
return ;
}
/**
* fatalErrorCallback :
* @ ctxt : An XML parser context
* @ msg : the message to display / transmit
* @ . . . : extra parameters for the message display
*
* Display and format a fatalError messages , gives file , line , position and
* extra parameters .
*/
static void XMLCDECL
fatalErrorCallback ( void * ctx ATTRIBUTE_UNUSED ,
const char * msg ATTRIBUTE_UNUSED , . . . )
{
return ;
}
/*
* SAX2 specific callbacks
*/
/**
* startElementNsCallback :
* @ ctxt : An XML parser context
* @ name : The element name
*
* called when an opening tag has been processed .
*/
static void
startElementNsCallback ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * localname ATTRIBUTE_UNUSED ,
const xmlChar * prefix ATTRIBUTE_UNUSED ,
const xmlChar * URI ATTRIBUTE_UNUSED ,
int nb_namespaces ATTRIBUTE_UNUSED ,
const xmlChar * * namespaces ATTRIBUTE_UNUSED ,
int nb_attributes ATTRIBUTE_UNUSED ,
int nb_defaulted ATTRIBUTE_UNUSED ,
const xmlChar * * attributes ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ;
}
/**
* endElementCallback :
* @ ctxt : An XML parser context
* @ name : The element name
*
* called when the end of an element has been detected .
*/
static void
endElementNsCallback ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * localname ATTRIBUTE_UNUSED ,
const xmlChar * prefix ATTRIBUTE_UNUSED ,
const xmlChar * URI ATTRIBUTE_UNUSED )
{
callbacks + + ;
return ;
}
static xmlSAXHandler callbackSAX2HandlerStruct = {
internalSubsetCallback ,
isStandaloneCallback ,
hasInternalSubsetCallback ,
hasExternalSubsetCallback ,
resolveEntityCallback ,
getEntityCallback ,
entityDeclCallback ,
notationDeclCallback ,
attributeDeclCallback ,
elementDeclCallback ,
unparsedEntityDeclCallback ,
setDocumentLocatorCallback ,
startDocumentCallback ,
endDocumentCallback ,
NULL ,
NULL ,
referenceCallback ,
charactersCallback ,
ignorableWhitespaceCallback ,
processingInstructionCallback ,
commentCallback ,
warningCallback ,
errorCallback ,
fatalErrorCallback ,
getParameterEntityCallback ,
cdataBlockCallback ,
externalSubsetCallback ,
XML_SAX2_MAGIC ,
NULL ,
startElementNsCallback ,
endElementNsCallback ,
NULL
} ;
static xmlSAXHandlerPtr callbackSAX2Handler = & callbackSAX2HandlerStruct ;
/************************************************************************
* *
* The tests front - ends *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* readerTest :
* @ filename : the file to parse
* @ max_size : size of the limit to test
* @ options : parsing options
* @ fail : should a failure be reported
*
2012-08-03 08:04:09 +04:00
* Parse a memory generated file using SAX
2012-07-18 13:43:34 +04:00
*
* Returns 0 in case of success , an error code otherwise
*/
static int
saxTest ( const char * filename , size_t limit , int options , int fail ) {
int res = 0 ;
xmlParserCtxtPtr ctxt ;
xmlDocPtr doc ;
nb_tests + + ;
maxlen = limit ;
2022-08-24 05:21:58 +03:00
ctxt = xmlNewSAXParserCtxt ( callbackSAX2Handler , NULL ) ;
2012-07-18 13:43:34 +04:00
if ( ctxt = = NULL ) {
fprintf ( stderr , " Failed to create parser context \n " ) ;
return ( 1 ) ;
}
doc = xmlCtxtReadFile ( ctxt , filename , NULL , options ) ;
if ( doc ! = NULL ) {
fprintf ( stderr , " SAX parsing generated a document ! \n " ) ;
xmlFreeDoc ( doc ) ;
res = 0 ;
} else if ( ctxt - > wellFormed = = 0 ) {
if ( fail )
res = 0 ;
else {
2016-08-22 12:44:18 +03:00
fprintf ( stderr , " Failed to parse '%s' %lu \n " , filename ,
( unsigned long ) limit ) ;
2012-07-18 13:43:34 +04:00
res = 1 ;
}
} else {
if ( fail ) {
fprintf ( stderr , " Failed to get failure for '%s' %lu \n " ,
2016-08-22 12:44:18 +03:00
filename , ( unsigned long ) limit ) ;
2012-07-18 13:43:34 +04:00
res = 1 ;
} else
res = 0 ;
}
xmlFreeParserCtxt ( ctxt ) ;
return ( res ) ;
}
# ifdef LIBXML_READER_ENABLED
/**
* readerTest :
* @ filename : the file to parse
* @ max_size : size of the limit to test
* @ options : parsing options
* @ fail : should a failure be reported
*
* Parse a memory generated file using the xmlReader
*
* Returns 0 in case of success , an error code otherwise
*/
static int
readerTest ( const char * filename , size_t limit , int options , int fail ) {
xmlTextReaderPtr reader ;
int res = 0 ;
int ret ;
nb_tests + + ;
maxlen = limit ;
reader = xmlReaderForFile ( filename , NULL , options ) ;
if ( reader = = NULL ) {
fprintf ( stderr , " Failed to open '%s' test \n " , filename ) ;
return ( 1 ) ;
}
ret = xmlTextReaderRead ( reader ) ;
while ( ret = = 1 ) {
ret = xmlTextReaderRead ( reader ) ;
}
if ( ret ! = 0 ) {
if ( fail )
res = 0 ;
else {
2012-09-11 09:26:36 +04:00
if ( strncmp ( filename , " crazy: " , 6 ) = = 0 )
2012-08-03 08:04:09 +04:00
fprintf ( stderr , " Failed to parse '%s' %u \n " ,
filename , crazy_indx ) ;
else
fprintf ( stderr , " Failed to parse '%s' %lu \n " ,
2016-08-22 12:44:18 +03:00
filename , ( unsigned long ) limit ) ;
2012-07-18 13:43:34 +04:00
res = 1 ;
}
} else {
if ( fail ) {
2012-09-11 09:26:36 +04:00
if ( strncmp ( filename , " crazy: " , 6 ) = = 0 )
2012-08-03 08:04:09 +04:00
fprintf ( stderr , " Failed to get failure for '%s' %u \n " ,
filename , crazy_indx ) ;
else
fprintf ( stderr , " Failed to get failure for '%s' %lu \n " ,
2016-08-22 12:44:18 +03:00
filename , ( unsigned long ) limit ) ;
2012-07-18 13:43:34 +04:00
res = 1 ;
} else
res = 0 ;
}
2012-08-03 08:04:09 +04:00
if ( timeout )
res = 1 ;
2012-07-18 13:43:34 +04:00
xmlFreeTextReader ( reader ) ;
return ( res ) ;
}
# endif
/************************************************************************
* *
* Tests descriptions *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
typedef int ( * functest ) ( const char * filename , size_t limit , int options ,
int fail ) ;
typedef struct limitDesc limitDesc ;
typedef limitDesc * limitDescPtr ;
struct limitDesc {
const char * name ; /* the huge generator name */
size_t limit ; /* the limit to test */
int options ; /* extra parser options */
int fail ; /* whether the test should fail */
} ;
static limitDesc limitDescriptions [ ] = {
2012-09-28 10:59:33 +04:00
/* max length of a text node in content */
2012-07-18 13:43:34 +04:00
{ " huge:textNode " , XML_MAX_TEXT_LENGTH - CHUNK , 0 , 0 } ,
{ " huge:textNode " , XML_MAX_TEXT_LENGTH + CHUNK , 0 , 1 } ,
{ " huge:textNode " , XML_MAX_TEXT_LENGTH + CHUNK , XML_PARSE_HUGE , 0 } ,
2012-09-28 10:59:33 +04:00
/* max length of a text node in content */
2012-07-18 13:43:34 +04:00
{ " huge:attrNode " , XML_MAX_TEXT_LENGTH - CHUNK , 0 , 0 } ,
{ " huge:attrNode " , XML_MAX_TEXT_LENGTH + CHUNK , 0 , 1 } ,
{ " huge:attrNode " , XML_MAX_TEXT_LENGTH + CHUNK , XML_PARSE_HUGE , 0 } ,
2012-09-28 10:59:33 +04:00
/* max length of a comment node */
2012-07-18 13:43:34 +04:00
{ " huge:commentNode " , XML_MAX_TEXT_LENGTH - CHUNK , 0 , 0 } ,
{ " huge:commentNode " , XML_MAX_TEXT_LENGTH + CHUNK , 0 , 1 } ,
{ " huge:commentNode " , XML_MAX_TEXT_LENGTH + CHUNK , XML_PARSE_HUGE , 0 } ,
2012-09-28 10:59:33 +04:00
/* max length of a PI node */
2012-07-19 16:36:43 +04:00
{ " huge:piNode " , XML_MAX_TEXT_LENGTH - CHUNK , 0 , 0 } ,
{ " huge:piNode " , XML_MAX_TEXT_LENGTH + CHUNK , 0 , 1 } ,
{ " huge:piNode " , XML_MAX_TEXT_LENGTH + CHUNK , XML_PARSE_HUGE , 0 } ,
2012-07-18 13:43:34 +04:00
} ;
typedef struct testDesc testDesc ;
typedef testDesc * testDescPtr ;
struct testDesc {
2019-09-30 18:04:54 +03:00
const char * desc ; /* description of the test */
2012-07-18 13:43:34 +04:00
functest func ; /* function implementing the test */
} ;
static
testDesc testDescriptions [ ] = {
{ " Parsing of huge files with the sax parser " , saxTest } ,
/* { "Parsing of huge files with the tree parser", treeTest}, */
# ifdef LIBXML_READER_ENABLED
{ " Parsing of huge files with the reader " , readerTest } ,
# endif
{ NULL , NULL }
} ;
typedef struct testException testException ;
typedef testException * testExceptionPtr ;
struct testException {
unsigned int test ; /* the parser test number */
unsigned int limit ; /* the limit test number */
int fail ; /* new fail value or -1*/
size_t size ; /* new limit value or 0 */
} ;
static
testException testExceptions [ ] = {
/* the SAX parser doesn't hit a limit of XML_MAX_TEXT_LENGTH text nodes */
{ 0 , 1 , 0 , 0 } ,
} ;
static int
launchTests ( testDescPtr tst , unsigned int test ) {
int res = 0 , err = 0 ;
unsigned int i , j ;
size_t limit ;
int fail ;
if ( tst = = NULL ) return ( - 1 ) ;
for ( i = 0 ; i < sizeof ( limitDescriptions ) / sizeof ( limitDescriptions [ 0 ] ) ; i + + ) {
limit = limitDescriptions [ i ] . limit ;
fail = limitDescriptions [ i ] . fail ;
/*
* Handle exceptions if any
*/
for ( j = 0 ; j < sizeof ( testExceptions ) / sizeof ( testExceptions [ 0 ] ) ; j + + ) {
if ( ( testExceptions [ j ] . test = = test ) & &
( testExceptions [ j ] . limit = = i ) ) {
if ( testExceptions [ j ] . fail ! = - 1 )
fail = testExceptions [ j ] . fail ;
if ( testExceptions [ j ] . size ! = 0 )
limit = testExceptions [ j ] . size ;
break ;
}
}
res = tst - > func ( limitDescriptions [ i ] . name , limit ,
limitDescriptions [ i ] . options , fail ) ;
if ( res ! = 0 ) {
nb_errors + + ;
err + + ;
}
}
return ( err ) ;
}
static int
runtest ( unsigned int i ) {
int ret = 0 , res ;
int old_errors , old_tests , old_leaks ;
old_errors = nb_errors ;
old_tests = nb_tests ;
old_leaks = nb_leaks ;
if ( ( tests_quiet = = 0 ) & & ( testDescriptions [ i ] . desc ! = NULL ) )
printf ( " ## %s \n " , testDescriptions [ i ] . desc ) ;
res = launchTests ( & testDescriptions [ i ] , i ) ;
if ( res ! = 0 )
ret + + ;
if ( verbose ) {
if ( ( nb_errors = = old_errors ) & & ( nb_leaks = = old_leaks ) )
printf ( " Ran %d tests, no errors \n " , nb_tests - old_tests ) ;
else
printf ( " Ran %d tests, %d errors, %d leaks \n " ,
nb_tests - old_tests ,
nb_errors - old_errors ,
nb_leaks - old_leaks ) ;
}
return ( ret ) ;
}
2012-08-03 08:04:09 +04:00
static int
launchCrazySAX ( unsigned int test , int fail ) {
int res = 0 , err = 0 ;
crazy_indx = test ;
res = saxTest ( " crazy::test " , XML_MAX_LOOKUP_LIMIT - CHUNK , 0 , fail ) ;
if ( res ! = 0 ) {
nb_errors + + ;
err + + ;
}
if ( tests_quiet = = 0 )
fprintf ( stderr , " %c " , crazy [ test ] ) ;
return ( err ) ;
}
2013-08-03 15:22:54 +04:00
# ifdef LIBXML_READER_ENABLED
2012-08-03 08:04:09 +04:00
static int
launchCrazy ( unsigned int test , int fail ) {
int res = 0 , err = 0 ;
crazy_indx = test ;
res = readerTest ( " crazy::test " , XML_MAX_LOOKUP_LIMIT - CHUNK , 0 , fail ) ;
if ( res ! = 0 ) {
nb_errors + + ;
err + + ;
}
if ( tests_quiet = = 0 )
fprintf ( stderr , " %c " , crazy [ test ] ) ;
return ( err ) ;
}
2013-08-03 15:22:54 +04:00
# endif
2012-08-03 08:04:09 +04:00
static int get_crazy_fail ( int test ) {
/*
* adding 1000000 of character ' a ' leads to parser failure mostly
* everywhere except in those special spots . Need to be updated
* each time crazy is updated
*/
int fail = 1 ;
if ( ( test = = 44 ) | | /* PI in Misc */
( ( test > = 50 ) & & ( test < = 55 ) ) | | /* Comment in Misc */
( test = = 79 ) | | /* PI in DTD */
( ( test > = 85 ) & & ( test < = 90 ) ) | | /* Comment in DTD */
( test = = 154 ) | | /* PI in Misc */
( ( test > = 160 ) & & ( test < = 165 ) ) | | /* Comment in Misc */
( ( test > = 178 ) & & ( test < = 181 ) ) | | /* attribute value */
( test = = 183 ) | | /* Text */
( test = = 189 ) | | /* PI in Content */
( test = = 191 ) | | /* Text */
( ( test > = 195 ) & & ( test < = 200 ) ) | | /* Comment in Content */
( ( test > = 203 ) & & ( test < = 206 ) ) | | /* Text */
( test = = 215 ) | | ( test = = 216 ) | | /* in CDATA */
( test = = 219 ) | | /* Text */
( test = = 231 ) | | /* PI in Misc */
( ( test > = 237 ) & & ( test < = 242 ) ) ) /* Comment in Misc */
fail = 0 ;
return ( fail ) ;
}
static int
runcrazy ( void ) {
2012-08-27 13:08:54 +04:00
int ret = 0 , res = 0 ;
2012-08-03 08:04:09 +04:00
int old_errors , old_tests , old_leaks ;
unsigned int i ;
old_errors = nb_errors ;
old_tests = nb_tests ;
old_leaks = nb_leaks ;
2013-08-03 15:22:54 +04:00
# ifdef LIBXML_READER_ENABLED
2012-08-03 08:04:09 +04:00
if ( tests_quiet = = 0 ) {
printf ( " ## Crazy tests on reader \n " ) ;
}
for ( i = 0 ; i < strlen ( crazy ) ; i + + ) {
res + = launchCrazy ( i , get_crazy_fail ( i ) ) ;
if ( res ! = 0 )
ret + + ;
}
2013-08-03 15:22:54 +04:00
# endif
2012-08-03 08:04:09 +04:00
if ( tests_quiet = = 0 ) {
printf ( " \n ## Crazy tests on SAX \n " ) ;
}
for ( i = 0 ; i < strlen ( crazy ) ; i + + ) {
res + = launchCrazySAX ( i , get_crazy_fail ( i ) ) ;
if ( res ! = 0 )
ret + + ;
}
if ( tests_quiet = = 0 )
fprintf ( stderr , " \n " ) ;
if ( verbose ) {
if ( ( nb_errors = = old_errors ) & & ( nb_leaks = = old_leaks ) )
printf ( " Ran %d tests, no errors \n " , nb_tests - old_tests ) ;
else
printf ( " Ran %d tests, %d errors, %d leaks \n " ,
nb_tests - old_tests ,
nb_errors - old_errors ,
nb_leaks - old_leaks ) ;
}
return ( ret ) ;
}
2012-07-18 13:43:34 +04:00
int
main ( int argc ATTRIBUTE_UNUSED , char * * argv ATTRIBUTE_UNUSED ) {
int i , a , ret = 0 ;
int subset = 0 ;
fillFilling ( ) ;
initializeLibxml2 ( ) ;
for ( a = 1 ; a < argc ; a + + ) {
if ( ! strcmp ( argv [ a ] , " -v " ) )
verbose = 1 ;
else if ( ! strcmp ( argv [ a ] , " -quiet " ) )
tests_quiet = 1 ;
2012-08-03 08:04:09 +04:00
else if ( ! strcmp ( argv [ a ] , " -crazy " ) )
subset = 1 ;
2012-07-18 13:43:34 +04:00
}
if ( subset = = 0 ) {
for ( i = 0 ; testDescriptions [ i ] . func ! = NULL ; i + + ) {
ret + = runtest ( i ) ;
}
}
2012-08-03 08:04:09 +04:00
ret + = runcrazy ( ) ;
2012-07-18 13:43:34 +04:00
if ( ( nb_errors = = 0 ) & & ( nb_leaks = = 0 ) ) {
ret = 0 ;
printf ( " Total %d tests, no errors \n " ,
nb_tests ) ;
} else {
ret = 1 ;
printf ( " Total %d tests, %d errors, %d leaks \n " ,
nb_tests , nb_errors , nb_leaks ) ;
}
xmlCleanupParser ( ) ;
xmlMemoryDump ( ) ;
return ( ret ) ;
}