2005-07-07 00:41:33 +04:00
/*
* runtest . c : C program to run libxml2 regression tests without
2019-09-30 18:04:54 +03:00
* requiring make or Python , and reducing platform dependencies
2005-07-07 00:41:33 +04:00
* to a strict minimum .
*
* To compile on Unixes :
* cc - o runtest ` xml2 - config - - cflags ` runtest . c ` xml2 - config - - libs ` - lpthread
*
* See Copyright for the status of this software .
*
* daniel @ veillard . com
*/
2005-10-28 20:37:05 +04:00
# include "libxml.h"
# include <stdio.h>
2005-07-07 00:41:33 +04:00
# if !defined(_WIN32) || defined(__CYGWIN__)
# include <unistd.h>
# endif
# include <string.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <libxml/parser.h>
2017-06-16 22:38:57 +03:00
# include <libxml/parserInternals.h>
2005-07-07 00:41:33 +04:00
# include <libxml/tree.h>
# include <libxml/uri.h>
2017-10-31 19:17:16 +03:00
# include <libxml/encoding.h>
2005-07-07 00:41:33 +04:00
# ifdef LIBXML_OUTPUT_ENABLED
# ifdef LIBXML_READER_ENABLED
# include <libxml/xmlreader.h>
# endif
# ifdef LIBXML_XINCLUDE_ENABLED
# include <libxml/xinclude.h>
# endif
# ifdef LIBXML_XPATH_ENABLED
# include <libxml/xpath.h>
# include <libxml/xpathInternals.h>
# ifdef LIBXML_XPTR_ENABLED
# include <libxml/xpointer.h>
# endif
# endif
# ifdef LIBXML_SCHEMAS_ENABLED
# include <libxml/relaxng.h>
# include <libxml/xmlschemas.h>
# include <libxml/xmlschemastypes.h>
# endif
# ifdef LIBXML_PATTERN_ENABLED
# include <libxml/pattern.h>
# endif
# ifdef LIBXML_C14N_ENABLED
# include <libxml/c14n.h>
# endif
# ifdef LIBXML_HTML_ENABLED
# include <libxml/HTMLparser.h>
# include <libxml/HTMLtree.h>
/*
* pseudo flag for the unification of HTML and XML tests
*/
# define XML_PARSE_HTML 1 << 24
# endif
# if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
# include <libxml/globals.h>
# include <libxml/threads.h>
# include <libxml/parser.h>
# include <libxml/catalog.h>
# include <string.h>
# endif
/*
* O_BINARY is just for Windows compatibility - if it isn ' t defined
* on this system , avoid any compilation error
*/
# ifdef O_BINARY
# define RD_FLAGS O_RDONLY | O_BINARY
2016-05-22 04:58:30 +03:00
# define WR_FLAGS O_WRONLY | O_CREAT | O_TRUNC | O_BINARY
2005-07-07 00:41:33 +04:00
# else
2016-05-22 04:58:30 +03:00
# define RD_FLAGS O_RDONLY
# define WR_FLAGS O_WRONLY | O_CREAT | O_TRUNC
2005-07-07 00:41:33 +04:00
# endif
typedef int ( * functest ) ( const char * filename , const char * result ,
const char * error , int options ) ;
typedef struct testDesc testDesc ;
typedef testDesc * testDescPtr ;
struct testDesc {
2019-09-30 18:04:54 +03:00
const char * desc ; /* description of the test */
2005-07-07 00:41:33 +04:00
functest func ; /* function implementing the test */
const char * in ; /* glob to path for input files */
const char * out ; /* output directory */
const char * suffix ; /* suffix for output files */
const char * err ; /* suffix for error output files */
int options ; /* parser options for the test */
} ;
2016-05-22 04:58:30 +03:00
static int update_results = 0 ;
2020-06-04 12:58:04 +03:00
static char * temp_directory = NULL ;
2005-07-07 00:41:33 +04:00
static int checkTestFile ( const char * filename ) ;
# if defined(_WIN32) && !defined(__CYGWIN__)
# include <windows.h>
# include <io.h>
typedef struct
{
size_t gl_pathc ; /* Count of paths matched so far */
char * * gl_pathv ; /* List of matched pathnames. */
size_t gl_offs ; /* Slots to reserve in 'gl_pathv'. */
} glob_t ;
# define GLOB_DOOFFS 0
2017-10-09 03:05:41 +03:00
static int glob ( const char * pattern , ATTRIBUTE_UNUSED int flags ,
ATTRIBUTE_UNUSED int errfunc ( const char * epath , int eerrno ) ,
2005-07-07 00:41:33 +04:00
glob_t * pglob ) {
glob_t * ret ;
WIN32_FIND_DATA FindFileData ;
HANDLE hFind ;
unsigned int nb_paths = 0 ;
char directory [ 500 ] ;
int len ;
if ( ( pattern = = NULL ) | | ( pglob = = NULL ) ) return ( - 1 ) ;
2008-08-25 18:53:31 +04:00
2005-07-07 00:41:33 +04:00
strncpy ( directory , pattern , 499 ) ;
for ( len = strlen ( directory ) ; len > = 0 ; len - - ) {
if ( directory [ len ] = = ' / ' ) {
len + + ;
directory [ len ] = 0 ;
break ;
}
}
if ( len < = 0 )
len = 0 ;
2008-08-25 18:53:31 +04:00
2005-07-07 00:41:33 +04:00
ret = pglob ;
memset ( ret , 0 , sizeof ( glob_t ) ) ;
2008-08-25 18:53:31 +04:00
2005-07-07 00:41:33 +04:00
hFind = FindFirstFileA ( pattern , & FindFileData ) ;
2008-08-25 18:53:31 +04:00
if ( hFind = = INVALID_HANDLE_VALUE )
2005-07-07 00:41:33 +04:00
return ( 0 ) ;
nb_paths = 20 ;
ret - > gl_pathv = ( char * * ) malloc ( nb_paths * sizeof ( char * ) ) ;
if ( ret - > gl_pathv = = NULL ) {
FindClose ( hFind ) ;
return ( - 1 ) ;
}
strncpy ( directory + len , FindFileData . cFileName , 499 - len ) ;
ret - > gl_pathv [ ret - > gl_pathc ] = strdup ( directory ) ;
if ( ret - > gl_pathv [ ret - > gl_pathc ] = = NULL )
goto done ;
ret - > gl_pathc + + ;
while ( FindNextFileA ( hFind , & FindFileData ) ) {
if ( FindFileData . cFileName [ 0 ] = = ' . ' )
continue ;
if ( ret - > gl_pathc + 2 > nb_paths ) {
char * * tmp = realloc ( ret - > gl_pathv , nb_paths * 2 * sizeof ( char * ) ) ;
if ( tmp = = NULL )
break ;
ret - > gl_pathv = tmp ;
nb_paths * = 2 ;
}
strncpy ( directory + len , FindFileData . cFileName , 499 - len ) ;
ret - > gl_pathv [ ret - > gl_pathc ] = strdup ( directory ) ;
if ( ret - > gl_pathv [ ret - > gl_pathc ] = = NULL )
break ;
ret - > gl_pathc + + ;
}
ret - > gl_pathv [ ret - > gl_pathc ] = NULL ;
done :
FindClose ( hFind ) ;
return ( 0 ) ;
}
2008-08-25 18:53:31 +04:00
2005-07-07 00:41:33 +04:00
static void globfree ( glob_t * pglob ) {
unsigned int i ;
if ( pglob = = NULL )
return ;
2008-08-25 18:53:31 +04:00
2005-07-07 00:41:33 +04:00
for ( i = 0 ; i < pglob - > gl_pathc ; i + + ) {
if ( pglob - > gl_pathv [ i ] ! = NULL )
free ( pglob - > gl_pathv [ i ] ) ;
}
}
2012-05-23 11:52:45 +04:00
2005-07-07 00:41:33 +04:00
# else
# include <glob.h>
# endif
/************************************************************************
* *
* Libxml2 specific routines *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int nb_tests = 0 ;
static int nb_errors = 0 ;
static int nb_leaks = 0 ;
static int extraMemoryFromResolver = 0 ;
static int
fatalError ( void ) {
fprintf ( stderr , " Exitting tests on fatal error \n " ) ;
exit ( 1 ) ;
}
/*
* 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 .
*/
2008-08-25 18:53:31 +04:00
static xmlParserInputPtr
2005-07-07 00:41:33 +04:00
testExternalEntityLoader ( const char * URL , const char * ID ,
xmlParserCtxtPtr ctxt ) {
xmlParserInputPtr ret ;
if ( checkTestFile ( URL ) ) {
ret = xmlNoNetExternalEntityLoader ( URL , ID , ctxt ) ;
} else {
int memused = xmlMemUsed ( ) ;
ret = xmlNoNetExternalEntityLoader ( URL , ID , ctxt ) ;
extraMemoryFromResolver + = xmlMemUsed ( ) - memused ;
}
2008-08-25 18:53:31 +04:00
2005-07-07 00:41:33 +04:00
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 ;
2005-07-21 17:24:09 +04:00
static void XMLCDECL
2005-07-07 00:41:33 +04:00
testErrorHandler ( 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 ;
}
2005-07-21 17:24:09 +04:00
static void XMLCDECL
2005-07-07 00:41:33 +04:00
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
2008-08-25 18:53:31 +04:00
*
2005-07-07 00:41:33 +04:00
* Displays current context within the input content for error tracking
*/
static void
2008-08-25 18:53:31 +04:00
xmlParserPrintFileContextInternal ( xmlParserInputPtr input ,
2005-07-07 00:41:33 +04:00
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) */
2008-08-25 18:53:31 +04:00
while ( ( n + + < ( sizeof ( content ) - 1 ) ) & & ( cur > base ) & &
( * ( cur ) ! = ' \n ' ) & & ( * ( cur ) ! = ' \r ' ) )
2005-07-07 00:41:33 +04:00
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 */
2008-08-25 18:53:31 +04:00
while ( ( * cur ! = 0 ) & & ( * ( cur ) ! = ' \n ' ) & &
( * ( cur ) ! = ' \r ' ) & & ( n < sizeof ( content ) - 1 ) ) {
2005-07-07 00:41:33 +04:00
* 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 ) ;
# ifdef LIBXML_SCHEMAS_ENABLED
xmlSchemaInitTypes ( ) ;
xmlRelaxNGInitTypes ( ) ;
# endif
}
/************************************************************************
* *
* File name and path utilities *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static const char * baseFilename ( const char * filename ) {
const char * cur ;
if ( filename = = NULL )
return ( NULL ) ;
cur = & filename [ strlen ( filename ) ] ;
while ( ( cur > filename ) & & ( * cur ! = ' / ' ) )
cur - - ;
if ( * cur = = ' / ' )
return ( cur + 1 ) ;
return ( cur ) ;
}
static char * resultFilename ( const char * filename , const char * out ,
const char * suffix ) {
const char * base ;
char res [ 500 ] ;
2006-06-18 21:31:31 +04:00
char suffixbuff [ 500 ] ;
2005-07-07 00:41:33 +04:00
/*************
if ( ( filename [ 0 ] = = ' t ' ) & & ( filename [ 1 ] = = ' e ' ) & &
( filename [ 2 ] = = ' s ' ) & & ( filename [ 3 ] = = ' t ' ) & &
( filename [ 4 ] = = ' / ' ) )
filename = & filename [ 5 ] ;
* * * * * * * * * * * * */
2008-08-25 18:53:31 +04:00
2005-07-07 00:41:33 +04:00
base = baseFilename ( filename ) ;
if ( suffix = = NULL )
suffix = " .tmp " ;
if ( out = = NULL )
out = " " ;
2006-06-18 21:31:31 +04:00
strncpy ( suffixbuff , suffix , 499 ) ;
# ifdef VMS
if ( strstr ( base , " . " ) & & suffixbuff [ 0 ] = = ' . ' )
suffixbuff [ 0 ] = ' _ ' ;
# endif
2019-01-01 18:30:38 +03:00
if ( snprintf ( res , 499 , " %s%s%s " , out , base , suffixbuff ) > = 499 )
res [ 499 ] = 0 ;
2005-07-07 00:41:33 +04:00
return ( strdup ( res ) ) ;
}
static int checkTestFile ( const char * filename ) {
struct stat buf ;
if ( stat ( filename , & buf ) = = - 1 )
return ( 0 ) ;
# if defined(_WIN32) && !defined(__CYGWIN__)
if ( ! ( buf . st_mode & _S_IFREG ) )
return ( 0 ) ;
# else
if ( ! S_ISREG ( buf . st_mode ) )
return ( 0 ) ;
# endif
return ( 1 ) ;
}
2016-05-22 04:58:30 +03:00
static int compareFiles ( const char * r1 /* temp */ , const char * r2 /* result */ ) {
2005-07-07 00:41:33 +04:00
int res1 , res2 ;
int fd1 , fd2 ;
char bytes1 [ 4096 ] ;
char bytes2 [ 4096 ] ;
2016-05-22 04:58:30 +03:00
if ( update_results ) {
fd1 = open ( r1 , RD_FLAGS ) ;
if ( fd1 < 0 )
return ( - 1 ) ;
fd2 = open ( r2 , WR_FLAGS , 0644 ) ;
if ( fd2 < 0 ) {
close ( fd1 ) ;
return ( - 1 ) ;
}
do {
res1 = read ( fd1 , bytes1 , 4096 ) ;
if ( res1 < = 0 )
break ;
res2 = write ( fd2 , bytes1 , res1 ) ;
if ( res2 < = 0 | | res2 ! = res1 )
break ;
} while ( 1 ) ;
close ( fd2 ) ;
close ( fd1 ) ;
return ( res1 ! = 0 ) ;
}
2005-07-07 00:41:33 +04:00
fd1 = open ( r1 , RD_FLAGS ) ;
if ( fd1 < 0 )
return ( - 1 ) ;
fd2 = open ( r2 , RD_FLAGS ) ;
if ( fd2 < 0 ) {
close ( fd1 ) ;
return ( - 1 ) ;
}
while ( 1 ) {
res1 = read ( fd1 , bytes1 , 4096 ) ;
res2 = read ( fd2 , bytes2 , 4096 ) ;
2006-03-10 03:36:23 +03:00
if ( ( res1 ! = res2 ) | | ( res1 < 0 ) ) {
2005-07-07 00:41:33 +04:00
close ( fd1 ) ;
close ( fd2 ) ;
return ( 1 ) ;
}
if ( res1 = = 0 )
break ;
if ( memcmp ( bytes1 , bytes2 , res1 ) ! = 0 ) {
close ( fd1 ) ;
close ( fd2 ) ;
return ( 1 ) ;
}
}
close ( fd1 ) ;
close ( fd2 ) ;
return ( 0 ) ;
}
static int compareFileMem ( const char * filename , const char * mem , int size ) {
int res ;
int fd ;
char bytes [ 4096 ] ;
int idx = 0 ;
struct stat info ;
2016-05-22 04:58:30 +03:00
if ( update_results ) {
fd = open ( filename , WR_FLAGS , 0644 ) ;
2016-05-22 06:14:45 +03:00
if ( fd < 0 ) {
fprintf ( stderr , " failed to open %s for writing " , filename ) ;
2016-05-22 04:58:30 +03:00
return ( - 1 ) ;
2016-05-22 06:14:45 +03:00
}
2016-05-22 04:58:30 +03:00
res = write ( fd , mem , size ) ;
close ( fd ) ;
return ( res ! = size ) ;
}
2016-05-22 06:14:45 +03:00
if ( stat ( filename , & info ) < 0 ) {
fprintf ( stderr , " failed to stat %s \n " , filename ) ;
2005-07-07 00:41:33 +04:00
return ( - 1 ) ;
2016-05-22 06:14:45 +03:00
}
if ( info . st_size ! = size ) {
fprintf ( stderr , " file %s is %ld bytes, result is %d bytes \n " ,
2016-08-22 12:44:18 +03:00
filename , ( long ) info . st_size , size ) ;
2005-07-07 00:41:33 +04:00
return ( - 1 ) ;
2016-05-22 06:14:45 +03:00
}
2005-07-07 00:41:33 +04:00
fd = open ( filename , RD_FLAGS ) ;
2016-05-22 06:14:45 +03:00
if ( fd < 0 ) {
fprintf ( stderr , " failed to open %s for reading " , filename ) ;
2005-07-07 00:41:33 +04:00
return ( - 1 ) ;
2016-05-22 06:14:45 +03:00
}
2005-07-07 00:41:33 +04:00
while ( idx < size ) {
res = read ( fd , bytes , 4096 ) ;
if ( res < = 0 )
break ;
2008-08-25 18:53:31 +04:00
if ( res + idx > size )
2005-07-07 00:41:33 +04:00
break ;
if ( memcmp ( bytes , & mem [ idx ] , res ) ! = 0 ) {
int ix ;
for ( ix = 0 ; ix < res ; ix + + )
if ( bytes [ ix ] ! = mem [ idx + ix ] )
break ;
fprintf ( stderr , " Compare error at position %d \n " , idx + ix ) ;
close ( fd ) ;
return ( 1 ) ;
}
idx + = res ;
}
close ( fd ) ;
2016-05-22 06:14:45 +03:00
if ( idx ! = size ) {
fprintf ( stderr , " Compare error index %d, size %d \n " , idx , size ) ;
}
2005-07-07 00:41:33 +04:00
return ( idx ! = size ) ;
}
static int loadMem ( const char * filename , const char * * mem , int * size ) {
int fd , res ;
struct stat info ;
char * base ;
int siz = 0 ;
2008-08-25 18:53:31 +04:00
if ( stat ( filename , & info ) < 0 )
2005-07-07 00:41:33 +04:00
return ( - 1 ) ;
base = malloc ( info . st_size + 1 ) ;
if ( base = = NULL )
return ( - 1 ) ;
if ( ( fd = open ( filename , RD_FLAGS ) ) < 0 ) {
free ( base ) ;
return ( - 1 ) ;
}
while ( ( res = read ( fd , & base [ siz ] , info . st_size - siz ) ) > 0 ) {
siz + = res ;
}
close ( fd ) ;
# if !defined(_WIN32)
if ( siz ! = info . st_size ) {
free ( base ) ;
return ( - 1 ) ;
}
# endif
base [ siz ] = 0 ;
* mem = base ;
* size = siz ;
return ( 0 ) ;
}
static int unloadMem ( const char * mem ) {
free ( ( char * ) mem ) ;
return ( 0 ) ;
}
/************************************************************************
* *
* Tests implementations *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/************************************************************************
* *
* Parse to SAX based tests *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-07-29 03:49:35 +04:00
static FILE * SAXdebug = NULL ;
2005-07-07 00:41:33 +04:00
/*
* empty SAX block
*/
2005-07-29 03:49:35 +04:00
static xmlSAXHandler emptySAXHandlerStruct = {
2005-07-07 00:41:33 +04:00
NULL , /* internalSubset */
NULL , /* isStandalone */
NULL , /* hasInternalSubset */
NULL , /* hasExternalSubset */
NULL , /* resolveEntity */
NULL , /* getEntity */
NULL , /* entityDecl */
NULL , /* notationDecl */
NULL , /* attributeDecl */
NULL , /* elementDecl */
NULL , /* unparsedEntityDecl */
NULL , /* setDocumentLocator */
NULL , /* startDocument */
NULL , /* endDocument */
NULL , /* startElement */
NULL , /* endElement */
NULL , /* reference */
NULL , /* characters */
NULL , /* ignorableWhitespace */
NULL , /* processingInstruction */
NULL , /* comment */
NULL , /* xmlParserWarning */
NULL , /* xmlParserError */
NULL , /* xmlParserError */
NULL , /* getParameterEntity */
NULL , /* cdataBlock; */
NULL , /* externalSubset; */
1 ,
NULL ,
NULL , /* startElementNs */
NULL , /* endElementNs */
NULL /* xmlStructuredErrorFunc */
} ;
static xmlSAXHandlerPtr emptySAXHandler = & emptySAXHandlerStruct ;
2005-07-29 03:49:35 +04:00
static int callbacks = 0 ;
static int quiet = 0 ;
2005-07-07 00:41:33 +04:00
/**
* isStandaloneDebug :
* @ ctxt : An XML parser context
*
* Is this document tagged standalone ?
*
* Returns 1 if true
*/
static int
isStandaloneDebug ( void * ctx ATTRIBUTE_UNUSED )
{
callbacks + + ;
if ( quiet )
return ( 0 ) ;
fprintf ( SAXdebug , " SAX.isStandalone() \n " ) ;
return ( 0 ) ;
}
/**
* hasInternalSubsetDebug :
* @ ctxt : An XML parser context
*
* Does this document has an internal subset
*
* Returns 1 if true
*/
static int
hasInternalSubsetDebug ( void * ctx ATTRIBUTE_UNUSED )
{
callbacks + + ;
if ( quiet )
return ( 0 ) ;
fprintf ( SAXdebug , " SAX.hasInternalSubset() \n " ) ;
return ( 0 ) ;
}
/**
* hasExternalSubsetDebug :
* @ ctxt : An XML parser context
*
* Does this document has an external subset
*
* Returns 1 if true
*/
static int
hasExternalSubsetDebug ( void * ctx ATTRIBUTE_UNUSED )
{
callbacks + + ;
if ( quiet )
return ( 0 ) ;
fprintf ( SAXdebug , " SAX.hasExternalSubset() \n " ) ;
return ( 0 ) ;
}
/**
* internalSubsetDebug :
* @ ctxt : An XML parser context
*
* Does this document has an internal subset
*/
static void
internalSubsetDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * name ,
const xmlChar * ExternalID , const xmlChar * SystemID )
{
callbacks + + ;
if ( quiet )
return ;
2019-08-01 16:01:47 +03:00
if ( name = = NULL )
name = BAD_CAST " (null) " ;
2005-07-07 00:41:33 +04:00
fprintf ( SAXdebug , " SAX.internalSubset(%s, " , name ) ;
if ( ExternalID = = NULL )
fprintf ( SAXdebug , " , " ) ;
else
fprintf ( SAXdebug , " %s, " , ExternalID ) ;
if ( SystemID = = NULL )
fprintf ( SAXdebug , " ) \n " ) ;
else
fprintf ( SAXdebug , " %s) \n " , SystemID ) ;
}
/**
* externalSubsetDebug :
* @ ctxt : An XML parser context
*
* Does this document has an external subset
*/
static void
externalSubsetDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * name ,
const xmlChar * ExternalID , const xmlChar * SystemID )
{
callbacks + + ;
if ( quiet )
return ;
fprintf ( SAXdebug , " SAX.externalSubset(%s, " , name ) ;
if ( ExternalID = = NULL )
fprintf ( SAXdebug , " , " ) ;
else
fprintf ( SAXdebug , " %s, " , ExternalID ) ;
if ( SystemID = = NULL )
fprintf ( SAXdebug , " ) \n " ) ;
else
fprintf ( SAXdebug , " %s) \n " , SystemID ) ;
}
/**
* resolveEntityDebug :
* @ 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
resolveEntityDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * publicId , const xmlChar * systemId )
{
callbacks + + ;
if ( quiet )
return ( NULL ) ;
/* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
2008-08-25 18:53:31 +04:00
2005-07-07 00:41:33 +04:00
fprintf ( SAXdebug , " SAX.resolveEntity( " ) ;
if ( publicId ! = NULL )
fprintf ( SAXdebug , " %s " , ( char * ) publicId ) ;
else
fprintf ( SAXdebug , " " ) ;
if ( systemId ! = NULL )
fprintf ( SAXdebug , " , %s) \n " , ( char * ) systemId ) ;
else
fprintf ( SAXdebug , " , ) \n " ) ;
/*********
if ( systemId ! = NULL ) {
return ( xmlNewInputFromFile ( ctxt , ( char * ) systemId ) ) ;
}
* * * * * * * * */
return ( NULL ) ;
}
/**
* getEntityDebug :
* @ 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
getEntityDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * name )
{
callbacks + + ;
if ( quiet )
return ( NULL ) ;
fprintf ( SAXdebug , " SAX.getEntity(%s) \n " , name ) ;
return ( NULL ) ;
}
/**
* getParameterEntityDebug :
* @ ctxt : An XML parser context
* @ name : The entity name
*
* Get a parameter entity by name
*
* Returns the xmlParserInputPtr
*/
static xmlEntityPtr
getParameterEntityDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * name )
{
callbacks + + ;
if ( quiet )
return ( NULL ) ;
fprintf ( SAXdebug , " SAX.getParameterEntity(%s) \n " , name ) ;
return ( NULL ) ;
}
/**
* entityDeclDebug :
* @ ctxt : An XML parser context
2008-08-25 18:53:31 +04:00
* @ name : the entity name
* @ type : the entity type
2005-07-07 00:41:33 +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
entityDeclDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * name , int type ,
const xmlChar * publicId , const xmlChar * systemId , xmlChar * content )
{
const xmlChar * nullstr = BAD_CAST " (null) " ;
/* not all libraries handle printing null pointers nicely */
if ( publicId = = NULL )
publicId = nullstr ;
if ( systemId = = NULL )
systemId = nullstr ;
if ( content = = NULL )
content = ( xmlChar * ) nullstr ;
callbacks + + ;
if ( quiet )
return ;
fprintf ( SAXdebug , " SAX.entityDecl(%s, %d, %s, %s, %s) \n " ,
name , type , publicId , systemId , content ) ;
}
/**
* attributeDeclDebug :
* @ ctxt : An XML parser context
2008-08-25 18:53:31 +04:00
* @ name : the attribute name
* @ type : the attribute type
2005-07-07 00:41:33 +04:00
*
* An attribute definition has been parsed
*/
static void
attributeDeclDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * elem ,
const xmlChar * name , int type , int def ,
const xmlChar * defaultValue , xmlEnumerationPtr tree )
{
callbacks + + ;
if ( quiet )
return ;
if ( defaultValue = = NULL )
fprintf ( SAXdebug , " SAX.attributeDecl(%s, %s, %d, %d, NULL, ...) \n " ,
elem , name , type , def ) ;
else
fprintf ( SAXdebug , " SAX.attributeDecl(%s, %s, %d, %d, %s, ...) \n " ,
elem , name , type , def , defaultValue ) ;
xmlFreeEnumeration ( tree ) ;
}
/**
* elementDeclDebug :
* @ ctxt : An XML parser context
2008-08-25 18:53:31 +04:00
* @ name : the element name
* @ type : the element type
2005-07-07 00:41:33 +04:00
* @ content : the element value ( without processing ) .
*
* An element definition has been parsed
*/
static void
elementDeclDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * name , int type ,
xmlElementContentPtr content ATTRIBUTE_UNUSED )
{
callbacks + + ;
if ( quiet )
return ;
fprintf ( SAXdebug , " SAX.elementDecl(%s, %d, ...) \n " ,
name , type ) ;
}
/**
* notationDeclDebug :
* @ 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
notationDeclDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * name ,
const xmlChar * publicId , const xmlChar * systemId )
{
callbacks + + ;
if ( quiet )
return ;
fprintf ( SAXdebug , " SAX.notationDecl(%s, %s, %s) \n " ,
( char * ) name , ( char * ) publicId , ( char * ) systemId ) ;
}
/**
* unparsedEntityDeclDebug :
* @ 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
unparsedEntityDeclDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * name ,
const xmlChar * publicId , const xmlChar * systemId ,
const xmlChar * notationName )
{
const xmlChar * nullstr = BAD_CAST " (null) " ;
if ( publicId = = NULL )
publicId = nullstr ;
if ( systemId = = NULL )
systemId = nullstr ;
if ( notationName = = NULL )
notationName = nullstr ;
callbacks + + ;
if ( quiet )
return ;
fprintf ( SAXdebug , " SAX.unparsedEntityDecl(%s, %s, %s, %s) \n " ,
( char * ) name , ( char * ) publicId , ( char * ) systemId ,
( char * ) notationName ) ;
}
/**
* setDocumentLocatorDebug :
* @ 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
setDocumentLocatorDebug ( void * ctx ATTRIBUTE_UNUSED , xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED )
{
callbacks + + ;
if ( quiet )
return ;
fprintf ( SAXdebug , " SAX.setDocumentLocator() \n " ) ;
}
/**
* startDocumentDebug :
* @ ctxt : An XML parser context
*
* called when the document start being processed .
*/
static void
startDocumentDebug ( void * ctx ATTRIBUTE_UNUSED )
{
callbacks + + ;
if ( quiet )
return ;
fprintf ( SAXdebug , " SAX.startDocument() \n " ) ;
}
/**
* endDocumentDebug :
* @ ctxt : An XML parser context
*
* called when the document end has been detected .
*/
static void
endDocumentDebug ( void * ctx ATTRIBUTE_UNUSED )
{
callbacks + + ;
if ( quiet )
return ;
fprintf ( SAXdebug , " SAX.endDocument() \n " ) ;
}
/**
* startElementDebug :
* @ ctxt : An XML parser context
* @ name : The element name
*
* called when an opening tag has been processed .
*/
static void
startElementDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * name , const xmlChar * * atts )
{
int i ;
callbacks + + ;
if ( quiet )
return ;
fprintf ( SAXdebug , " SAX.startElement(%s " , ( char * ) name ) ;
if ( atts ! = NULL ) {
for ( i = 0 ; ( atts [ i ] ! = NULL ) ; i + + ) {
fprintf ( SAXdebug , " , %s=' " , atts [ i + + ] ) ;
if ( atts [ i ] ! = NULL )
fprintf ( SAXdebug , " %s' " , atts [ i ] ) ;
}
}
fprintf ( SAXdebug , " ) \n " ) ;
}
/**
* endElementDebug :
* @ ctxt : An XML parser context
* @ name : The element name
*
* called when the end of an element has been detected .
*/
static void
endElementDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * name )
{
callbacks + + ;
if ( quiet )
return ;
fprintf ( SAXdebug , " SAX.endElement(%s) \n " , ( char * ) name ) ;
}
/**
* charactersDebug :
* @ 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
charactersDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * ch , int len )
{
char output [ 40 ] ;
int i ;
callbacks + + ;
if ( quiet )
return ;
for ( i = 0 ; ( i < len ) & & ( i < 30 ) ; i + + )
output [ i ] = ch [ i ] ;
output [ i ] = 0 ;
fprintf ( SAXdebug , " SAX.characters(%s, %d) \n " , output , len ) ;
}
/**
* referenceDebug :
* @ ctxt : An XML parser context
* @ name : The entity name
*
2008-08-25 18:53:31 +04:00
* called when an entity reference is detected .
2005-07-07 00:41:33 +04:00
*/
static void
referenceDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * name )
{
callbacks + + ;
if ( quiet )
return ;
fprintf ( SAXdebug , " SAX.reference(%s) \n " , name ) ;
}
/**
* ignorableWhitespaceDebug :
* @ 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
ignorableWhitespaceDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * ch , int len )
{
char output [ 40 ] ;
int i ;
callbacks + + ;
if ( quiet )
return ;
for ( i = 0 ; ( i < len ) & & ( i < 30 ) ; i + + )
output [ i ] = ch [ i ] ;
output [ i ] = 0 ;
fprintf ( SAXdebug , " SAX.ignorableWhitespace(%s, %d) \n " , output , len ) ;
}
/**
* processingInstructionDebug :
* @ 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
processingInstructionDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * target ,
const xmlChar * data )
{
callbacks + + ;
if ( quiet )
return ;
if ( data ! = NULL )
fprintf ( SAXdebug , " SAX.processingInstruction(%s, %s) \n " ,
( char * ) target , ( char * ) data ) ;
else
fprintf ( SAXdebug , " SAX.processingInstruction(%s, NULL) \n " ,
( char * ) target ) ;
}
/**
* cdataBlockDebug :
* @ 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
cdataBlockDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * value , int len )
{
callbacks + + ;
if ( quiet )
return ;
fprintf ( SAXdebug , " SAX.pcdata(%.20s, %d) \n " ,
( char * ) value , len ) ;
}
/**
* commentDebug :
* @ ctxt : An XML parser context
* @ value : the comment content
*
* A comment has been parsed .
*/
static void
commentDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * value )
{
callbacks + + ;
if ( quiet )
return ;
fprintf ( SAXdebug , " SAX.comment(%s) \n " , value ) ;
}
/**
* warningDebug :
* @ 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 .
*/
2005-07-21 17:24:09 +04:00
static void XMLCDECL
2005-07-07 00:41:33 +04:00
warningDebug ( void * ctx ATTRIBUTE_UNUSED , const char * msg , . . . )
{
va_list args ;
callbacks + + ;
if ( quiet )
return ;
va_start ( args , msg ) ;
fprintf ( SAXdebug , " SAX.warning: " ) ;
vfprintf ( SAXdebug , msg , args ) ;
va_end ( args ) ;
}
/**
* errorDebug :
* @ 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 .
*/
2005-07-21 17:24:09 +04:00
static void XMLCDECL
2005-07-07 00:41:33 +04:00
errorDebug ( void * ctx ATTRIBUTE_UNUSED , const char * msg , . . . )
{
va_list args ;
callbacks + + ;
if ( quiet )
return ;
va_start ( args , msg ) ;
fprintf ( SAXdebug , " SAX.error: " ) ;
vfprintf ( SAXdebug , msg , args ) ;
va_end ( args ) ;
}
/**
* fatalErrorDebug :
* @ 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 .
*/
2005-07-21 17:24:09 +04:00
static void XMLCDECL
2005-07-07 00:41:33 +04:00
fatalErrorDebug ( void * ctx ATTRIBUTE_UNUSED , const char * msg , . . . )
{
va_list args ;
callbacks + + ;
if ( quiet )
return ;
va_start ( args , msg ) ;
fprintf ( SAXdebug , " SAX.fatalError: " ) ;
vfprintf ( SAXdebug , msg , args ) ;
va_end ( args ) ;
}
2005-07-29 03:49:35 +04:00
static xmlSAXHandler debugSAXHandlerStruct = {
2005-07-07 00:41:33 +04:00
internalSubsetDebug ,
isStandaloneDebug ,
hasInternalSubsetDebug ,
hasExternalSubsetDebug ,
resolveEntityDebug ,
getEntityDebug ,
entityDeclDebug ,
notationDeclDebug ,
attributeDeclDebug ,
elementDeclDebug ,
unparsedEntityDeclDebug ,
setDocumentLocatorDebug ,
startDocumentDebug ,
endDocumentDebug ,
startElementDebug ,
endElementDebug ,
referenceDebug ,
charactersDebug ,
ignorableWhitespaceDebug ,
processingInstructionDebug ,
commentDebug ,
warningDebug ,
errorDebug ,
fatalErrorDebug ,
getParameterEntityDebug ,
cdataBlockDebug ,
externalSubsetDebug ,
1 ,
NULL ,
NULL ,
NULL ,
NULL
} ;
2005-07-29 03:49:35 +04:00
static xmlSAXHandlerPtr debugSAXHandler = & debugSAXHandlerStruct ;
2005-07-07 00:41:33 +04:00
/*
* SAX2 specific callbacks
*/
/**
* startElementNsDebug :
* @ ctxt : An XML parser context
* @ name : The element name
*
* called when an opening tag has been processed .
*/
static void
startElementNsDebug ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * localname ,
const xmlChar * prefix ,
const xmlChar * URI ,
int nb_namespaces ,
const xmlChar * * namespaces ,
int nb_attributes ,
int nb_defaulted ,
const xmlChar * * attributes )
{
int i ;
callbacks + + ;
if ( quiet )
return ;
fprintf ( SAXdebug , " SAX.startElementNs(%s " , ( char * ) localname ) ;
if ( prefix = = NULL )
fprintf ( SAXdebug , " , NULL " ) ;
else
fprintf ( SAXdebug , " , %s " , ( char * ) prefix ) ;
if ( URI = = NULL )
fprintf ( SAXdebug , " , NULL " ) ;
else
fprintf ( SAXdebug , " , '%s' " , ( char * ) URI ) ;
fprintf ( SAXdebug , " , %d " , nb_namespaces ) ;
2008-08-25 18:53:31 +04:00
2005-07-07 00:41:33 +04:00
if ( namespaces ! = NULL ) {
for ( i = 0 ; i < nb_namespaces * 2 ; i + + ) {
fprintf ( SAXdebug , " , xmlns " ) ;
if ( namespaces [ i ] ! = NULL )
fprintf ( SAXdebug , " :%s " , namespaces [ i ] ) ;
i + + ;
fprintf ( SAXdebug , " ='%s' " , namespaces [ i ] ) ;
}
}
fprintf ( SAXdebug , " , %d, %d " , nb_attributes , nb_defaulted ) ;
if ( attributes ! = NULL ) {
for ( i = 0 ; i < nb_attributes * 5 ; i + = 5 ) {
if ( attributes [ i + 1 ] ! = NULL )
fprintf ( SAXdebug , " , %s:%s=' " , attributes [ i + 1 ] , attributes [ i ] ) ;
else
fprintf ( SAXdebug , " , %s=' " , attributes [ i ] ) ;
fprintf ( SAXdebug , " %.4s...', %d " , attributes [ i + 3 ] ,
( int ) ( attributes [ i + 4 ] - attributes [ i + 3 ] ) ) ;
}
}
fprintf ( SAXdebug , " ) \n " ) ;
}
/**
* endElementDebug :
* @ ctxt : An XML parser context
* @ name : The element name
*
* called when the end of an element has been detected .
*/
static void
endElementNsDebug ( void * ctx ATTRIBUTE_UNUSED ,
const xmlChar * localname ,
const xmlChar * prefix ,
const xmlChar * URI )
{
callbacks + + ;
if ( quiet )
return ;
fprintf ( SAXdebug , " SAX.endElementNs(%s " , ( char * ) localname ) ;
if ( prefix = = NULL )
fprintf ( SAXdebug , " , NULL " ) ;
else
fprintf ( SAXdebug , " , %s " , ( char * ) prefix ) ;
if ( URI = = NULL )
fprintf ( SAXdebug , " , NULL) \n " ) ;
else
fprintf ( SAXdebug , " , '%s') \n " , ( char * ) URI ) ;
}
2005-07-29 03:49:35 +04:00
static xmlSAXHandler debugSAX2HandlerStruct = {
2005-07-07 00:41:33 +04:00
internalSubsetDebug ,
isStandaloneDebug ,
hasInternalSubsetDebug ,
hasExternalSubsetDebug ,
resolveEntityDebug ,
getEntityDebug ,
entityDeclDebug ,
notationDeclDebug ,
attributeDeclDebug ,
elementDeclDebug ,
unparsedEntityDeclDebug ,
setDocumentLocatorDebug ,
startDocumentDebug ,
endDocumentDebug ,
NULL ,
NULL ,
referenceDebug ,
charactersDebug ,
ignorableWhitespaceDebug ,
processingInstructionDebug ,
commentDebug ,
warningDebug ,
errorDebug ,
fatalErrorDebug ,
getParameterEntityDebug ,
cdataBlockDebug ,
externalSubsetDebug ,
XML_SAX2_MAGIC ,
NULL ,
startElementNsDebug ,
endElementNsDebug ,
NULL
} ;
2005-07-29 03:49:35 +04:00
static xmlSAXHandlerPtr debugSAX2Handler = & debugSAX2HandlerStruct ;
2005-07-07 00:41:33 +04:00
# ifdef LIBXML_HTML_ENABLED
/**
* htmlstartElementDebug :
* @ ctxt : An XML parser context
* @ name : The element name
*
* called when an opening tag has been processed .
*/
static void
htmlstartElementDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * name , const xmlChar * * atts )
{
int i ;
fprintf ( SAXdebug , " SAX.startElement(%s " , ( char * ) name ) ;
if ( atts ! = NULL ) {
for ( i = 0 ; ( atts [ i ] ! = NULL ) ; i + + ) {
fprintf ( SAXdebug , " , %s " , atts [ i + + ] ) ;
if ( atts [ i ] ! = NULL ) {
unsigned char output [ 40 ] ;
const unsigned char * att = atts [ i ] ;
int outlen , attlen ;
fprintf ( SAXdebug , " =' " ) ;
while ( ( attlen = strlen ( ( char * ) att ) ) > 0 ) {
outlen = sizeof output - 1 ;
htmlEncodeEntities ( output , & outlen , att , & attlen , ' \' ' ) ;
output [ outlen ] = 0 ;
fprintf ( SAXdebug , " %s " , ( char * ) output ) ;
att + = attlen ;
}
fprintf ( SAXdebug , " ' " ) ;
}
}
}
fprintf ( SAXdebug , " ) \n " ) ;
}
/**
* htmlcharactersDebug :
* @ 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
htmlcharactersDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * ch , int len )
{
unsigned char output [ 40 ] ;
int inlen = len , outlen = 30 ;
htmlEncodeEntities ( output , & outlen , ch , & inlen , 0 ) ;
output [ outlen ] = 0 ;
fprintf ( SAXdebug , " SAX.characters(%s, %d) \n " , output , len ) ;
}
/**
* htmlcdataDebug :
* @ ctxt : An XML parser context
* @ ch : a xmlChar string
* @ len : the number of xmlChar
*
* receiving some cdata chars from the parser .
* Question : how much at a time ? ? ?
*/
static void
htmlcdataDebug ( void * ctx ATTRIBUTE_UNUSED , const xmlChar * ch , int len )
{
unsigned char output [ 40 ] ;
int inlen = len , outlen = 30 ;
htmlEncodeEntities ( output , & outlen , ch , & inlen , 0 ) ;
output [ outlen ] = 0 ;
fprintf ( SAXdebug , " SAX.cdata(%s, %d) \n " , output , len ) ;
}
2005-07-29 03:49:35 +04:00
static xmlSAXHandler debugHTMLSAXHandlerStruct = {
2005-07-07 00:41:33 +04:00
internalSubsetDebug ,
isStandaloneDebug ,
hasInternalSubsetDebug ,
hasExternalSubsetDebug ,
resolveEntityDebug ,
getEntityDebug ,
entityDeclDebug ,
notationDeclDebug ,
attributeDeclDebug ,
elementDeclDebug ,
unparsedEntityDeclDebug ,
setDocumentLocatorDebug ,
startDocumentDebug ,
endDocumentDebug ,
htmlstartElementDebug ,
endElementDebug ,
referenceDebug ,
htmlcharactersDebug ,
ignorableWhitespaceDebug ,
processingInstructionDebug ,
commentDebug ,
warningDebug ,
errorDebug ,
fatalErrorDebug ,
getParameterEntityDebug ,
htmlcdataDebug ,
externalSubsetDebug ,
1 ,
NULL ,
NULL ,
NULL ,
NULL
} ;
2005-07-29 03:49:35 +04:00
static xmlSAXHandlerPtr debugHTMLSAXHandler = & debugHTMLSAXHandlerStruct ;
2005-07-07 00:41:33 +04:00
# endif /* LIBXML_HTML_ENABLED */
/**
* saxParseTest :
* @ filename : the file to parse
* @ result : the file with expected result
* @ err : the file with error messages
*
* Parse a file using the SAX API and check for errors .
*
* Returns 0 in case of success , an error code otherwise
*/
static int
saxParseTest ( const char * filename , const char * result ,
const char * err ATTRIBUTE_UNUSED ,
int options ) {
int ret ;
char * temp ;
nb_tests + + ;
2020-06-04 12:58:04 +03:00
temp = resultFilename ( filename , temp_directory , " .res " ) ;
2005-07-07 00:41:33 +04:00
if ( temp = = NULL ) {
fprintf ( stderr , " out of memory \n " ) ;
fatalError ( ) ;
}
SAXdebug = fopen ( temp , " wb " ) ;
if ( SAXdebug = = NULL ) {
fprintf ( stderr , " Failed to write to %s \n " , temp ) ;
free ( temp ) ;
return ( - 1 ) ;
}
/* for SAX we really want the callbacks though the context handlers */
xmlSetStructuredErrorFunc ( NULL , NULL ) ;
xmlSetGenericErrorFunc ( NULL , testErrorHandler ) ;
# ifdef LIBXML_HTML_ENABLED
if ( options & XML_PARSE_HTML ) {
htmlSAXParseFile ( filename , NULL , emptySAXHandler , NULL ) ;
ret = 0 ;
} else
# endif
2017-06-16 22:38:57 +03:00
{
xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt ( filename ) ;
memcpy ( ctxt - > sax , emptySAXHandler , sizeof ( xmlSAXHandler ) ) ;
xmlCtxtUseOptions ( ctxt , options ) ;
xmlParseDocument ( ctxt ) ;
ret = ctxt - > wellFormed ? 0 : ctxt - > errNo ;
xmlFreeDoc ( ctxt - > myDoc ) ;
xmlFreeParserCtxt ( ctxt ) ;
}
2005-07-07 00:41:33 +04:00
if ( ret = = XML_WAR_UNDECLARED_ENTITY ) {
fprintf ( SAXdebug , " xmlSAXUserParseFile returned error %d \n " , ret ) ;
ret = 0 ;
}
if ( ret ! = 0 ) {
fprintf ( stderr , " Failed to parse %s \n " , filename ) ;
2014-06-21 00:15:16 +04:00
ret = 1 ;
goto done ;
2005-07-07 00:41:33 +04:00
}
# ifdef LIBXML_HTML_ENABLED
if ( options & XML_PARSE_HTML ) {
htmlSAXParseFile ( filename , NULL , debugHTMLSAXHandler , NULL ) ;
ret = 0 ;
} else
# endif
2017-06-16 22:38:57 +03:00
{
xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt ( filename ) ;
if ( options & XML_PARSE_SAX1 ) {
memcpy ( ctxt - > sax , debugSAXHandler , sizeof ( xmlSAXHandler ) ) ;
options - = XML_PARSE_SAX1 ;
} else {
memcpy ( ctxt - > sax , debugSAX2Handler , sizeof ( xmlSAXHandler ) ) ;
}
xmlCtxtUseOptions ( ctxt , options ) ;
xmlParseDocument ( ctxt ) ;
ret = ctxt - > wellFormed ? 0 : ctxt - > errNo ;
xmlFreeDoc ( ctxt - > myDoc ) ;
xmlFreeParserCtxt ( ctxt ) ;
2005-07-07 00:41:33 +04:00
}
if ( ret = = XML_WAR_UNDECLARED_ENTITY ) {
fprintf ( SAXdebug , " xmlSAXUserParseFile returned error %d \n " , ret ) ;
ret = 0 ;
}
fclose ( SAXdebug ) ;
if ( compareFiles ( temp , result ) ) {
fprintf ( stderr , " Got a difference for %s \n " , filename ) ;
ret = 1 ;
2009-09-05 16:52:55 +04:00
}
2014-06-21 00:15:16 +04:00
done :
2009-09-05 16:52:55 +04:00
if ( temp ! = NULL ) {
unlink ( temp ) ;
free ( temp ) ;
}
2008-08-25 18:53:31 +04:00
2005-07-07 00:41:33 +04:00
/* switch back to structured error handling */
xmlSetGenericErrorFunc ( NULL , NULL ) ;
xmlSetStructuredErrorFunc ( NULL , testStructuredErrorHandler ) ;
return ( ret ) ;
}
/************************************************************************
* *
* Parse to tree based tests *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* oldParseTest :
* @ filename : the file to parse
* @ result : the file with expected result
* @ err : the file with error messages : unused
*
* Parse a file using the old xmlParseFile API , then serialize back
* reparse the result and serialize again , then check for deviation
* in serialization .
*
* Returns 0 in case of success , an error code otherwise
*/
static int
oldParseTest ( const char * filename , const char * result ,
const char * err ATTRIBUTE_UNUSED ,
int options ATTRIBUTE_UNUSED ) {
xmlDocPtr doc ;
char * temp ;
int res = 0 ;
nb_tests + + ;
/*
* base of the test , parse with the old API
*/
# ifdef LIBXML_SAX1_ENABLED
doc = xmlParseFile ( filename ) ;
# else
doc = xmlReadFile ( filename , NULL , 0 ) ;
# endif
if ( doc = = NULL )
return ( 1 ) ;
2020-06-04 12:58:04 +03:00
temp = resultFilename ( filename , temp_directory , " .res " ) ;
2005-07-07 00:41:33 +04:00
if ( temp = = NULL ) {
fprintf ( stderr , " out of memory \n " ) ;
fatalError ( ) ;
}
xmlSaveFile ( temp , doc ) ;
if ( compareFiles ( temp , result ) ) {
res = 1 ;
}
xmlFreeDoc ( doc ) ;
/*
* Parse the saved result to make sure the round trip is okay
*/
# ifdef LIBXML_SAX1_ENABLED
doc = xmlParseFile ( temp ) ;
# else
doc = xmlReadFile ( temp , NULL , 0 ) ;
# endif
if ( doc = = NULL )
return ( 1 ) ;
xmlSaveFile ( temp , doc ) ;
if ( compareFiles ( temp , result ) ) {
res = 1 ;
}
xmlFreeDoc ( doc ) ;
2009-09-05 16:52:55 +04:00
if ( temp ! = NULL ) {
unlink ( temp ) ;
free ( temp ) ;
}
2005-07-07 00:41:33 +04:00
return ( res ) ;
}
# ifdef LIBXML_PUSH_ENABLED
/**
* pushParseTest :
* @ filename : the file to parse
* @ result : the file with expected result
* @ err : the file with error messages : unused
*
* Parse a file using the Push API , then serialize back
* to check for content .
*
* Returns 0 in case of success , an error code otherwise
*/
static int
pushParseTest ( const char * filename , const char * result ,
const char * err ATTRIBUTE_UNUSED ,
int options ) {
xmlParserCtxtPtr ctxt ;
xmlDocPtr doc ;
const char * base ;
int size , res ;
int cur = 0 ;
2017-06-12 19:26:11 +03:00
int chunkSize = 4 ;
2005-07-07 00:41:33 +04:00
nb_tests + + ;
/*
* load the document in memory and work from there .
*/
if ( loadMem ( filename , & base , & size ) ! = 0 ) {
fprintf ( stderr , " Failed to load %s \n " , filename ) ;
return ( - 1 ) ;
}
2008-08-25 18:53:31 +04:00
2017-06-12 19:26:11 +03:00
if ( chunkSize > size )
chunkSize = size ;
2005-07-07 00:41:33 +04:00
# ifdef LIBXML_HTML_ENABLED
if ( options & XML_PARSE_HTML )
2017-06-12 19:26:11 +03:00
ctxt = htmlCreatePushParserCtxt ( NULL , NULL , base + cur , chunkSize , filename ,
2005-07-07 00:41:33 +04:00
XML_CHAR_ENCODING_NONE ) ;
else
# endif
2017-06-12 19:26:11 +03:00
ctxt = xmlCreatePushParserCtxt ( NULL , NULL , base + cur , chunkSize , filename ) ;
2005-07-07 00:41:33 +04:00
xmlCtxtUseOptions ( ctxt , options ) ;
2017-06-12 19:26:11 +03:00
cur + = chunkSize ;
chunkSize = 1024 ;
2016-03-01 22:34:04 +03:00
do {
2017-06-12 19:26:11 +03:00
if ( cur + chunkSize > = size ) {
2005-07-07 00:41:33 +04:00
# ifdef LIBXML_HTML_ENABLED
if ( options & XML_PARSE_HTML )
htmlParseChunk ( ctxt , base + cur , size - cur , 1 ) ;
else
# endif
xmlParseChunk ( ctxt , base + cur , size - cur , 1 ) ;
break ;
} else {
# ifdef LIBXML_HTML_ENABLED
if ( options & XML_PARSE_HTML )
2017-06-12 19:26:11 +03:00
htmlParseChunk ( ctxt , base + cur , chunkSize , 0 ) ;
2005-07-07 00:41:33 +04:00
else
# endif
2017-06-12 19:26:11 +03:00
xmlParseChunk ( ctxt , base + cur , chunkSize , 0 ) ;
cur + = chunkSize ;
2005-07-07 00:41:33 +04:00
}
2016-03-01 22:34:04 +03:00
} while ( cur < size ) ;
2005-07-07 00:41:33 +04:00
doc = ctxt - > myDoc ;
# ifdef LIBXML_HTML_ENABLED
if ( options & XML_PARSE_HTML )
res = 1 ;
else
# endif
res = ctxt - > wellFormed ;
xmlFreeParserCtxt ( ctxt ) ;
free ( ( char * ) base ) ;
if ( ! res ) {
xmlFreeDoc ( doc ) ;
fprintf ( stderr , " Failed to parse %s \n " , filename ) ;
return ( - 1 ) ;
}
# ifdef LIBXML_HTML_ENABLED
if ( options & XML_PARSE_HTML )
htmlDocDumpMemory ( doc , ( xmlChar * * ) & base , & size ) ;
else
# endif
xmlDocDumpMemory ( doc , ( xmlChar * * ) & base , & size ) ;
xmlFreeDoc ( doc ) ;
res = compareFileMem ( result , base , size ) ;
if ( ( base = = NULL ) | | ( res ! = 0 ) ) {
if ( base ! = NULL )
xmlFree ( ( char * ) base ) ;
2016-05-22 06:14:45 +03:00
fprintf ( stderr , " Result for %s failed in %s \n " , filename , result ) ;
2005-07-07 00:41:33 +04:00
return ( - 1 ) ;
}
xmlFree ( ( char * ) base ) ;
if ( err ! = NULL ) {
res = compareFileMem ( err , testErrors , testErrorsSize ) ;
if ( res ! = 0 ) {
fprintf ( stderr , " Error for %s failed \n " , filename ) ;
return ( - 1 ) ;
}
}
return ( 0 ) ;
}
# endif
/**
* memParseTest :
* @ filename : the file to parse
* @ result : the file with expected result
* @ err : the file with error messages : unused
*
* Parse a file using the old xmlReadMemory API , then serialize back
* reparse the result and serialize again , then check for deviation
* in serialization .
*
* Returns 0 in case of success , an error code otherwise
*/
static int
memParseTest ( const char * filename , const char * result ,
const char * err ATTRIBUTE_UNUSED ,
int options ATTRIBUTE_UNUSED ) {
xmlDocPtr doc ;
const char * base ;
int size , res ;
nb_tests + + ;
/*
* load and parse the memory
*/
if ( loadMem ( filename , & base , & size ) ! = 0 ) {
fprintf ( stderr , " Failed to load %s \n " , filename ) ;
return ( - 1 ) ;
}
2008-08-25 18:53:31 +04:00
2005-07-07 00:41:33 +04:00
doc = xmlReadMemory ( base , size , filename , NULL , 0 ) ;
unloadMem ( base ) ;
if ( doc = = NULL ) {
return ( 1 ) ;
}
xmlDocDumpMemory ( doc , ( xmlChar * * ) & base , & size ) ;
xmlFreeDoc ( doc ) ;
res = compareFileMem ( result , base , size ) ;
if ( ( base = = NULL ) | | ( res ! = 0 ) ) {
if ( base ! = NULL )
xmlFree ( ( char * ) base ) ;
2016-05-22 06:14:45 +03:00
fprintf ( stderr , " Result for %s failed in %s \n " , filename , result ) ;
2005-07-07 00:41:33 +04:00
return ( - 1 ) ;
}
xmlFree ( ( char * ) base ) ;
return ( 0 ) ;
}
/**
* noentParseTest :
* @ filename : the file to parse
* @ result : the file with expected result
* @ err : the file with error messages : unused
*
* Parse a file with entity resolution , then serialize back
* reparse the result and serialize again , then check for deviation
* in serialization .
*
* Returns 0 in case of success , an error code otherwise
*/
static int
noentParseTest ( const char * filename , const char * result ,
const char * err ATTRIBUTE_UNUSED ,
int options ) {
xmlDocPtr doc ;
char * temp ;
int res = 0 ;
nb_tests + + ;
/*
* base of the test , parse with the old API
*/
doc = xmlReadFile ( filename , NULL , options ) ;
if ( doc = = NULL )
return ( 1 ) ;
2020-06-04 12:58:04 +03:00
temp = resultFilename ( filename , temp_directory , " .res " ) ;
2005-07-07 00:41:33 +04:00
if ( temp = = NULL ) {
fprintf ( stderr , " Out of memory \n " ) ;
fatalError ( ) ;
}
xmlSaveFile ( temp , doc ) ;
if ( compareFiles ( temp , result ) ) {
res = 1 ;
}
xmlFreeDoc ( doc ) ;
/*
* Parse the saved result to make sure the round trip is okay
*/
doc = xmlReadFile ( filename , NULL , options ) ;
if ( doc = = NULL )
return ( 1 ) ;
xmlSaveFile ( temp , doc ) ;
if ( compareFiles ( temp , result ) ) {
res = 1 ;
}
xmlFreeDoc ( doc ) ;
2009-09-05 16:52:55 +04:00
if ( temp ! = NULL ) {
unlink ( temp ) ;
free ( temp ) ;
}
2005-07-07 00:41:33 +04:00
return ( res ) ;
}
/**
* errParseTest :
* @ filename : the file to parse
* @ result : the file with expected result
* @ err : the file with error messages
*
* Parse a file using the xmlReadFile API and check for errors .
*
* Returns 0 in case of success , an error code otherwise
*/
static int
errParseTest ( const char * filename , const char * result , const char * err ,
int options ) {
xmlDocPtr doc ;
const char * base = NULL ;
int size , res = 0 ;
nb_tests + + ;
# ifdef LIBXML_HTML_ENABLED
if ( options & XML_PARSE_HTML ) {
doc = htmlReadFile ( filename , NULL , options ) ;
} else
# endif
# ifdef LIBXML_XINCLUDE_ENABLED
if ( options & XML_PARSE_XINCLUDE ) {
doc = xmlReadFile ( filename , NULL , options ) ;
xmlXIncludeProcessFlags ( doc , options ) ;
} else
# endif
{
xmlGetWarningsDefaultValue = 1 ;
doc = xmlReadFile ( filename , NULL , options ) ;
}
xmlGetWarningsDefaultValue = 0 ;
if ( result ) {
if ( doc = = NULL ) {
base = " " ;
size = 0 ;
} else {
# ifdef LIBXML_HTML_ENABLED
if ( options & XML_PARSE_HTML ) {
htmlDocDumpMemory ( doc , ( xmlChar * * ) & base , & size ) ;
} else
# endif
xmlDocDumpMemory ( doc , ( xmlChar * * ) & base , & size ) ;
}
res = compareFileMem ( result , base , size ) ;
}
if ( doc ! = NULL ) {
if ( base ! = NULL )
xmlFree ( ( char * ) base ) ;
xmlFreeDoc ( doc ) ;
}
2020-08-16 23:22:57 +03:00
if ( res ! = 0 ) {
fprintf ( stderr , " Result for %s failed in %s \n " , filename , result ) ;
return ( - 1 ) ;
}
2005-07-07 00:41:33 +04:00
if ( err ! = NULL ) {
res = compareFileMem ( err , testErrors , testErrorsSize ) ;
if ( res ! = 0 ) {
fprintf ( stderr , " Error for %s failed \n " , filename ) ;
return ( - 1 ) ;
}
} else if ( options & XML_PARSE_DTDVALID ) {
if ( testErrorsSize ! = 0 )
fprintf ( stderr , " Validation for %s failed \n " , filename ) ;
}
return ( 0 ) ;
}
# ifdef LIBXML_READER_ENABLED
/************************************************************************
* *
* Reader based tests *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void processNode ( FILE * out , xmlTextReaderPtr reader ) {
const xmlChar * name , * value ;
int type , empty ;
type = xmlTextReaderNodeType ( reader ) ;
empty = xmlTextReaderIsEmptyElement ( reader ) ;
name = xmlTextReaderConstName ( reader ) ;
if ( name = = NULL )
name = BAD_CAST " -- " ;
value = xmlTextReaderConstValue ( reader ) ;
2008-08-25 18:53:31 +04:00
fprintf ( out , " %d %d %s %d %d " ,
2005-07-07 00:41:33 +04:00
xmlTextReaderDepth ( reader ) ,
type ,
name ,
empty ,
xmlTextReaderHasValue ( reader ) ) ;
if ( value = = NULL )
fprintf ( out , " \n " ) ;
else {
fprintf ( out , " %s \n " , value ) ;
}
}
static int
streamProcessTest ( const char * filename , const char * result , const char * err ,
2017-06-17 15:12:53 +03:00
xmlTextReaderPtr reader , const char * rng ,
int options ATTRIBUTE_UNUSED ) {
2005-07-07 00:41:33 +04:00
int ret ;
char * temp = NULL ;
FILE * t = NULL ;
if ( reader = = NULL )
return ( - 1 ) ;
nb_tests + + ;
if ( result ! = NULL ) {
2020-06-04 12:58:04 +03:00
temp = resultFilename ( filename , temp_directory , " .res " ) ;
2005-07-07 00:41:33 +04:00
if ( temp = = NULL ) {
fprintf ( stderr , " Out of memory \n " ) ;
fatalError ( ) ;
}
t = fopen ( temp , " wb " ) ;
if ( t = = NULL ) {
fprintf ( stderr , " Can't open temp file %s \n " , temp ) ;
free ( temp ) ;
return ( - 1 ) ;
}
}
# ifdef LIBXML_SCHEMAS_ENABLED
if ( rng ! = NULL ) {
ret = xmlTextReaderRelaxNGValidate ( reader , rng ) ;
if ( ret < 0 ) {
testErrorHandler ( NULL , " Relax-NG schema %s failed to compile \n " ,
rng ) ;
fclose ( t ) ;
2009-09-05 16:52:55 +04:00
if ( temp ! = NULL ) {
unlink ( temp ) ;
free ( temp ) ;
}
2005-07-07 00:41:33 +04:00
return ( 0 ) ;
}
}
# endif
xmlGetWarningsDefaultValue = 1 ;
ret = xmlTextReaderRead ( reader ) ;
while ( ret = = 1 ) {
if ( ( t ! = NULL ) & & ( rng = = NULL ) )
processNode ( t , reader ) ;
ret = xmlTextReaderRead ( reader ) ;
}
if ( ret ! = 0 ) {
testErrorHandler ( NULL , " %s : failed to parse \n " , filename ) ;
}
if ( rng ! = NULL ) {
if ( xmlTextReaderIsValid ( reader ) ! = 1 ) {
testErrorHandler ( NULL , " %s fails to validate \n " , filename ) ;
} else {
testErrorHandler ( NULL , " %s validates \n " , filename ) ;
}
}
xmlGetWarningsDefaultValue = 0 ;
if ( t ! = NULL ) {
fclose ( t ) ;
ret = compareFiles ( temp , result ) ;
2009-09-05 16:52:55 +04:00
if ( temp ! = NULL ) {
unlink ( temp ) ;
free ( temp ) ;
}
2005-07-07 00:41:33 +04:00
if ( ret ) {
2016-05-22 06:14:45 +03:00
fprintf ( stderr , " Result for %s failed in %s \n " , filename , result ) ;
2005-07-07 00:41:33 +04:00
return ( - 1 ) ;
}
}
if ( err ! = NULL ) {
ret = compareFileMem ( err , testErrors , testErrorsSize ) ;
if ( ret ! = 0 ) {
fprintf ( stderr , " Error for %s failed \n " , filename ) ;
printf ( " %s " , testErrors ) ;
return ( - 1 ) ;
}
}
return ( 0 ) ;
}
/**
* streamParseTest :
* @ filename : the file to parse
* @ result : the file with expected result
* @ err : the file with error messages
*
* Parse a file using the reader API and check for errors .
*
* Returns 0 in case of success , an error code otherwise
*/
static int
streamParseTest ( const char * filename , const char * result , const char * err ,
int options ) {
xmlTextReaderPtr reader ;
int ret ;
reader = xmlReaderForFile ( filename , NULL , options ) ;
2012-10-25 11:39:39 +04:00
ret = streamProcessTest ( filename , result , err , reader , NULL , options ) ;
2005-07-07 00:41:33 +04:00
xmlFreeTextReader ( reader ) ;
return ( ret ) ;
}
/**
* walkerParseTest :
* @ filename : the file to parse
* @ result : the file with expected result
* @ err : the file with error messages
*
* Parse a file using the walker , i . e . a reader built from a atree .
*
* Returns 0 in case of success , an error code otherwise
*/
static int
walkerParseTest ( const char * filename , const char * result , const char * err ,
int options ) {
xmlDocPtr doc ;
xmlTextReaderPtr reader ;
int ret ;
doc = xmlReadFile ( filename , NULL , options ) ;
if ( doc = = NULL ) {
fprintf ( stderr , " Failed to parse %s \n " , filename ) ;
return ( - 1 ) ;
}
reader = xmlReaderWalker ( doc ) ;
2012-10-25 11:39:39 +04:00
ret = streamProcessTest ( filename , result , err , reader , NULL , options ) ;
2005-07-07 00:41:33 +04:00
xmlFreeTextReader ( reader ) ;
xmlFreeDoc ( doc ) ;
return ( ret ) ;
}
/**
* streamMemParseTest :
* @ filename : the file to parse
* @ result : the file with expected result
* @ err : the file with error messages
*
* Parse a file using the reader API from memory and check for errors .
*
* Returns 0 in case of success , an error code otherwise
*/
static int
streamMemParseTest ( const char * filename , const char * result , const char * err ,
int options ) {
xmlTextReaderPtr reader ;
int ret ;
const char * base ;
int size ;
/*
* load and parse the memory
*/
if ( loadMem ( filename , & base , & size ) ! = 0 ) {
fprintf ( stderr , " Failed to load %s \n " , filename ) ;
return ( - 1 ) ;
}
reader = xmlReaderForMemory ( base , size , filename , NULL , options ) ;
2012-10-25 11:39:39 +04:00
ret = streamProcessTest ( filename , result , err , reader , NULL , options ) ;
2005-07-07 00:41:33 +04:00
free ( ( char * ) base ) ;
xmlFreeTextReader ( reader ) ;
return ( ret ) ;
}
# endif
# ifdef LIBXML_XPATH_ENABLED
# ifdef LIBXML_DEBUG_ENABLED
/************************************************************************
* *
* XPath and XPointer based tests *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-07-29 03:49:35 +04:00
static FILE * xpathOutput ;
static xmlDocPtr xpathDocument ;
2005-07-07 00:41:33 +04:00
2016-06-25 13:35:09 +03:00
static void
ignoreGenericError ( void * ctx ATTRIBUTE_UNUSED ,
const char * msg ATTRIBUTE_UNUSED , . . . ) {
}
2005-07-07 00:41:33 +04:00
static void
testXPath ( const char * str , int xptr , int expr ) {
2016-06-25 13:35:09 +03:00
xmlGenericErrorFunc handler = ignoreGenericError ;
2005-07-07 00:41:33 +04:00
xmlXPathObjectPtr res ;
xmlXPathContextPtr ctxt ;
2008-08-25 18:53:31 +04:00
2016-06-25 13:35:09 +03:00
/* Don't print generic errors to stderr. */
initGenericErrorDefaultFunc ( & handler ) ;
2005-07-07 00:41:33 +04:00
nb_tests + + ;
# if defined(LIBXML_XPTR_ENABLED)
if ( xptr ) {
ctxt = xmlXPtrNewContext ( xpathDocument , NULL , NULL ) ;
res = xmlXPtrEval ( BAD_CAST str , ctxt ) ;
} else {
# endif
ctxt = xmlXPathNewContext ( xpathDocument ) ;
ctxt - > node = xmlDocGetRootElement ( xpathDocument ) ;
if ( expr )
res = xmlXPathEvalExpression ( BAD_CAST str , ctxt ) ;
else {
/* res = xmlXPathEval(BAD_CAST str, ctxt); */
xmlXPathCompExprPtr comp ;
comp = xmlXPathCompile ( BAD_CAST str ) ;
if ( comp ! = NULL ) {
res = xmlXPathCompiledEval ( comp , ctxt ) ;
xmlXPathFreeCompExpr ( comp ) ;
} else
res = NULL ;
}
# if defined(LIBXML_XPTR_ENABLED)
}
# endif
xmlXPathDebugDumpObject ( xpathOutput , res , 0 ) ;
xmlXPathFreeObject ( res ) ;
xmlXPathFreeContext ( ctxt ) ;
2016-06-25 13:35:09 +03:00
/* Reset generic error handler. */
initGenericErrorDefaultFunc ( NULL ) ;
2005-07-07 00:41:33 +04:00
}
/**
* xpathExprTest :
* @ filename : the file to parse
* @ result : the file with expected result
* @ err : the file with error messages
*
* Parse a file containing XPath standalone expressions and evaluate them
*
* Returns 0 in case of success , an error code otherwise
*/
static int
xpathCommonTest ( const char * filename , const char * result ,
int xptr , int expr ) {
FILE * input ;
char expression [ 5000 ] ;
int len , ret = 0 ;
char * temp ;
2020-06-04 12:58:04 +03:00
temp = resultFilename ( filename , temp_directory , " .res " ) ;
2005-07-07 00:41:33 +04:00
if ( temp = = NULL ) {
fprintf ( stderr , " Out of memory \n " ) ;
fatalError ( ) ;
}
xpathOutput = fopen ( temp , " wb " ) ;
if ( xpathOutput = = NULL ) {
fprintf ( stderr , " failed to open output file %s \n " , temp ) ;
free ( temp ) ;
return ( - 1 ) ;
}
input = fopen ( filename , " rb " ) ;
if ( input = = NULL ) {
xmlGenericError ( xmlGenericErrorContext ,
" Cannot open %s for reading \n " , filename ) ;
free ( temp ) ;
return ( - 1 ) ;
}
while ( fgets ( expression , 4500 , input ) ! = NULL ) {
len = strlen ( expression ) ;
len - - ;
2008-08-25 18:53:31 +04:00
while ( ( len > = 0 ) & &
2005-07-07 00:41:33 +04:00
( ( expression [ len ] = = ' \n ' ) | | ( expression [ len ] = = ' \t ' ) | |
( expression [ len ] = = ' \r ' ) | | ( expression [ len ] = = ' ' ) ) ) len - - ;
2008-08-25 18:53:31 +04:00
expression [ len + 1 ] = 0 ;
2005-07-07 00:41:33 +04:00
if ( len > = 0 ) {
fprintf ( xpathOutput ,
" \n ======================== \n Expression: %s \n " ,
expression ) ;
testXPath ( expression , xptr , expr ) ;
}
}
fclose ( input ) ;
fclose ( xpathOutput ) ;
if ( result ! = NULL ) {
ret = compareFiles ( temp , result ) ;
if ( ret ) {
2016-05-22 06:14:45 +03:00
fprintf ( stderr , " Result for %s failed in %s \n " , filename , result ) ;
2005-07-07 00:41:33 +04:00
}
}
2009-09-05 16:52:55 +04:00
if ( temp ! = NULL ) {
unlink ( temp ) ;
free ( temp ) ;
}
2005-07-07 00:41:33 +04:00
return ( ret ) ;
}
/**
* xpathExprTest :
* @ filename : the file to parse
* @ result : the file with expected result
* @ err : the file with error messages
*
* Parse a file containing XPath standalone expressions and evaluate them
*
* Returns 0 in case of success , an error code otherwise
*/
static int
xpathExprTest ( const char * filename , const char * result ,
const char * err ATTRIBUTE_UNUSED ,
int options ATTRIBUTE_UNUSED ) {
return ( xpathCommonTest ( filename , result , 0 , 1 ) ) ;
}
/**
* xpathDocTest :
* @ filename : the file to parse
* @ result : the file with expected result
* @ err : the file with error messages
*
* Parse a file containing XPath expressions and evaluate them against
* a set of corresponding documents .
*
* Returns 0 in case of success , an error code otherwise
*/
static int
xpathDocTest ( const char * filename ,
const char * resul ATTRIBUTE_UNUSED ,
const char * err ATTRIBUTE_UNUSED ,
int options ) {
char pattern [ 500 ] ;
char result [ 500 ] ;
glob_t globbuf ;
size_t i ;
int ret = 0 , res ;
xpathDocument = xmlReadFile ( filename , NULL ,
options | XML_PARSE_DTDATTR | XML_PARSE_NOENT ) ;
if ( xpathDocument = = NULL ) {
fprintf ( stderr , " Failed to load %s \n " , filename ) ;
return ( - 1 ) ;
}
2019-01-01 18:30:38 +03:00
res = snprintf ( pattern , 499 , " ./test/XPath/tests/%s* " ,
baseFilename ( filename ) ) ;
if ( res > = 499 )
pattern [ 499 ] = 0 ;
2005-07-07 00:41:33 +04:00
globbuf . gl_offs = 0 ;
glob ( pattern , GLOB_DOOFFS , NULL , & globbuf ) ;
for ( i = 0 ; i < globbuf . gl_pathc ; i + + ) {
2019-01-01 18:30:38 +03:00
res = snprintf ( result , 499 , " result/XPath/tests/%s " ,
2005-07-07 00:41:33 +04:00
baseFilename ( globbuf . gl_pathv [ i ] ) ) ;
2019-01-01 18:30:38 +03:00
if ( res > = 499 )
result [ 499 ] = 0 ;
2005-07-07 00:41:33 +04:00
res = xpathCommonTest ( globbuf . gl_pathv [ i ] , & result [ 0 ] , 0 , 0 ) ;
if ( res ! = 0 )
ret = res ;
}
globfree ( & globbuf ) ;
xmlFreeDoc ( xpathDocument ) ;
return ( ret ) ;
}
# ifdef LIBXML_XPTR_ENABLED
/**
* xptrDocTest :
* @ filename : the file to parse
* @ result : the file with expected result
* @ err : the file with error messages
*
* Parse a file containing XPath expressions and evaluate them against
* a set of corresponding documents .
*
* Returns 0 in case of success , an error code otherwise
*/
static int
xptrDocTest ( const char * filename ,
const char * resul ATTRIBUTE_UNUSED ,
const char * err ATTRIBUTE_UNUSED ,
int options ) {
char pattern [ 500 ] ;
char result [ 500 ] ;
glob_t globbuf ;
size_t i ;
int ret = 0 , res ;
xpathDocument = xmlReadFile ( filename , NULL ,
options | XML_PARSE_DTDATTR | XML_PARSE_NOENT ) ;
if ( xpathDocument = = NULL ) {
fprintf ( stderr , " Failed to load %s \n " , filename ) ;
return ( - 1 ) ;
}
2019-01-01 18:30:38 +03:00
res = snprintf ( pattern , 499 , " ./test/XPath/xptr/%s* " ,
baseFilename ( filename ) ) ;
if ( res > = 499 )
pattern [ 499 ] = 0 ;
2005-07-07 00:41:33 +04:00
globbuf . gl_offs = 0 ;
glob ( pattern , GLOB_DOOFFS , NULL , & globbuf ) ;
for ( i = 0 ; i < globbuf . gl_pathc ; i + + ) {
2019-01-01 18:30:38 +03:00
res = snprintf ( result , 499 , " result/XPath/xptr/%s " ,
2005-07-07 00:41:33 +04:00
baseFilename ( globbuf . gl_pathv [ i ] ) ) ;
2019-01-01 18:30:38 +03:00
if ( res > = 499 )
result [ 499 ] = 0 ;
2005-07-07 00:41:33 +04:00
res = xpathCommonTest ( globbuf . gl_pathv [ i ] , & result [ 0 ] , 1 , 0 ) ;
if ( res ! = 0 )
ret = res ;
}
globfree ( & globbuf ) ;
xmlFreeDoc ( xpathDocument ) ;
return ( ret ) ;
}
# endif /* LIBXML_XPTR_ENABLED */
/**
* xmlidDocTest :
* @ filename : the file to parse
* @ result : the file with expected result
* @ err : the file with error messages
*
* Parse a file containing xml : id and check for errors and verify
* that XPath queries will work on them as expected .
*
* Returns 0 in case of success , an error code otherwise
*/
static int
xmlidDocTest ( const char * filename ,
const char * result ,
const char * err ,
int options ) {
int res = 0 ;
int ret = 0 ;
char * temp ;
xpathDocument = xmlReadFile ( filename , NULL ,
options | XML_PARSE_DTDATTR | XML_PARSE_NOENT ) ;
if ( xpathDocument = = NULL ) {
fprintf ( stderr , " Failed to load %s \n " , filename ) ;
return ( - 1 ) ;
}
2020-06-04 12:58:04 +03:00
temp = resultFilename ( filename , temp_directory , " .res " ) ;
2005-07-07 00:41:33 +04:00
if ( temp = = NULL ) {
fprintf ( stderr , " Out of memory \n " ) ;
fatalError ( ) ;
}
xpathOutput = fopen ( temp , " wb " ) ;
if ( xpathOutput = = NULL ) {
fprintf ( stderr , " failed to open output file %s \n " , temp ) ;
xmlFreeDoc ( xpathDocument ) ;
free ( temp ) ;
return ( - 1 ) ;
}
testXPath ( " id('bar') " , 0 , 0 ) ;
fclose ( xpathOutput ) ;
if ( result ! = NULL ) {
ret = compareFiles ( temp , result ) ;
if ( ret ) {
2016-05-22 06:14:45 +03:00
fprintf ( stderr , " Result for %s failed in %s \n " , filename , result ) ;
2005-07-07 00:41:33 +04:00
res = 1 ;
}
}
2009-09-05 16:52:55 +04:00
if ( temp ! = NULL ) {
unlink ( temp ) ;
free ( temp ) ;
}
2005-07-07 00:41:33 +04:00
xmlFreeDoc ( xpathDocument ) ;
if ( err ! = NULL ) {
ret = compareFileMem ( err , testErrors , testErrorsSize ) ;
if ( ret ! = 0 ) {
fprintf ( stderr , " Error for %s failed \n " , filename ) ;
res = 1 ;
}
}
return ( res ) ;
}
# endif /* LIBXML_DEBUG_ENABLED */
# endif /* XPATH */
/************************************************************************
* *
* URI based tests *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void
handleURI ( const char * str , const char * base , FILE * o ) {
int ret ;
xmlURIPtr uri ;
2006-03-10 03:36:23 +03:00
xmlChar * res = NULL ;
2005-07-07 00:41:33 +04:00
uri = xmlCreateURI ( ) ;
if ( base = = NULL ) {
ret = xmlParseURIReference ( uri , str ) ;
if ( ret ! = 0 )
fprintf ( o , " %s : error %d \n " , str , ret ) ;
else {
xmlNormalizeURIPath ( uri - > path ) ;
xmlPrintURI ( o , uri ) ;
fprintf ( o , " \n " ) ;
}
} else {
res = xmlBuildURI ( ( xmlChar * ) str , ( xmlChar * ) base ) ;
if ( res ! = NULL ) {
fprintf ( o , " %s \n " , ( char * ) res ) ;
}
else
fprintf ( o , " ::ERROR:: \n " ) ;
}
if ( res ! = NULL )
xmlFree ( res ) ;
xmlFreeURI ( uri ) ;
}
/**
* uriCommonTest :
* @ filename : the file to parse
* @ result : the file with expected result
* @ err : the file with error messages
*
* Parse a file containing URI and check for errors
*
* Returns 0 in case of success , an error code otherwise
*/
static int
uriCommonTest ( const char * filename ,
const char * result ,
const char * err ,
const char * base ) {
char * temp ;
FILE * o , * f ;
char str [ 1024 ] ;
int res = 0 , i , ret ;
2020-06-04 12:58:04 +03:00
temp = resultFilename ( filename , temp_directory , " .res " ) ;
2005-07-07 00:41:33 +04:00
if ( temp = = NULL ) {
fprintf ( stderr , " Out of memory \n " ) ;
fatalError ( ) ;
}
o = fopen ( temp , " wb " ) ;
if ( o = = NULL ) {
fprintf ( stderr , " failed to open output file %s \n " , temp ) ;
free ( temp ) ;
return ( - 1 ) ;
}
f = fopen ( filename , " rb " ) ;
if ( f = = NULL ) {
fprintf ( stderr , " failed to open input file %s \n " , filename ) ;
fclose ( o ) ;
2009-09-05 16:52:55 +04:00
if ( temp ! = NULL ) {
unlink ( temp ) ;
free ( temp ) ;
}
2005-07-07 00:41:33 +04:00
return ( - 1 ) ;
}
while ( 1 ) {
/*
* read one line in string buffer .
*/
if ( fgets ( & str [ 0 ] , sizeof ( str ) - 1 , f ) = = NULL )
break ;
/*
* remove the ending spaces
*/
i = strlen ( str ) ;
while ( ( i > 0 ) & &
( ( str [ i - 1 ] = = ' \n ' ) | | ( str [ i - 1 ] = = ' \r ' ) | |
( str [ i - 1 ] = = ' ' ) | | ( str [ i - 1 ] = = ' \t ' ) ) ) {
i - - ;
str [ i ] = 0 ;
}
nb_tests + + ;
handleURI ( str , base , o ) ;
}
fclose ( f ) ;
fclose ( o ) ;
if ( result ! = NULL ) {
ret = compareFiles ( temp , result ) ;
if ( ret ) {
2016-05-22 06:14:45 +03:00
fprintf ( stderr , " Result for %s failed in %s \n " , filename , result ) ;
2005-07-07 00:41:33 +04:00
res = 1 ;
}
}
if ( err ! = NULL ) {
ret = compareFileMem ( err , testErrors , testErrorsSize ) ;
if ( ret ! = 0 ) {
fprintf ( stderr , " Error for %s failed \n " , filename ) ;
res = 1 ;
}
}
2009-09-05 16:52:55 +04:00
if ( temp ! = NULL ) {
unlink ( temp ) ;
free ( temp ) ;
}
2005-07-07 00:41:33 +04:00
return ( res ) ;
}
/**
* uriParseTest :
* @ filename : the file to parse
* @ result : the file with expected result
* @ err : the file with error messages
*
* Parse a file containing URI and check for errors
*
* Returns 0 in case of success , an error code otherwise
*/
static int
uriParseTest ( const char * filename ,
const char * result ,
const char * err ,
int options ATTRIBUTE_UNUSED ) {
return ( uriCommonTest ( filename , result , err , NULL ) ) ;
}
/**
* uriBaseTest :
* @ filename : the file to parse
* @ result : the file with expected result
* @ err : the file with error messages
*
* Parse a file containing URI , compose them against a fixed base and
* check for errors
*
* Returns 0 in case of success , an error code otherwise
*/
static int
uriBaseTest ( const char * filename ,
const char * result ,
const char * err ,
int options ATTRIBUTE_UNUSED ) {
return ( uriCommonTest ( filename , result , err ,
" http://foo.com/path/to/index.html?orig#help " ) ) ;
}
2005-08-07 14:46:19 +04:00
static int urip_success = 1 ;
static int urip_current = 0 ;
static const char * urip_testURLs [ ] = {
" urip://example.com/a b.html " ,
" urip://example.com/a%20b.html " ,
" file:///path/to/a b.html " ,
" file:///path/to/a%20b.html " ,
" /path/to/a b.html " ,
" /path/to/a%20b.html " ,
2012-08-20 16:58:24 +04:00
" urip://example.com/r " " \xe9 " " sum " " \xe9 " " .html " ,
2005-08-07 14:46:19 +04:00
" urip://example.com/test?a=1&b=2%263&c=4#foo " ,
NULL
} ;
static const char * urip_rcvsURLs [ ] = {
/* it is an URI the strings must be escaped */
" urip://example.com/a%20b.html " ,
/* check that % escaping is not broken */
" urip://example.com/a%20b.html " ,
/* it's an URI path the strings must be escaped */
" file:///path/to/a%20b.html " ,
/* check that % escaping is not broken */
" file:///path/to/a%20b.html " ,
/* this is not an URI, this is a path, so this should not be escaped */
" /path/to/a b.html " ,
/* check that paths with % are not broken */
" /path/to/a%20b.html " ,
/* out of context the encoding can't be guessed byte by byte conversion */
" urip://example.com/r%E9sum%E9.html " ,
/* verify we don't destroy URIs especially the query part */
" urip://example.com/test?a=1&b=2%263&c=4#foo " ,
NULL
} ;
static const char * urip_res = " <list/> " ;
static const char * urip_cur = NULL ;
static int urip_rlen ;
/**
* uripMatch :
* @ URI : an URI to test
*
* Check for an urip : query
*
* Returns 1 if yes and 0 if another Input module should be used
*/
static int
uripMatch ( const char * URI ) {
if ( ( URI = = NULL ) | | ( ! strcmp ( URI , " file:///etc/xml/catalog " ) ) )
return ( 0 ) ;
/* Verify we received the escaped URL */
if ( strcmp ( urip_rcvsURLs [ urip_current ] , URI ) )
urip_success = 0 ;
return ( 1 ) ;
}
/**
* uripOpen :
* @ URI : an URI to test
*
* Return a pointer to the urip : query handler , in this example simply
* the urip_current pointer . . .
*
* Returns an Input context or NULL in case or error
*/
static void *
uripOpen ( const char * URI ) {
if ( ( URI = = NULL ) | | ( ! strcmp ( URI , " file:///etc/xml/catalog " ) ) )
return ( NULL ) ;
/* Verify we received the escaped URL */
if ( strcmp ( urip_rcvsURLs [ urip_current ] , URI ) )
urip_success = 0 ;
urip_cur = urip_res ;
urip_rlen = strlen ( urip_res ) ;
return ( ( void * ) urip_cur ) ;
}
/**
* uripClose :
* @ context : the read context
*
* Close the urip : query handler
*
* Returns 0 or - 1 in case of error
*/
static int
uripClose ( void * context ) {
if ( context = = NULL ) return ( - 1 ) ;
urip_cur = NULL ;
urip_rlen = 0 ;
return ( 0 ) ;
}
/**
* uripRead :
* @ context : the read context
* @ buffer : where to store data
* @ len : number of bytes to read
*
* Implement an urip : query read .
*
* Returns the number of bytes read or - 1 in case of error
*/
static int
uripRead ( void * context , char * buffer , int len ) {
const char * ptr = ( const char * ) context ;
if ( ( context = = NULL ) | | ( buffer = = NULL ) | | ( len < 0 ) )
return ( - 1 ) ;
if ( len > urip_rlen ) len = urip_rlen ;
memcpy ( buffer , ptr , len ) ;
urip_rlen - = len ;
return ( len ) ;
}
static int
urip_checkURL ( const char * URL ) {
xmlDocPtr doc ;
doc = xmlReadFile ( URL , NULL , 0 ) ;
if ( doc = = NULL )
return ( - 1 ) ;
xmlFreeDoc ( doc ) ;
return ( 1 ) ;
}
/**
* uriPathTest :
* @ filename : ignored
* @ result : ignored
* @ err : ignored
*
* Run a set of tests to check how Path and URI are handled before
* being passed to the I / O layer
*
* Returns 0 in case of success , an error code otherwise
*/
static int
uriPathTest ( const char * filename ATTRIBUTE_UNUSED ,
const char * result ATTRIBUTE_UNUSED ,
const char * err ATTRIBUTE_UNUSED ,
int options ATTRIBUTE_UNUSED ) {
int parsed ;
int failures = 0 ;
/*
* register the new I / O handlers
*/
if ( xmlRegisterInputCallbacks ( uripMatch , uripOpen , uripRead , uripClose ) < 0 )
{
fprintf ( stderr , " failed to register HTTP handler \n " ) ;
return ( - 1 ) ;
}
for ( urip_current = 0 ; urip_testURLs [ urip_current ] ! = NULL ; urip_current + + ) {
urip_success = 1 ;
parsed = urip_checkURL ( urip_testURLs [ urip_current ] ) ;
if ( urip_success ! = 1 ) {
fprintf ( stderr , " failed the URL passing test for %s " ,
urip_testURLs [ urip_current ] ) ;
failures + + ;
} else if ( parsed ! = 1 ) {
fprintf ( stderr , " failed the parsing test for %s " ,
urip_testURLs [ urip_current ] ) ;
failures + + ;
}
nb_tests + + ;
}
xmlPopInputCallbacks ( ) ;
return ( failures ) ;
}
2005-07-07 00:41:33 +04:00
# ifdef LIBXML_SCHEMAS_ENABLED
/************************************************************************
* *
* Schemas tests *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int
schemasOneTest ( const char * sch ,
const char * filename ,
const char * result ,
const char * err ,
int options ,
xmlSchemaPtr schemas ) {
xmlDocPtr doc ;
xmlSchemaValidCtxtPtr ctxt ;
int ret = 0 ;
2006-06-18 21:31:31 +04:00
int validResult = 0 ;
2005-07-07 00:41:33 +04:00
char * temp ;
FILE * schemasOutput ;
doc = xmlReadFile ( filename , NULL , options ) ;
if ( doc = = NULL ) {
fprintf ( stderr , " failed to parse instance %s for %s \n " , filename , sch ) ;
return ( - 1 ) ;
}
2020-06-04 12:58:04 +03:00
temp = resultFilename ( result , temp_directory , " .res " ) ;
2005-07-07 00:41:33 +04:00
if ( temp = = NULL ) {
fprintf ( stderr , " Out of memory \n " ) ;
fatalError ( ) ;
}
schemasOutput = fopen ( temp , " wb " ) ;
if ( schemasOutput = = NULL ) {
fprintf ( stderr , " failed to open output file %s \n " , temp ) ;
xmlFreeDoc ( doc ) ;
free ( temp ) ;
return ( - 1 ) ;
}
ctxt = xmlSchemaNewValidCtxt ( schemas ) ;
2019-01-01 18:48:40 +03:00
xmlSchemaSetValidErrors ( ctxt , testErrorHandler , testErrorHandler , ctxt ) ;
2006-06-18 21:31:31 +04:00
validResult = xmlSchemaValidateDoc ( ctxt , doc ) ;
if ( validResult = = 0 ) {
2005-07-07 00:41:33 +04:00
fprintf ( schemasOutput , " %s validates \n " , filename ) ;
2006-06-18 21:31:31 +04:00
} else if ( validResult > 0 ) {
2005-07-07 00:41:33 +04:00
fprintf ( schemasOutput , " %s fails to validate \n " , filename ) ;
} else {
fprintf ( schemasOutput , " %s validation generated an internal error \n " ,
filename ) ;
}
fclose ( schemasOutput ) ;
if ( result ) {
if ( compareFiles ( temp , result ) ) {
fprintf ( stderr , " Result for %s on %s failed \n " , filename , sch ) ;
ret = 1 ;
}
}
2009-09-05 16:52:55 +04:00
if ( temp ! = NULL ) {
unlink ( temp ) ;
free ( temp ) ;
}
2005-07-07 00:41:33 +04:00
2006-06-18 21:31:31 +04:00
if ( ( validResult ! = 0 ) & & ( err ! = NULL ) ) {
2005-07-07 00:41:33 +04:00
if ( compareFileMem ( err , testErrors , testErrorsSize ) ) {
fprintf ( stderr , " Error for %s on %s failed \n " , filename , sch ) ;
ret = 1 ;
}
}
xmlSchemaFreeValidCtxt ( ctxt ) ;
xmlFreeDoc ( doc ) ;
return ( ret ) ;
}
/**
* schemasTest :
* @ filename : the schemas file
* @ result : the file with expected result
* @ err : the file with error messages
*
* Parse a file containing URI , compose them against a fixed base and
* check for errors
*
* Returns 0 in case of success , an error code otherwise
*/
static int
schemasTest ( const char * filename ,
const char * resul ATTRIBUTE_UNUSED ,
const char * errr ATTRIBUTE_UNUSED ,
int options ) {
const char * base = baseFilename ( filename ) ;
const char * base2 ;
const char * instance ;
xmlSchemaParserCtxtPtr ctxt ;
xmlSchemaPtr schemas ;
int res = 0 , len , ret ;
char pattern [ 500 ] ;
char prefix [ 500 ] ;
char result [ 500 ] ;
char err [ 500 ] ;
glob_t globbuf ;
size_t i ;
char count = 0 ;
/* first compile the schemas if possible */
ctxt = xmlSchemaNewParserCtxt ( filename ) ;
2019-01-01 18:48:40 +03:00
xmlSchemaSetParserErrors ( ctxt , testErrorHandler , testErrorHandler , ctxt ) ;
2005-07-07 00:41:33 +04:00
schemas = xmlSchemaParse ( ctxt ) ;
xmlSchemaFreeParserCtxt ( ctxt ) ;
/*
* most of the mess is about the output filenames generated by the Makefile
*/
len = strlen ( base ) ;
if ( ( len > 499 ) | | ( len < 5 ) ) {
xmlSchemaFree ( schemas ) ;
return ( - 1 ) ;
}
len - = 4 ; /* remove trailing .xsd */
if ( base [ len - 2 ] = = ' _ ' ) {
len - = 2 ; /* remove subtest number */
}
if ( base [ len - 2 ] = = ' _ ' ) {
len - = 2 ; /* remove subtest number */
}
memcpy ( prefix , base , len ) ;
prefix [ len ] = 0 ;
2019-01-01 18:30:38 +03:00
if ( snprintf ( pattern , 499 , " ./test/schemas/%s_?.xml " , prefix ) > = 499 )
pattern [ 499 ] = 0 ;
2005-07-07 00:41:33 +04:00
if ( base [ len ] = = ' _ ' ) {
len + = 2 ;
memcpy ( prefix , base , len ) ;
prefix [ len ] = 0 ;
}
globbuf . gl_offs = 0 ;
glob ( pattern , GLOB_DOOFFS , NULL , & globbuf ) ;
for ( i = 0 ; i < globbuf . gl_pathc ; i + + ) {
testErrorsSize = 0 ;
testErrors [ 0 ] = 0 ;
instance = globbuf . gl_pathv [ i ] ;
base2 = baseFilename ( instance ) ;
len = strlen ( base2 ) ;
if ( ( len > 6 ) & & ( base2 [ len - 6 ] = = ' _ ' ) ) {
count = base2 [ len - 5 ] ;
2019-01-01 18:30:38 +03:00
ret = snprintf ( result , 499 , " result/schemas/%s_%c " ,
2005-07-07 00:41:33 +04:00
prefix , count ) ;
2019-01-01 18:30:38 +03:00
if ( ret > = 499 )
result [ 499 ] = 0 ;
ret = snprintf ( err , 499 , " result/schemas/%s_%c.err " ,
2005-07-07 00:41:33 +04:00
prefix , count ) ;
2019-01-01 18:30:38 +03:00
if ( ret > = 499 )
err [ 499 ] = 0 ;
2005-07-07 00:41:33 +04:00
} else {
fprintf ( stderr , " don't know how to process %s \n " , instance ) ;
continue ;
}
if ( schemas = = NULL ) {
} else {
nb_tests + + ;
ret = schemasOneTest ( filename , instance , result , err ,
options , schemas ) ;
2005-11-15 11:50:04 +03:00
if ( ret ! = 0 )
res = ret ;
2005-07-07 00:41:33 +04:00
}
}
globfree ( & globbuf ) ;
xmlSchemaFree ( schemas ) ;
return ( res ) ;
}
/************************************************************************
* *
* Schemas tests *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int
rngOneTest ( const char * sch ,
const char * filename ,
const char * result ,
const char * err ,
int options ,
xmlRelaxNGPtr schemas ) {
xmlDocPtr doc ;
xmlRelaxNGValidCtxtPtr ctxt ;
int ret = 0 ;
char * temp ;
FILE * schemasOutput ;
doc = xmlReadFile ( filename , NULL , options ) ;
if ( doc = = NULL ) {
fprintf ( stderr , " failed to parse instance %s for %s \n " , filename , sch ) ;
return ( - 1 ) ;
}
2020-06-04 12:58:04 +03:00
temp = resultFilename ( result , temp_directory , " .res " ) ;
2005-07-07 00:41:33 +04:00
if ( temp = = NULL ) {
fprintf ( stderr , " Out of memory \n " ) ;
fatalError ( ) ;
}
schemasOutput = fopen ( temp , " wb " ) ;
if ( schemasOutput = = NULL ) {
fprintf ( stderr , " failed to open output file %s \n " , temp ) ;
xmlFreeDoc ( doc ) ;
free ( temp ) ;
return ( - 1 ) ;
}
ctxt = xmlRelaxNGNewValidCtxt ( schemas ) ;
2019-01-01 18:48:40 +03:00
xmlRelaxNGSetValidErrors ( ctxt , testErrorHandler , testErrorHandler , ctxt ) ;
2005-07-07 00:41:33 +04:00
ret = xmlRelaxNGValidateDoc ( ctxt , doc ) ;
if ( ret = = 0 ) {
testErrorHandler ( NULL , " %s validates \n " , filename ) ;
} else if ( ret > 0 ) {
testErrorHandler ( NULL , " %s fails to validate \n " , filename ) ;
} else {
testErrorHandler ( NULL , " %s validation generated an internal error \n " ,
filename ) ;
}
fclose ( schemasOutput ) ;
2009-09-07 16:58:47 +04:00
ret = 0 ;
2005-07-07 00:41:33 +04:00
if ( result ) {
if ( compareFiles ( temp , result ) ) {
fprintf ( stderr , " Result for %s on %s failed \n " , filename , sch ) ;
ret = 1 ;
}
}
2009-09-05 16:52:55 +04:00
if ( temp ! = NULL ) {
unlink ( temp ) ;
free ( temp ) ;
}
2005-07-07 00:41:33 +04:00
if ( err ! = NULL ) {
if ( compareFileMem ( err , testErrors , testErrorsSize ) ) {
fprintf ( stderr , " Error for %s on %s failed \n " , filename , sch ) ;
ret = 1 ;
printf ( " %s " , testErrors ) ;
}
}
xmlRelaxNGFreeValidCtxt ( ctxt ) ;
xmlFreeDoc ( doc ) ;
return ( ret ) ;
}
/**
* rngTest :
* @ filename : the schemas file
* @ result : the file with expected result
* @ err : the file with error messages
*
* Parse an RNG schemas and then apply it to the related . xml
*
* Returns 0 in case of success , an error code otherwise
*/
static int
rngTest ( const char * filename ,
const char * resul ATTRIBUTE_UNUSED ,
const char * errr ATTRIBUTE_UNUSED ,
int options ) {
const char * base = baseFilename ( filename ) ;
const char * base2 ;
const char * instance ;
xmlRelaxNGParserCtxtPtr ctxt ;
xmlRelaxNGPtr schemas ;
2010-01-22 16:24:25 +03:00
int res = 0 , len , ret = 0 ;
2005-07-07 00:41:33 +04:00
char pattern [ 500 ] ;
char prefix [ 500 ] ;
char result [ 500 ] ;
char err [ 500 ] ;
glob_t globbuf ;
size_t i ;
char count = 0 ;
/* first compile the schemas if possible */
ctxt = xmlRelaxNGNewParserCtxt ( filename ) ;
2019-01-01 18:48:40 +03:00
xmlRelaxNGSetParserErrors ( ctxt , testErrorHandler , testErrorHandler , ctxt ) ;
2005-07-07 00:41:33 +04:00
schemas = xmlRelaxNGParse ( ctxt ) ;
xmlRelaxNGFreeParserCtxt ( ctxt ) ;
/*
* most of the mess is about the output filenames generated by the Makefile
*/
len = strlen ( base ) ;
if ( ( len > 499 ) | | ( len < 5 ) ) {
xmlRelaxNGFree ( schemas ) ;
return ( - 1 ) ;
}
len - = 4 ; /* remove trailing .rng */
memcpy ( prefix , base , len ) ;
prefix [ len ] = 0 ;
2019-01-01 18:30:38 +03:00
if ( snprintf ( pattern , 499 , " ./test/relaxng/%s_?.xml " , prefix ) > = 499 )
pattern [ 499 ] = 0 ;
2005-07-07 00:41:33 +04:00
globbuf . gl_offs = 0 ;
glob ( pattern , GLOB_DOOFFS , NULL , & globbuf ) ;
for ( i = 0 ; i < globbuf . gl_pathc ; i + + ) {
testErrorsSize = 0 ;
testErrors [ 0 ] = 0 ;
instance = globbuf . gl_pathv [ i ] ;
base2 = baseFilename ( instance ) ;
len = strlen ( base2 ) ;
if ( ( len > 6 ) & & ( base2 [ len - 6 ] = = ' _ ' ) ) {
count = base2 [ len - 5 ] ;
2019-01-01 18:30:38 +03:00
res = snprintf ( result , 499 , " result/relaxng/%s_%c " ,
2005-07-07 00:41:33 +04:00
prefix , count ) ;
2019-01-01 18:30:38 +03:00
if ( res > = 499 )
result [ 499 ] = 0 ;
res = snprintf ( err , 499 , " result/relaxng/%s_%c.err " ,
2005-07-07 00:41:33 +04:00
prefix , count ) ;
2019-01-01 18:30:38 +03:00
if ( res > = 499 )
err [ 499 ] = 0 ;
2005-07-07 00:41:33 +04:00
} else {
fprintf ( stderr , " don't know how to process %s \n " , instance ) ;
continue ;
}
if ( schemas = = NULL ) {
} else {
nb_tests + + ;
2019-01-01 18:30:38 +03:00
res = rngOneTest ( filename , instance , result , err ,
2005-07-07 00:41:33 +04:00
options , schemas ) ;
if ( res ! = 0 )
ret = res ;
}
}
globfree ( & globbuf ) ;
xmlRelaxNGFree ( schemas ) ;
2009-09-07 16:58:47 +04:00
return ( ret ) ;
2005-07-07 00:41:33 +04:00
}
# ifdef LIBXML_READER_ENABLED
/**
* rngStreamTest :
* @ filename : the schemas file
* @ result : the file with expected result
* @ err : the file with error messages
*
2008-08-25 18:53:31 +04:00
* Parse a set of files with streaming , applying an RNG schemas
2005-07-07 00:41:33 +04:00
*
* Returns 0 in case of success , an error code otherwise
*/
static int
rngStreamTest ( const char * filename ,
const char * resul ATTRIBUTE_UNUSED ,
const char * errr ATTRIBUTE_UNUSED ,
int options ) {
const char * base = baseFilename ( filename ) ;
const char * base2 ;
const char * instance ;
int res = 0 , len , ret ;
char pattern [ 500 ] ;
char prefix [ 500 ] ;
char result [ 500 ] ;
char err [ 500 ] ;
glob_t globbuf ;
size_t i ;
char count = 0 ;
xmlTextReaderPtr reader ;
int disable_err = 0 ;
/*
* most of the mess is about the output filenames generated by the Makefile
*/
len = strlen ( base ) ;
if ( ( len > 499 ) | | ( len < 5 ) ) {
fprintf ( stderr , " len(base) == %d ! \n " , len ) ;
return ( - 1 ) ;
}
len - = 4 ; /* remove trailing .rng */
memcpy ( prefix , base , len ) ;
prefix [ len ] = 0 ;
/*
* strictly unifying the error messages is nearly impossible this
* hack is also done in the Makefile
*/
if ( ( ! strcmp ( prefix , " tutor10_1 " ) ) | | ( ! strcmp ( prefix , " tutor10_2 " ) ) | |
2009-08-26 20:37:43 +04:00
( ! strcmp ( prefix , " tutor3_2 " ) ) | | ( ! strcmp ( prefix , " 307377 " ) ) | |
( ! strcmp ( prefix , " tutor8_2 " ) ) )
2005-07-07 00:41:33 +04:00
disable_err = 1 ;
2019-01-01 18:30:38 +03:00
if ( snprintf ( pattern , 499 , " ./test/relaxng/%s_?.xml " , prefix ) > = 499 )
pattern [ 499 ] = 0 ;
2005-07-07 00:41:33 +04:00
globbuf . gl_offs = 0 ;
glob ( pattern , GLOB_DOOFFS , NULL , & globbuf ) ;
for ( i = 0 ; i < globbuf . gl_pathc ; i + + ) {
testErrorsSize = 0 ;
testErrors [ 0 ] = 0 ;
instance = globbuf . gl_pathv [ i ] ;
base2 = baseFilename ( instance ) ;
len = strlen ( base2 ) ;
if ( ( len > 6 ) & & ( base2 [ len - 6 ] = = ' _ ' ) ) {
count = base2 [ len - 5 ] ;
2019-01-01 18:30:38 +03:00
ret = snprintf ( result , 499 , " result/relaxng/%s_%c " ,
2005-07-07 00:41:33 +04:00
prefix , count ) ;
2019-01-01 18:30:38 +03:00
if ( ret > = 499 )
result [ 499 ] = 0 ;
ret = snprintf ( err , 499 , " result/relaxng/%s_%c.err " ,
2005-07-07 00:41:33 +04:00
prefix , count ) ;
2019-01-01 18:30:38 +03:00
if ( ret > = 499 )
err [ 499 ] = 0 ;
2005-07-07 00:41:33 +04:00
} else {
fprintf ( stderr , " don't know how to process %s \n " , instance ) ;
continue ;
}
reader = xmlReaderForFile ( instance , NULL , options ) ;
if ( reader = = NULL ) {
2019-09-30 18:04:54 +03:00
fprintf ( stderr , " Failed to build reader for %s \n " , instance ) ;
2005-07-07 00:41:33 +04:00
}
if ( disable_err = = 1 )
2012-10-25 11:39:39 +04:00
ret = streamProcessTest ( instance , result , NULL , reader , filename ,
options ) ;
2005-07-07 00:41:33 +04:00
else
2012-10-25 11:39:39 +04:00
ret = streamProcessTest ( instance , result , err , reader , filename ,
options ) ;
2005-07-07 00:41:33 +04:00
xmlFreeTextReader ( reader ) ;
if ( ret ! = 0 ) {
fprintf ( stderr , " instance %s failed \n " , instance ) ;
res = ret ;
}
}
globfree ( & globbuf ) ;
return ( res ) ;
}
# endif /* READER */
# endif
# ifdef LIBXML_PATTERN_ENABLED
# ifdef LIBXML_READER_ENABLED
/************************************************************************
* *
* Patterns tests *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void patternNode ( FILE * out , xmlTextReaderPtr reader ,
const char * pattern , xmlPatternPtr patternc ,
xmlStreamCtxtPtr patstream ) {
xmlChar * path = NULL ;
int match = - 1 ;
int type , empty ;
type = xmlTextReaderNodeType ( reader ) ;
empty = xmlTextReaderIsEmptyElement ( reader ) ;
2008-08-25 18:53:31 +04:00
2005-07-07 00:41:33 +04:00
if ( type = = XML_READER_TYPE_ELEMENT ) {
/* do the check only on element start */
match = xmlPatternMatch ( patternc , xmlTextReaderCurrentNode ( reader ) ) ;
if ( match ) {
path = xmlGetNodePath ( xmlTextReaderCurrentNode ( reader ) ) ;
fprintf ( out , " Node %s matches pattern %s \n " , path , pattern ) ;
}
}
if ( patstream ! = NULL ) {
int ret ;
if ( type = = XML_READER_TYPE_ELEMENT ) {
ret = xmlStreamPush ( patstream ,
xmlTextReaderConstLocalName ( reader ) ,
xmlTextReaderConstNamespaceUri ( reader ) ) ;
if ( ret < 0 ) {
fprintf ( out , " xmlStreamPush() failure \n " ) ;
xmlFreeStreamCtxt ( patstream ) ;
patstream = NULL ;
} else if ( ret ! = match ) {
if ( path = = NULL ) {
path = xmlGetNodePath (
xmlTextReaderCurrentNode ( reader ) ) ;
}
fprintf ( out ,
" xmlPatternMatch and xmlStreamPush disagree \n " ) ;
fprintf ( out ,
" pattern %s node %s \n " ,
pattern , path ) ;
}
2008-08-25 18:53:31 +04:00
}
2005-07-07 00:41:33 +04:00
if ( ( type = = XML_READER_TYPE_END_ELEMENT ) | |
( ( type = = XML_READER_TYPE_ELEMENT ) & & ( empty ) ) ) {
ret = xmlStreamPop ( patstream ) ;
if ( ret < 0 ) {
fprintf ( out , " xmlStreamPop() failure \n " ) ;
xmlFreeStreamCtxt ( patstream ) ;
patstream = NULL ;
}
}
}
if ( path ! = NULL )
xmlFree ( path ) ;
}
/**
* patternTest :
* @ filename : the schemas file
* @ result : the file with expected result
* @ err : the file with error messages
*
2008-08-25 18:53:31 +04:00
* Parse a set of files with streaming , applying an RNG schemas
2005-07-07 00:41:33 +04:00
*
* Returns 0 in case of success , an error code otherwise
*/
static int
patternTest ( const char * filename ,
const char * resul ATTRIBUTE_UNUSED ,
const char * err ATTRIBUTE_UNUSED ,
int options ) {
xmlPatternPtr patternc = NULL ;
xmlStreamCtxtPtr patstream = NULL ;
FILE * o , * f ;
char str [ 1024 ] ;
char xml [ 500 ] ;
char result [ 500 ] ;
int len , i ;
int ret = 0 , res ;
char * temp ;
xmlTextReaderPtr reader ;
xmlDocPtr doc ;
len = strlen ( filename ) ;
len - = 4 ;
memcpy ( xml , filename , len ) ;
xml [ len ] = 0 ;
2019-01-01 18:30:38 +03:00
if ( snprintf ( result , 499 , " result/pattern/%s " , baseFilename ( xml ) ) > = 499 )
result [ 499 ] = 0 ;
2005-07-07 00:41:33 +04:00
memcpy ( xml + len , " .xml " , 5 ) ;
2016-05-22 04:58:30 +03:00
if ( ! checkTestFile ( xml ) & & ! update_results ) {
2005-07-07 00:41:33 +04:00
fprintf ( stderr , " Missing xml file %s \n " , xml ) ;
return ( - 1 ) ;
}
2016-05-22 04:58:30 +03:00
if ( ! checkTestFile ( result ) & & ! update_results ) {
2005-07-07 00:41:33 +04:00
fprintf ( stderr , " Missing result file %s \n " , result ) ;
return ( - 1 ) ;
}
f = fopen ( filename , " rb " ) ;
if ( f = = NULL ) {
fprintf ( stderr , " Failed to open %s \n " , filename ) ;
return ( - 1 ) ;
}
2020-06-04 12:58:04 +03:00
temp = resultFilename ( filename , temp_directory , " .res " ) ;
2005-07-07 00:41:33 +04:00
if ( temp = = NULL ) {
fprintf ( stderr , " Out of memory \n " ) ;
fatalError ( ) ;
}
o = fopen ( temp , " wb " ) ;
if ( o = = NULL ) {
fprintf ( stderr , " failed to open output file %s \n " , temp ) ;
fclose ( f ) ;
free ( temp ) ;
return ( - 1 ) ;
}
while ( 1 ) {
/*
* read one line in string buffer .
*/
if ( fgets ( & str [ 0 ] , sizeof ( str ) - 1 , f ) = = NULL )
break ;
/*
* remove the ending spaces
*/
i = strlen ( str ) ;
while ( ( i > 0 ) & &
( ( str [ i - 1 ] = = ' \n ' ) | | ( str [ i - 1 ] = = ' \r ' ) | |
( str [ i - 1 ] = = ' ' ) | | ( str [ i - 1 ] = = ' \t ' ) ) ) {
i - - ;
str [ i ] = 0 ;
}
doc = xmlReadFile ( xml , NULL , options ) ;
if ( doc = = NULL ) {
fprintf ( stderr , " Failed to parse %s \n " , xml ) ;
ret = 1 ;
} else {
xmlNodePtr root ;
const xmlChar * namespaces [ 22 ] ;
int j ;
xmlNsPtr ns ;
root = xmlDocGetRootElement ( doc ) ;
for ( ns = root - > nsDef , j = 0 ; ns ! = NULL & & j < 20 ; ns = ns - > next ) {
namespaces [ j + + ] = ns - > href ;
namespaces [ j + + ] = ns - > prefix ;
}
namespaces [ j + + ] = NULL ;
2009-09-05 16:52:55 +04:00
namespaces [ j ] = NULL ;
2005-07-07 00:41:33 +04:00
patternc = xmlPatterncompile ( ( const xmlChar * ) str , doc - > dict ,
0 , & namespaces [ 0 ] ) ;
if ( patternc = = NULL ) {
testErrorHandler ( NULL ,
" Pattern %s failed to compile \n " , str ) ;
xmlFreeDoc ( doc ) ;
ret = 1 ;
continue ;
}
patstream = xmlPatternGetStreamCtxt ( patternc ) ;
if ( patstream ! = NULL ) {
ret = xmlStreamPush ( patstream , NULL , NULL ) ;
if ( ret < 0 ) {
fprintf ( stderr , " xmlStreamPush() failure \n " ) ;
xmlFreeStreamCtxt ( patstream ) ;
patstream = NULL ;
}
}
nb_tests + + ;
reader = xmlReaderWalker ( doc ) ;
res = xmlTextReaderRead ( reader ) ;
while ( res = = 1 ) {
patternNode ( o , reader , str , patternc , patstream ) ;
res = xmlTextReaderRead ( reader ) ;
}
if ( res ! = 0 ) {
fprintf ( o , " %s : failed to parse \n " , filename ) ;
}
xmlFreeTextReader ( reader ) ;
xmlFreeDoc ( doc ) ;
xmlFreeStreamCtxt ( patstream ) ;
patstream = NULL ;
xmlFreePattern ( patternc ) ;
}
}
fclose ( f ) ;
fclose ( o ) ;
ret = compareFiles ( temp , result ) ;
if ( ret ) {
2016-05-22 06:14:45 +03:00
fprintf ( stderr , " Result for %s failed in %s \n " , filename , result ) ;
2005-07-07 00:41:33 +04:00
ret = 1 ;
}
2009-09-05 16:52:55 +04:00
if ( temp ! = NULL ) {
unlink ( temp ) ;
free ( temp ) ;
}
2005-07-07 00:41:33 +04:00
return ( ret ) ;
}
# endif /* READER */
# endif /* PATTERN */
# ifdef LIBXML_C14N_ENABLED
/************************************************************************
* *
* Canonicalization tests *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static xmlXPathObjectPtr
load_xpath_expr ( xmlDocPtr parent_doc , const char * filename ) {
2008-08-25 18:53:31 +04:00
xmlXPathObjectPtr xpath ;
2005-07-07 00:41:33 +04:00
xmlDocPtr doc ;
xmlChar * expr ;
2008-08-25 18:53:31 +04:00
xmlXPathContextPtr ctx ;
2005-07-07 00:41:33 +04:00
xmlNodePtr node ;
xmlNsPtr ns ;
2008-08-25 18:53:31 +04:00
2005-07-07 00:41:33 +04:00
/*
* load XPath expr as a file
*/
xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS ;
xmlSubstituteEntitiesDefault ( 1 ) ;
2005-08-24 02:14:02 +04:00
doc = xmlReadFile ( filename , NULL , XML_PARSE_DTDATTR | XML_PARSE_NOENT ) ;
2005-07-07 00:41:33 +04:00
if ( doc = = NULL ) {
fprintf ( stderr , " Error: unable to parse file \" %s \" \n " , filename ) ;
return ( NULL ) ;
}
2008-08-25 18:53:31 +04:00
2005-07-07 00:41:33 +04:00
/*
* Check the document is of the right kind
2008-08-25 18:53:31 +04:00
*/
2005-07-07 00:41:33 +04:00
if ( xmlDocGetRootElement ( doc ) = = NULL ) {
fprintf ( stderr , " Error: empty document for file \" %s \" \n " , filename ) ;
xmlFreeDoc ( doc ) ;
return ( NULL ) ;
}
node = doc - > children ;
while ( node ! = NULL & & ! xmlStrEqual ( node - > name , ( const xmlChar * ) " XPath " ) ) {
node = node - > next ;
}
2008-08-25 18:53:31 +04:00
if ( node = = NULL ) {
2005-07-07 00:41:33 +04:00
fprintf ( stderr , " Error: XPath element expected in the file \" %s \" \n " , filename ) ;
xmlFreeDoc ( doc ) ;
return ( NULL ) ;
}
expr = xmlNodeGetContent ( node ) ;
if ( expr = = NULL ) {
fprintf ( stderr , " Error: XPath content element is NULL \" %s \" \n " , filename ) ;
xmlFreeDoc ( doc ) ;
return ( NULL ) ;
}
ctx = xmlXPathNewContext ( parent_doc ) ;
if ( ctx = = NULL ) {
fprintf ( stderr , " Error: unable to create new context \n " ) ;
2008-08-25 18:53:31 +04:00
xmlFree ( expr ) ;
xmlFreeDoc ( doc ) ;
2005-07-07 00:41:33 +04:00
return ( NULL ) ;
}
/*
* Register namespaces
*/
ns = node - > nsDef ;
while ( ns ! = NULL ) {
if ( xmlXPathRegisterNs ( ctx , ns - > prefix , ns - > href ) ! = 0 ) {
fprintf ( stderr , " Error: unable to register NS with prefix= \" %s \" and href= \" %s \" \n " , ns - > prefix , ns - > href ) ;
2008-08-25 18:53:31 +04:00
xmlFree ( expr ) ;
xmlXPathFreeContext ( ctx ) ;
xmlFreeDoc ( doc ) ;
2005-07-07 00:41:33 +04:00
return ( NULL ) ;
}
ns = ns - > next ;
}
2008-08-25 18:53:31 +04:00
/*
2005-07-07 00:41:33 +04:00
* Evaluate xpath
*/
xpath = xmlXPathEvalExpression ( expr , ctx ) ;
if ( xpath = = NULL ) {
fprintf ( stderr , " Error: unable to evaluate xpath expression \n " ) ;
2008-08-25 18:53:31 +04:00
xmlFree ( expr ) ;
xmlXPathFreeContext ( ctx ) ;
xmlFreeDoc ( doc ) ;
2005-07-07 00:41:33 +04:00
return ( NULL ) ;
}
/* print_xpath_nodes(xpath->nodesetval); */
2008-08-25 18:53:31 +04:00
xmlFree ( expr ) ;
xmlXPathFreeContext ( ctx ) ;
xmlFreeDoc ( doc ) ;
2005-07-07 00:41:33 +04:00
return ( xpath ) ;
}
/*
* Macro used to grow the current buffer .
*/
# define xxx_growBufferReentrant() { \
buffer_size * = 2 ; \
buffer = ( xmlChar * * ) \
2008-08-25 18:53:31 +04:00
xmlRealloc ( buffer , buffer_size * sizeof ( xmlChar * ) ) ; \
2005-07-07 00:41:33 +04:00
if ( buffer = = NULL ) { \
perror ( " realloc failed " ) ; \
return ( NULL ) ; \
} \
}
static xmlChar * *
parse_list ( xmlChar * str ) {
xmlChar * * buffer ;
xmlChar * * out = NULL ;
int buffer_size = 0 ;
int len ;
if ( str = = NULL ) {
return ( NULL ) ;
}
len = xmlStrlen ( str ) ;
if ( ( str [ 0 ] = = ' \' ' ) & & ( str [ len - 1 ] = = ' \' ' ) ) {
str [ len - 1 ] = ' \0 ' ;
str + + ;
}
/*
* allocate an translation buffer .
*/
buffer_size = 1000 ;
buffer = ( xmlChar * * ) xmlMalloc ( buffer_size * sizeof ( xmlChar * ) ) ;
if ( buffer = = NULL ) {
perror ( " malloc failed " ) ;
return ( NULL ) ;
}
out = buffer ;
2008-08-25 18:53:31 +04:00
2005-07-07 00:41:33 +04:00
while ( * str ! = ' \0 ' ) {
if ( out - buffer > buffer_size - 10 ) {
int indx = out - buffer ;
xxx_growBufferReentrant ( ) ;
out = & buffer [ indx ] ;
}
( * out + + ) = str ;
while ( * str ! = ' , ' & & * str ! = ' \0 ' ) + + str ;
if ( * str = = ' , ' ) * ( str + + ) = ' \0 ' ;
}
( * out ) = NULL ;
return buffer ;
}
2008-08-25 18:53:31 +04:00
static int
2009-07-09 12:26:22 +04:00
c14nRunTest ( const char * xml_filename , int with_comments , int mode ,
2005-07-07 00:41:33 +04:00
const char * xpath_filename , const char * ns_filename ,
const char * result_file ) {
xmlDocPtr doc ;
2008-08-25 18:53:31 +04:00
xmlXPathObjectPtr xpath = NULL ;
2005-07-07 00:41:33 +04:00
xmlChar * result = NULL ;
int ret ;
xmlChar * * inclusive_namespaces = NULL ;
const char * nslist = NULL ;
int nssize ;
/*
* build an XML tree from a the file ; we need to add default
* attributes and resolve all character and entities references
*/
xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS ;
xmlSubstituteEntitiesDefault ( 1 ) ;
2005-08-24 02:14:02 +04:00
doc = xmlReadFile ( xml_filename , NULL , XML_PARSE_DTDATTR | XML_PARSE_NOENT ) ;
2005-07-07 00:41:33 +04:00
if ( doc = = NULL ) {
fprintf ( stderr , " Error: unable to parse file \" %s \" \n " , xml_filename ) ;
return ( - 1 ) ;
}
2008-08-25 18:53:31 +04:00
2005-07-07 00:41:33 +04:00
/*
* Check the document is of the right kind
2008-08-25 18:53:31 +04:00
*/
2005-07-07 00:41:33 +04:00
if ( xmlDocGetRootElement ( doc ) = = NULL ) {
fprintf ( stderr , " Error: empty document for file \" %s \" \n " , xml_filename ) ;
xmlFreeDoc ( doc ) ;
return ( - 1 ) ;
}
2008-08-25 18:53:31 +04:00
/*
* load xpath file if specified
2005-07-07 00:41:33 +04:00
*/
if ( xpath_filename ) {
xpath = load_xpath_expr ( doc , xpath_filename ) ;
if ( xpath = = NULL ) {
fprintf ( stderr , " Error: unable to evaluate xpath expression \n " ) ;
2008-08-25 18:53:31 +04:00
xmlFreeDoc ( doc ) ;
2005-07-07 00:41:33 +04:00
return ( - 1 ) ;
}
}
if ( ns_filename ! = NULL ) {
if ( loadMem ( ns_filename , & nslist , & nssize ) ) {
fprintf ( stderr , " Error: unable to evaluate xpath expression \n " ) ;
if ( xpath ! = NULL ) xmlXPathFreeObject ( xpath ) ;
2008-08-25 18:53:31 +04:00
xmlFreeDoc ( doc ) ;
2005-07-07 00:41:33 +04:00
return ( - 1 ) ;
}
inclusive_namespaces = parse_list ( ( xmlChar * ) nslist ) ;
}
/*
* Canonical form
2008-08-25 18:53:31 +04:00
*/
2005-07-07 00:41:33 +04:00
/* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */
2008-08-25 18:53:31 +04:00
ret = xmlC14NDocDumpMemory ( doc ,
( xpath ) ? xpath - > nodesetval : NULL ,
2009-07-09 12:26:22 +04:00
mode , inclusive_namespaces ,
2005-07-07 00:41:33 +04:00
with_comments , & result ) ;
if ( ret > = 0 ) {
if ( result ! = NULL ) {
if ( compareFileMem ( result_file , ( const char * ) result , ret ) ) {
fprintf ( stderr , " Result mismatch for %s \n " , xml_filename ) ;
2009-07-09 12:26:22 +04:00
fprintf ( stderr , " RESULT: \n %s \n " , ( const char * ) result ) ;
2005-07-07 00:41:33 +04:00
ret = - 1 ;
}
}
} else {
fprintf ( stderr , " Error: failed to canonicalize XML file \" %s \" (ret=%d) \n " , xml_filename , ret ) ;
ret = - 1 ;
}
2008-08-25 18:53:31 +04:00
2005-07-07 00:41:33 +04:00
/*
* Cleanup
2008-08-25 18:53:31 +04:00
*/
2005-07-07 00:41:33 +04:00
if ( result ! = NULL ) xmlFree ( result ) ;
if ( xpath ! = NULL ) xmlXPathFreeObject ( xpath ) ;
if ( inclusive_namespaces ! = NULL ) xmlFree ( inclusive_namespaces ) ;
if ( nslist ! = NULL ) free ( ( char * ) nslist ) ;
2008-08-25 18:53:31 +04:00
xmlFreeDoc ( doc ) ;
2005-07-07 00:41:33 +04:00
return ( ret ) ;
}
static int
2009-07-09 12:26:22 +04:00
c14nCommonTest ( const char * filename , int with_comments , int mode ,
2005-07-07 00:41:33 +04:00
const char * subdir ) {
char buf [ 500 ] ;
char prefix [ 500 ] ;
const char * base ;
int len ;
char * result = NULL ;
char * xpath = NULL ;
char * ns = NULL ;
int ret = 0 ;
base = baseFilename ( filename ) ;
len = strlen ( base ) ;
len - = 4 ;
memcpy ( prefix , base , len ) ;
prefix [ len ] = 0 ;
2019-01-01 18:30:38 +03:00
if ( snprintf ( buf , 499 , " result/c14n/%s/%s " , subdir , prefix ) > = 499 )
buf [ 499 ] = 0 ;
2016-05-22 04:58:30 +03:00
if ( ! checkTestFile ( buf ) & & ! update_results ) {
2005-07-07 00:41:33 +04:00
fprintf ( stderr , " Missing result file %s " , buf ) ;
return ( - 1 ) ;
}
result = strdup ( buf ) ;
2019-01-01 18:30:38 +03:00
if ( snprintf ( buf , 499 , " test/c14n/%s/%s.xpath " , subdir , prefix ) > = 499 )
buf [ 499 ] = 0 ;
2005-07-07 00:41:33 +04:00
if ( checkTestFile ( buf ) ) {
xpath = strdup ( buf ) ;
}
2019-01-01 18:30:38 +03:00
if ( snprintf ( buf , 499 , " test/c14n/%s/%s.ns " , subdir , prefix ) > = 499 )
buf [ 499 ] = 0 ;
2005-07-07 00:41:33 +04:00
if ( checkTestFile ( buf ) ) {
ns = strdup ( buf ) ;
}
nb_tests + + ;
2009-07-09 12:26:22 +04:00
if ( c14nRunTest ( filename , with_comments , mode ,
2005-07-07 00:41:33 +04:00
xpath , ns , result ) < 0 )
ret = 1 ;
if ( result ! = NULL ) free ( result ) ;
if ( xpath ! = NULL ) free ( xpath ) ;
if ( ns ! = NULL ) free ( ns ) ;
return ( ret ) ;
}
static int
c14nWithCommentTest ( const char * filename ,
const char * resul ATTRIBUTE_UNUSED ,
const char * err ATTRIBUTE_UNUSED ,
int options ATTRIBUTE_UNUSED ) {
2009-07-09 12:26:22 +04:00
return ( c14nCommonTest ( filename , 1 , XML_C14N_1_0 , " with-comments " ) ) ;
2005-07-07 00:41:33 +04:00
}
static int
c14nWithoutCommentTest ( const char * filename ,
const char * resul ATTRIBUTE_UNUSED ,
const char * err ATTRIBUTE_UNUSED ,
int options ATTRIBUTE_UNUSED ) {
2009-07-09 12:26:22 +04:00
return ( c14nCommonTest ( filename , 0 , XML_C14N_1_0 , " without-comments " ) ) ;
2005-07-07 00:41:33 +04:00
}
static int
c14nExcWithoutCommentTest ( const char * filename ,
const char * resul ATTRIBUTE_UNUSED ,
const char * err ATTRIBUTE_UNUSED ,
int options ATTRIBUTE_UNUSED ) {
2009-07-09 12:26:22 +04:00
return ( c14nCommonTest ( filename , 0 , XML_C14N_EXCLUSIVE_1_0 , " exc-without-comments " ) ) ;
}
static int
c14n11WithoutCommentTest ( const char * filename ,
const char * resul ATTRIBUTE_UNUSED ,
const char * err ATTRIBUTE_UNUSED ,
int options ATTRIBUTE_UNUSED ) {
return ( c14nCommonTest ( filename , 0 , XML_C14N_1_1 , " 1-1-without-comments " ) ) ;
2005-07-07 00:41:33 +04:00
}
# endif
2017-06-16 22:27:47 +03:00
# if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
2005-07-07 00:41:33 +04:00
/************************************************************************
* *
* Catalog and threads test *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* mostly a cut and paste from testThreads . c
*/
# define MAX_ARGC 20
2017-10-21 15:43:00 +03:00
typedef struct {
const char * filename ;
int okay ;
} xmlThreadParams ;
2005-07-07 00:41:33 +04:00
static const char * catalog = " test/threads/complex.xml " ;
2017-10-21 15:43:00 +03:00
static xmlThreadParams threadParams [ ] = {
{ " test/threads/abc.xml " , 0 } ,
{ " test/threads/acb.xml " , 0 } ,
{ " test/threads/bac.xml " , 0 } ,
{ " test/threads/bca.xml " , 0 } ,
{ " test/threads/cab.xml " , 0 } ,
{ " test/threads/cba.xml " , 0 } ,
{ " test/threads/invalid.xml " , 0 }
2005-07-07 00:41:33 +04:00
} ;
2017-10-21 15:43:00 +03:00
static const unsigned int num_threads = sizeof ( threadParams ) /
sizeof ( threadParams [ 0 ] ) ;
2005-07-07 00:41:33 +04:00
# ifndef xmlDoValidityCheckingDefaultValue
# error xmlDoValidityCheckingDefaultValue is not a macro
# endif
# ifndef xmlGenericErrorContext
# error xmlGenericErrorContext is not a macro
# endif
static void *
thread_specific_data ( void * private_data )
{
xmlDocPtr myDoc ;
2017-10-21 15:43:00 +03:00
xmlThreadParams * params = ( xmlThreadParams * ) private_data ;
const char * filename = params - > filename ;
2005-07-07 00:41:33 +04:00
int okay = 1 ;
if ( ! strcmp ( filename , " test/threads/invalid.xml " ) ) {
xmlDoValidityCheckingDefaultValue = 0 ;
xmlGenericErrorContext = stdout ;
} else {
xmlDoValidityCheckingDefaultValue = 1 ;
xmlGenericErrorContext = stderr ;
}
2017-06-16 22:27:47 +03:00
# ifdef LIBXML_SAX1_ENABLED
2005-07-07 00:41:33 +04:00
myDoc = xmlParseFile ( filename ) ;
2017-06-16 22:27:47 +03:00
# else
myDoc = xmlReadFile ( filename , NULL , XML_WITH_CATALOG ) ;
# endif
2005-07-07 00:41:33 +04:00
if ( myDoc ) {
xmlFreeDoc ( myDoc ) ;
} else {
printf ( " parse failed \n " ) ;
okay = 0 ;
}
if ( ! strcmp ( filename , " test/threads/invalid.xml " ) ) {
if ( xmlDoValidityCheckingDefaultValue ! = 0 ) {
printf ( " ValidityCheckingDefaultValue override failed \n " ) ;
okay = 0 ;
}
if ( xmlGenericErrorContext ! = stdout ) {
printf ( " xmlGenericErrorContext override failed \n " ) ;
okay = 0 ;
}
} else {
if ( xmlDoValidityCheckingDefaultValue ! = 1 ) {
printf ( " ValidityCheckingDefaultValue override failed \n " ) ;
okay = 0 ;
}
if ( xmlGenericErrorContext ! = stderr ) {
printf ( " xmlGenericErrorContext override failed \n " ) ;
okay = 0 ;
}
}
2017-10-21 15:43:00 +03:00
params - > okay = okay ;
return ( NULL ) ;
2005-07-07 00:41:33 +04:00
}
2017-10-09 01:20:01 +03:00
# if defined(_WIN32) && !defined(__CYGWIN__)
2005-07-07 00:41:33 +04:00
# include <windows.h>
# include <string.h>
# define TEST_REPEAT_COUNT 500
static HANDLE tid [ MAX_ARGC ] ;
static DWORD WINAPI
win32_thread_specific_data ( void * private_data )
{
2017-10-21 15:43:00 +03:00
thread_specific_data ( private_data ) ;
return ( 0 ) ;
2005-07-07 00:41:33 +04:00
}
static int
testThread ( void )
{
unsigned int i , repeat ;
BOOL ret ;
int res = 0 ;
xmlInitParser ( ) ;
for ( repeat = 0 ; repeat < TEST_REPEAT_COUNT ; repeat + + ) {
xmlLoadCatalog ( catalog ) ;
nb_tests + + ;
for ( i = 0 ; i < num_threads ; i + + ) {
tid [ i ] = ( HANDLE ) - 1 ;
}
for ( i = 0 ; i < num_threads ; i + + ) {
DWORD useless ;
tid [ i ] = CreateThread ( NULL , 0 ,
2008-08-25 18:53:31 +04:00
win32_thread_specific_data ,
2017-10-21 15:43:00 +03:00
( void * ) & threadParams [ i ] , 0 ,
2005-07-07 00:41:33 +04:00
& useless ) ;
if ( tid [ i ] = = NULL ) {
fprintf ( stderr , " CreateThread failed \n " ) ;
return ( 1 ) ;
}
}
if ( WaitForMultipleObjects ( num_threads , tid , TRUE , INFINITE ) = =
WAIT_FAILED ) {
fprintf ( stderr , " WaitForMultipleObjects failed \n " ) ;
return ( 1 ) ;
}
for ( i = 0 ; i < num_threads ; i + + ) {
2017-10-21 15:43:00 +03:00
DWORD exitCode ;
ret = GetExitCodeThread ( tid [ i ] , & exitCode ) ;
2005-07-07 00:41:33 +04:00
if ( ret = = 0 ) {
fprintf ( stderr , " GetExitCodeThread failed \n " ) ;
return ( 1 ) ;
}
CloseHandle ( tid [ i ] ) ;
}
xmlCatalogCleanup ( ) ;
for ( i = 0 ; i < num_threads ; i + + ) {
2017-10-21 15:43:00 +03:00
if ( threadParams [ i ] . okay = = 0 ) {
2005-07-07 00:41:33 +04:00
fprintf ( stderr , " Thread %d handling %s failed \n " ,
2017-10-21 15:43:00 +03:00
i , threadParams [ i ] . filename ) ;
2005-07-07 00:41:33 +04:00
res = 1 ;
}
}
}
return ( res ) ;
}
# elif defined __BEOS__
# include <OS.h>
static thread_id tid [ MAX_ARGC ] ;
static int
testThread ( void )
{
unsigned int i , repeat ;
status_t ret ;
int res = 0 ;
xmlInitParser ( ) ;
for ( repeat = 0 ; repeat < 500 ; repeat + + ) {
xmlLoadCatalog ( catalog ) ;
for ( i = 0 ; i < num_threads ; i + + ) {
tid [ i ] = ( thread_id ) - 1 ;
}
for ( i = 0 ; i < num_threads ; i + + ) {
tid [ i ] =
spawn_thread ( thread_specific_data , " xmlTestThread " ,
2017-10-21 15:43:00 +03:00
B_NORMAL_PRIORITY , ( void * ) & threadParams [ i ] ) ;
2005-07-07 00:41:33 +04:00
if ( tid [ i ] < B_OK ) {
fprintf ( stderr , " beos_thread_create failed \n " ) ;
return ( 1 ) ;
}
printf ( " beos_thread_create %d -> %d \n " , i , tid [ i ] ) ;
}
for ( i = 0 ; i < num_threads ; i + + ) {
2017-10-21 15:43:00 +03:00
void * result ;
ret = wait_for_thread ( tid [ i ] , & result ) ;
2005-07-07 00:41:33 +04:00
printf ( " beos_thread_wait %d -> %d \n " , i , ret ) ;
if ( ret ! = B_OK ) {
fprintf ( stderr , " beos_thread_wait failed \n " ) ;
return ( 1 ) ;
}
}
xmlCatalogCleanup ( ) ;
ret = B_OK ;
for ( i = 0 ; i < num_threads ; i + + )
2017-10-21 15:43:00 +03:00
if ( threadParams [ i ] . okay = = 0 ) {
printf ( " Thread %d handling %s failed \n " , i ,
threadParams [ i ] . filename ) ;
2005-07-07 00:41:33 +04:00
ret = B_ERROR ;
}
}
if ( ret ! = B_OK )
return ( 1 ) ;
return ( 0 ) ;
}
2012-08-07 06:14:56 +04:00
# elif defined HAVE_PTHREAD_H
# include <pthread.h>
static pthread_t tid [ MAX_ARGC ] ;
static int
testThread ( void )
{
unsigned int i , repeat ;
int ret ;
int res = 0 ;
xmlInitParser ( ) ;
for ( repeat = 0 ; repeat < 500 ; repeat + + ) {
xmlLoadCatalog ( catalog ) ;
nb_tests + + ;
for ( i = 0 ; i < num_threads ; i + + ) {
tid [ i ] = ( pthread_t ) - 1 ;
}
for ( i = 0 ; i < num_threads ; i + + ) {
ret = pthread_create ( & tid [ i ] , 0 , thread_specific_data ,
2017-10-21 15:43:00 +03:00
( void * ) & threadParams [ i ] ) ;
2012-08-07 06:14:56 +04:00
if ( ret ! = 0 ) {
fprintf ( stderr , " pthread_create failed \n " ) ;
return ( 1 ) ;
}
}
for ( i = 0 ; i < num_threads ; i + + ) {
2017-10-21 15:43:00 +03:00
void * result ;
ret = pthread_join ( tid [ i ] , & result ) ;
2012-08-07 06:14:56 +04:00
if ( ret ! = 0 ) {
fprintf ( stderr , " pthread_join failed \n " ) ;
return ( 1 ) ;
}
}
xmlCatalogCleanup ( ) ;
for ( i = 0 ; i < num_threads ; i + + )
2017-10-21 15:43:00 +03:00
if ( threadParams [ i ] . okay = = 0 ) {
2012-08-07 06:14:56 +04:00
fprintf ( stderr , " Thread %d handling %s failed \n " ,
2017-10-21 15:43:00 +03:00
i , threadParams [ i ] . filename ) ;
2012-08-07 06:14:56 +04:00
res = 1 ;
}
}
return ( res ) ;
}
2005-07-07 00:41:33 +04:00
# else
static int
testThread ( void )
{
fprintf ( stderr ,
" Specific platform thread support not detected \n " ) ;
return ( - 1 ) ;
}
# endif
2008-08-25 18:53:31 +04:00
static int
2005-07-07 00:41:33 +04:00
threadsTest ( const char * filename ATTRIBUTE_UNUSED ,
const char * resul ATTRIBUTE_UNUSED ,
const char * err ATTRIBUTE_UNUSED ,
int options ATTRIBUTE_UNUSED ) {
return ( testThread ( ) ) ;
}
# endif
/************************************************************************
* *
* Tests Descriptions *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static
testDesc testDescriptions [ ] = {
{ " XML regression tests " ,
oldParseTest , " ./test/* " , " result/ " , " " , NULL ,
0 } ,
{ " XML regression tests on memory " ,
memParseTest , " ./test/* " , " result/ " , " " , NULL ,
0 } ,
{ " XML entity subst regression tests " ,
noentParseTest , " ./test/* " , " result/noent/ " , " " , NULL ,
XML_PARSE_NOENT } ,
{ " XML Namespaces regression tests " ,
errParseTest , " ./test/namespaces/* " , " result/namespaces/ " , " " , " .err " ,
0 } ,
{ " Error cases regression tests " ,
errParseTest , " ./test/errors/*.xml " , " result/errors/ " , " " , " .err " ,
0 } ,
2020-02-11 15:13:52 +03:00
{ " Error cases regression tests with entity substitution " ,
errParseTest , " ./test/errors/*.xml " , " result/errors/ " , NULL , " .ent " ,
XML_PARSE_NOENT } ,
2017-06-05 16:37:17 +03:00
{ " Error cases regression tests (old 1.0) " ,
errParseTest , " ./test/errors10/*.xml " , " result/errors10/ " , " " , " .err " ,
XML_PARSE_OLD10 } ,
2005-07-07 00:41:33 +04:00
# ifdef LIBXML_READER_ENABLED
{ " Error cases stream regression tests " ,
streamParseTest , " ./test/errors/*.xml " , " result/errors/ " , NULL , " .str " ,
0 } ,
{ " Reader regression tests " ,
streamParseTest , " ./test/* " , " result/ " , " .rdr " , NULL ,
0 } ,
{ " Reader entities substitution regression tests " ,
streamParseTest , " ./test/* " , " result/ " , " .rde " , NULL ,
XML_PARSE_NOENT } ,
{ " Reader on memory regression tests " ,
streamMemParseTest , " ./test/* " , " result/ " , " .rdr " , NULL ,
0 } ,
{ " Walker regression tests " ,
walkerParseTest , " ./test/* " , " result/ " , " .rdr " , NULL ,
0 } ,
# endif
# ifdef LIBXML_SAX1_ENABLED
{ " SAX1 callbacks regression tests " ,
saxParseTest , " ./test/* " , " result/ " , " .sax " , NULL ,
XML_PARSE_SAX1 } ,
2017-06-16 22:38:57 +03:00
# endif
2005-07-07 00:41:33 +04:00
{ " SAX2 callbacks regression tests " ,
saxParseTest , " ./test/* " , " result/ " , " .sax2 " , NULL ,
0 } ,
2017-06-16 22:38:57 +03:00
{ " SAX2 callbacks regression tests with entity substitution " ,
saxParseTest , " ./test/* " , " result/noent/ " , " .sax2 " , NULL ,
XML_PARSE_NOENT } ,
2005-07-07 00:41:33 +04:00
# ifdef LIBXML_PUSH_ENABLED
{ " XML push regression tests " ,
pushParseTest , " ./test/* " , " result/ " , " " , NULL ,
0 } ,
# endif
# ifdef LIBXML_HTML_ENABLED
{ " HTML regression tests " ,
errParseTest , " ./test/HTML/* " , " result/HTML/ " , " " , " .err " ,
XML_PARSE_HTML } ,
# ifdef LIBXML_PUSH_ENABLED
{ " Push HTML regression tests " ,
pushParseTest , " ./test/HTML/* " , " result/HTML/ " , " " , " .err " ,
XML_PARSE_HTML } ,
# endif
{ " HTML SAX regression tests " ,
saxParseTest , " ./test/HTML/* " , " result/HTML/ " , " .sax " , NULL ,
XML_PARSE_HTML } ,
# endif
# ifdef LIBXML_VALID_ENABLED
{ " Valid documents regression tests " ,
errParseTest , " ./test/VCM/* " , NULL , NULL , NULL ,
XML_PARSE_DTDVALID } ,
{ " Validity checking regression tests " ,
errParseTest , " ./test/VC/* " , " result/VC/ " , NULL , " " ,
XML_PARSE_DTDVALID } ,
2012-10-25 11:39:39 +04:00
# ifdef LIBXML_READER_ENABLED
{ " Streaming validity checking regression tests " ,
streamParseTest , " ./test/valid/*.xml " , " result/valid/ " , NULL , " .err.rdr " ,
XML_PARSE_DTDVALID } ,
{ " Streaming validity error checking regression tests " ,
streamParseTest , " ./test/VC/* " , " result/VC/ " , NULL , " .rdr " ,
XML_PARSE_DTDVALID } ,
# endif
2005-07-07 00:41:33 +04:00
{ " General documents valid regression tests " ,
errParseTest , " ./test/valid/* " , " result/valid/ " , " " , " .err " ,
XML_PARSE_DTDVALID } ,
# endif
# ifdef LIBXML_XINCLUDE_ENABLED
{ " XInclude regression tests " ,
errParseTest , " ./test/XInclude/docs/* " , " result/XInclude/ " , " " , NULL ,
/* Ignore errors at this point ".err", */
XML_PARSE_XINCLUDE } ,
2008-05-12 16:58:46 +04:00
# ifdef LIBXML_READER_ENABLED
2005-07-07 00:41:33 +04:00
{ " XInclude xmlReader regression tests " ,
streamParseTest , " ./test/XInclude/docs/* " , " result/XInclude/ " , " .rdr " ,
/* Ignore errors at this point ".err", */
NULL , XML_PARSE_XINCLUDE } ,
2008-05-12 16:58:46 +04:00
# endif
2005-07-07 00:41:33 +04:00
{ " XInclude regression tests stripping include nodes " ,
errParseTest , " ./test/XInclude/docs/* " , " result/XInclude/ " , " " , NULL ,
/* Ignore errors at this point ".err", */
XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE } ,
2008-05-12 16:58:46 +04:00
# ifdef LIBXML_READER_ENABLED
2005-07-07 00:41:33 +04:00
{ " XInclude xmlReader regression tests stripping include nodes " ,
streamParseTest , " ./test/XInclude/docs/* " , " result/XInclude/ " , " .rdr " ,
/* Ignore errors at this point ".err", */
NULL , XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE } ,
# endif
2008-05-12 16:58:46 +04:00
# endif
2005-07-07 00:41:33 +04:00
# ifdef LIBXML_XPATH_ENABLED
# ifdef LIBXML_DEBUG_ENABLED
{ " XPath expressions regression tests " ,
xpathExprTest , " ./test/XPath/expr/* " , " result/XPath/expr/ " , " " , NULL ,
0 } ,
{ " XPath document queries regression tests " ,
xpathDocTest , " ./test/XPath/docs/* " , NULL , NULL , NULL ,
0 } ,
# ifdef LIBXML_XPTR_ENABLED
{ " XPointer document queries regression tests " ,
xptrDocTest , " ./test/XPath/docs/* " , NULL , NULL , NULL ,
0 } ,
# endif
{ " xml:id regression tests " ,
xmlidDocTest , " ./test/xmlid/* " , " result/xmlid/ " , " " , " .err " ,
0 } ,
# endif
# endif
{ " URI parsing tests " ,
uriParseTest , " ./test/URI/*.uri " , " result/URI/ " , " " , NULL ,
0 } ,
{ " URI base composition tests " ,
uriBaseTest , " ./test/URI/*.data " , " result/URI/ " , " " , NULL ,
0 } ,
2005-08-07 14:46:19 +04:00
{ " Path URI conversion tests " ,
uriPathTest , NULL , NULL , NULL , NULL ,
0 } ,
2005-07-07 00:41:33 +04:00
# ifdef LIBXML_SCHEMAS_ENABLED
{ " Schemas regression tests " ,
schemasTest , " ./test/schemas/*_*.xsd " , NULL , NULL , NULL ,
0 } ,
{ " Relax-NG regression tests " ,
rngTest , " ./test/relaxng/*.rng " , NULL , NULL , NULL ,
XML_PARSE_DTDATTR | XML_PARSE_NOENT } ,
# ifdef LIBXML_READER_ENABLED
{ " Relax-NG streaming regression tests " ,
rngStreamTest , " ./test/relaxng/*.rng " , NULL , NULL , NULL ,
XML_PARSE_DTDATTR | XML_PARSE_NOENT } ,
# endif
# endif
# ifdef LIBXML_PATTERN_ENABLED
# ifdef LIBXML_READER_ENABLED
{ " Pattern regression tests " ,
patternTest , " ./test/pattern/*.pat " , " result/pattern/ " , NULL , NULL ,
0 } ,
# endif
# endif
# ifdef LIBXML_C14N_ENABLED
{ " C14N with comments regression tests " ,
c14nWithCommentTest , " ./test/c14n/with-comments/*.xml " , NULL , NULL , NULL ,
0 } ,
{ " C14N without comments regression tests " ,
c14nWithoutCommentTest , " ./test/c14n/without-comments/*.xml " , NULL , NULL , NULL ,
0 } ,
{ " C14N exclusive without comments regression tests " ,
c14nExcWithoutCommentTest , " ./test/c14n/exc-without-comments/*.xml " , NULL , NULL , NULL ,
0 } ,
2009-07-09 12:26:22 +04:00
{ " C14N 1.1 without comments regression tests " ,
c14n11WithoutCommentTest , " ./test/c14n/1-1-without-comments/*.xml " , NULL , NULL , NULL ,
0 } ,
2005-07-07 00:41:33 +04:00
# endif
2017-06-16 22:27:47 +03:00
# if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
2005-07-07 00:41:33 +04:00
{ " Catalog and Threads regression tests " ,
threadsTest , NULL , NULL , NULL , NULL ,
0 } ,
# endif
{ NULL , NULL , NULL , NULL , NULL , NULL , 0 }
} ;
/************************************************************************
* *
* The main code driving the tests *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int
launchTests ( testDescPtr tst ) {
int res = 0 , err = 0 ;
size_t i ;
char * result ;
char * error ;
int mem ;
2018-09-04 18:13:29 +03:00
xmlCharEncodingHandlerPtr ebcdicHandler , eucJpHandler ;
2017-10-31 19:17:16 +03:00
ebcdicHandler = xmlGetCharEncodingHandler ( XML_CHAR_ENCODING_EBCDIC ) ;
2018-09-04 18:13:29 +03:00
eucJpHandler = xmlGetCharEncodingHandler ( XML_CHAR_ENCODING_EUC_JP ) ;
2005-07-07 00:41:33 +04:00
if ( tst = = NULL ) return ( - 1 ) ;
if ( tst - > in ! = NULL ) {
glob_t globbuf ;
globbuf . gl_offs = 0 ;
glob ( tst - > in , GLOB_DOOFFS , NULL , & globbuf ) ;
for ( i = 0 ; i < globbuf . gl_pathc ; i + + ) {
if ( ! checkTestFile ( globbuf . gl_pathv [ i ] ) )
continue ;
2018-09-04 18:13:29 +03:00
if ( ( ( ebcdicHandler = = NULL ) & &
( strstr ( globbuf . gl_pathv [ i ] , " ebcdic " ) ! = NULL ) ) | |
( ( eucJpHandler = = NULL ) & &
( strstr ( globbuf . gl_pathv [ i ] , " icu_parse_test " ) ! = NULL ) ) )
2017-10-31 19:17:16 +03:00
continue ;
2005-07-07 00:41:33 +04:00
if ( tst - > suffix ! = NULL ) {
result = resultFilename ( globbuf . gl_pathv [ i ] , tst - > out ,
tst - > suffix ) ;
if ( result = = NULL ) {
fprintf ( stderr , " Out of memory ! \n " ) ;
fatalError ( ) ;
}
} else {
result = NULL ;
}
if ( tst - > err ! = NULL ) {
error = resultFilename ( globbuf . gl_pathv [ i ] , tst - > out ,
tst - > err ) ;
if ( error = = NULL ) {
fprintf ( stderr , " Out of memory ! \n " ) ;
fatalError ( ) ;
}
} else {
error = NULL ;
}
2016-05-22 04:58:30 +03:00
if ( ( result ) & & ( ! checkTestFile ( result ) ) & & ! update_results ) {
2005-07-07 00:41:33 +04:00
fprintf ( stderr , " Missing result file %s \n " , result ) ;
2016-05-22 04:58:30 +03:00
} else if ( ( error ) & & ( ! checkTestFile ( error ) ) & & ! update_results ) {
2005-07-07 00:41:33 +04:00
fprintf ( stderr , " Missing error file %s \n " , error ) ;
} else {
mem = xmlMemUsed ( ) ;
extraMemoryFromResolver = 0 ;
testErrorsSize = 0 ;
testErrors [ 0 ] = 0 ;
res = tst - > func ( globbuf . gl_pathv [ i ] , result , error ,
2005-08-25 17:19:21 +04:00
tst - > options | XML_PARSE_COMPACT ) ;
2005-07-07 00:41:33 +04:00
xmlResetLastError ( ) ;
if ( res ! = 0 ) {
fprintf ( stderr , " File %s generated an error \n " ,
globbuf . gl_pathv [ i ] ) ;
nb_errors + + ;
err + + ;
}
else if ( xmlMemUsed ( ) ! = mem ) {
if ( ( xmlMemUsed ( ) ! = mem ) & &
( extraMemoryFromResolver = = 0 ) ) {
fprintf ( stderr , " File %s leaked %d bytes \n " ,
globbuf . gl_pathv [ i ] , xmlMemUsed ( ) - mem ) ;
nb_leaks + + ;
err + + ;
}
}
testErrorsSize = 0 ;
}
if ( result )
free ( result ) ;
if ( error )
free ( error ) ;
}
globfree ( & globbuf ) ;
} else {
testErrorsSize = 0 ;
testErrors [ 0 ] = 0 ;
extraMemoryFromResolver = 0 ;
res = tst - > func ( NULL , NULL , NULL , tst - > options ) ;
if ( res ! = 0 ) {
nb_errors + + ;
err + + ;
}
}
2017-10-31 19:17:16 +03:00
xmlCharEncCloseFunc ( ebcdicHandler ) ;
2018-09-04 18:13:29 +03:00
xmlCharEncCloseFunc ( eucJpHandler ) ;
2017-10-31 19:17:16 +03:00
2005-07-07 00:41:33 +04:00
return ( err ) ;
}
2005-07-30 17:18:24 +04:00
static int verbose = 0 ;
2005-08-07 14:46:19 +04:00
static int tests_quiet = 0 ;
2005-07-30 17:18:24 +04:00
static int
runtest ( 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 ;
2005-08-07 14:46:19 +04:00
if ( ( tests_quiet = = 0 ) & & ( testDescriptions [ i ] . desc ! = NULL ) )
2005-07-30 17:18:24 +04:00
printf ( " ## %s \n " , testDescriptions [ i ] . desc ) ;
res = launchTests ( & testDescriptions [ 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 ) ;
}
2005-07-07 00:41:33 +04:00
int
main ( int argc ATTRIBUTE_UNUSED , char * * argv ATTRIBUTE_UNUSED ) {
2005-07-30 17:18:24 +04:00
int i , a , ret = 0 ;
int subset = 0 ;
2005-07-07 00:41:33 +04:00
2017-10-09 03:05:41 +03:00
# if defined(_WIN32) && !defined(__CYGWIN__)
setvbuf ( stdout , NULL , _IONBF , 0 ) ;
setvbuf ( stderr , NULL , _IONBF , 0 ) ;
# endif
2019-10-14 17:48:32 +03:00
# if defined(_MSC_VER) && _MSC_VER >= 1400 && _MSC_VER < 1900
_set_output_format ( _TWO_DIGIT_EXPONENT ) ;
# endif
2005-07-07 00:41:33 +04:00
initializeLibxml2 ( ) ;
2005-07-30 17:18:24 +04:00
for ( a = 1 ; a < argc ; a + + ) {
if ( ! strcmp ( argv [ a ] , " -v " ) )
verbose = 1 ;
2016-05-22 04:58:30 +03:00
else if ( ! strcmp ( argv [ a ] , " -u " ) )
update_results = 1 ;
2005-08-07 14:46:19 +04:00
else if ( ! strcmp ( argv [ a ] , " -quiet " ) )
tests_quiet = 1 ;
2020-06-04 12:58:04 +03:00
else if ( ! strcmp ( argv [ a ] , " --out " ) )
temp_directory = argv [ + + a ] ;
2005-07-30 17:18:24 +04:00
else {
for ( i = 0 ; testDescriptions [ i ] . func ! = NULL ; i + + ) {
if ( strstr ( testDescriptions [ i ] . desc , argv [ a ] ) ) {
ret + = runtest ( i ) ;
subset + + ;
}
}
}
}
if ( subset = = 0 ) {
for ( i = 0 ; testDescriptions [ i ] . func ! = NULL ; i + + ) {
ret + = runtest ( i ) ;
2005-07-07 00:41:33 +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 ) ;
}
# else /* ! LIBXML_OUTPUT_ENABLED */
int
main ( int argc ATTRIBUTE_UNUSED , char * * argv ATTRIBUTE_UNUSED ) {
fprintf ( stderr , " runtest requires output to be enabled in libxml2 \n " ) ;
return ( 1 ) ;
}
# endif