2008-07-29 20:12:31 +04:00
/*
2019-07-13 05:47:25 +03:00
* runxmlconf . c : C program to run XML W3C conformance testsuites
2008-07-29 20:12:31 +04:00
*
* See Copyright for the status of this software .
*
* daniel @ veillard . com
*/
2024-06-15 20:13:08 +03:00
# include "libxml.h"
2008-07-29 20:12:31 +04:00
# include <stdio.h>
2023-09-21 01:44:50 +03:00
# include <libxml/xmlversion.h>
2008-07-29 20:12:31 +04:00
2023-09-21 02:29:40 +03:00
# if defined(LIBXML_XPATH_ENABLED) && defined(LIBXML_VALID_ENABLED)
2008-09-25 19:36:43 +04:00
2008-07-29 20:12:31 +04:00
# include <string.h>
# include <sys/stat.h>
2024-06-11 12:34:48 +03:00
# include <libxml/catalog.h>
2008-07-29 20:12:31 +04:00
# include <libxml/parser.h>
# include <libxml/parserInternals.h>
# include <libxml/tree.h>
# include <libxml/uri.h>
# include <libxml/xmlreader.h>
# include <libxml/xpath.h>
# include <libxml/xpathInternals.h>
2008-07-29 20:44:59 +04:00
# define LOGFILE "runxmlconf.log"
2008-07-29 20:12:31 +04:00
static FILE * logfile = NULL ;
static int verbose = 0 ;
2008-09-01 17:08:57 +04:00
# define NB_EXPECTED_ERRORS 15
2008-07-29 20:12:31 +04:00
2008-07-31 12:20:02 +04:00
const char * skipped_tests [ ] = {
/* http://lists.w3.org/Archives/Public/public-xml-testsuite/2008Jul/0000.html */
" rmt-ns10-035 " ,
NULL
} ;
2008-07-29 20:12:31 +04:00
/************************************************************************
* *
* File name and path utilities *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int checkTestFile ( const char * filename ) {
struct stat buf ;
if ( stat ( filename , & buf ) = = - 1 )
return ( 0 ) ;
2022-03-01 00:42:10 +03:00
# if defined(_WIN32)
2008-07-29 20:12:31 +04:00
if ( ! ( buf . st_mode & _S_IFREG ) )
return ( 0 ) ;
# else
if ( ! S_ISREG ( buf . st_mode ) )
return ( 0 ) ;
# endif
return ( 1 ) ;
}
static xmlChar * composeDir ( const xmlChar * dir , const xmlChar * path ) {
char buf [ 500 ] ;
if ( dir = = NULL ) return ( xmlStrdup ( path ) ) ;
if ( path = = NULL ) return ( NULL ) ;
snprintf ( buf , 500 , " %s/%s " , ( const char * ) dir , ( const char * ) path ) ;
return ( xmlStrdup ( ( const xmlChar * ) buf ) ) ;
}
/************************************************************************
* *
* Libxml2 specific routines *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int nb_skipped = 0 ;
static int nb_tests = 0 ;
static int nb_errors = 0 ;
static int nb_leaks = 0 ;
/*
* 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 ;
2008-07-31 23:54:59 +04:00
static int nbError = 0 ;
static int nbFatal = 0 ;
2008-07-29 20:12:31 +04:00
static void test_log ( const char * msg , . . . ) {
va_list args ;
if ( logfile ! = NULL ) {
fprintf ( logfile , " \n ------------ \n " ) ;
va_start ( args , msg ) ;
vfprintf ( logfile , msg , args ) ;
va_end ( args ) ;
fprintf ( logfile , " %s " , testErrors ) ;
testErrorsSize = 0 ; testErrors [ 0 ] = 0 ;
}
if ( verbose ) {
va_start ( args , msg ) ;
vfprintf ( stderr , msg , args ) ;
va_end ( args ) ;
}
}
static void
2023-10-24 16:02:36 +03:00
testErrorHandler ( void * userData ATTRIBUTE_UNUSED , const xmlError * error ) {
2008-07-29 20:12:31 +04:00
int res ;
if ( testErrorsSize > = 32768 )
return ;
2008-07-31 23:54:59 +04:00
res = snprintf ( & testErrors [ testErrorsSize ] ,
2008-07-29 20:12:31 +04:00
32768 - testErrorsSize ,
2008-07-31 23:54:59 +04:00
" %s:%d: %s \n " , ( error - > file ? error - > file : " entity " ) ,
error - > line , error - > message ) ;
if ( error - > level = = XML_ERR_FATAL )
nbFatal + + ;
else if ( error - > level = = XML_ERR_ERROR )
nbError + + ;
2008-07-29 20:12:31 +04:00
if ( testErrorsSize + res > = 32768 ) {
/* buffer is full */
testErrorsSize = 32768 ;
testErrors [ testErrorsSize ] = 0 ;
} else {
testErrorsSize + = res ;
}
testErrors [ testErrorsSize ] = 0 ;
}
static xmlXPathContextPtr ctxtXPath ;
static void
initializeLibxml2 ( void ) {
xmlMemSetup ( xmlMemFree , xmlMemMalloc , xmlMemRealloc , xmlMemoryStrdup ) ;
xmlInitParser ( ) ;
2024-06-11 12:34:48 +03:00
# ifdef LIBXML_CATALOG_ENABLED
xmlInitializeCatalog ( ) ;
xmlCatalogSetDefaults ( XML_CATA_ALLOW_NONE ) ;
# endif
2008-07-29 20:12:31 +04:00
ctxtXPath = xmlXPathNewContext ( NULL ) ;
/*
* Deactivate the cache if created ; otherwise we have to create / free it
* for every test , since it will confuse the memory leak detection .
* Note that normally this need not be done , since the cache is not
2019-09-30 18:04:54 +03:00
* created until set explicitly with xmlXPathContextSetCache ( ) ;
* but for test purposes it is sometimes useful to activate the
2008-07-29 20:12:31 +04:00
* cache by default for the whole library .
*/
if ( ctxtXPath - > cache ! = NULL )
xmlXPathContextSetCache ( ctxtXPath , 0 , - 1 , 0 ) ;
}
/************************************************************************
* *
* Run the xmlconf test if found *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-31 23:54:59 +04:00
static int
xmlconfTestInvalid ( const char * id , const char * filename , int options ) {
xmlDocPtr doc ;
xmlParserCtxtPtr ctxt ;
int ret = 1 ;
ctxt = xmlNewParserCtxt ( ) ;
if ( ctxt = = NULL ) {
test_log ( " test %s : %s out of memory \n " ,
id , filename ) ;
return ( 0 ) ;
}
2024-01-04 15:59:23 +03:00
xmlCtxtSetErrorHandler ( ctxt , testErrorHandler , NULL ) ;
2008-07-31 23:54:59 +04:00
doc = xmlCtxtReadFile ( ctxt , filename , NULL , options ) ;
if ( doc = = NULL ) {
test_log ( " test %s : %s invalid document turned not well-formed too \n " ,
id , filename ) ;
} else {
/* invalidity should be reported both in the context and in the document */
if ( ( ctxt - > valid ! = 0 ) | | ( doc - > properties & XML_DOC_DTDVALID ) ) {
test_log ( " test %s : %s failed to detect invalid document \n " ,
id , filename ) ;
nb_errors + + ;
ret = 0 ;
}
xmlFreeDoc ( doc ) ;
}
xmlFreeParserCtxt ( ctxt ) ;
return ( ret ) ;
}
static int
xmlconfTestValid ( const char * id , const char * filename , int options ) {
xmlDocPtr doc ;
xmlParserCtxtPtr ctxt ;
int ret = 1 ;
ctxt = xmlNewParserCtxt ( ) ;
if ( ctxt = = NULL ) {
test_log ( " test %s : %s out of memory \n " ,
id , filename ) ;
return ( 0 ) ;
}
2024-01-04 15:59:23 +03:00
xmlCtxtSetErrorHandler ( ctxt , testErrorHandler , NULL ) ;
2008-07-31 23:54:59 +04:00
doc = xmlCtxtReadFile ( ctxt , filename , NULL , options ) ;
if ( doc = = NULL ) {
test_log ( " test %s : %s failed to parse a valid document \n " ,
id , filename ) ;
nb_errors + + ;
ret = 0 ;
} else {
/* validity should be reported both in the context and in the document */
if ( ( ctxt - > valid = = 0 ) | | ( ( doc - > properties & XML_DOC_DTDVALID ) = = 0 ) ) {
test_log ( " test %s : %s failed to validate a valid document \n " ,
id , filename ) ;
nb_errors + + ;
ret = 0 ;
}
xmlFreeDoc ( doc ) ;
}
xmlFreeParserCtxt ( ctxt ) ;
return ( ret ) ;
}
2008-07-29 20:12:31 +04:00
static int
xmlconfTestNotNSWF ( const char * id , const char * filename , int options ) {
2024-01-04 15:59:23 +03:00
xmlParserCtxtPtr ctxt ;
2008-07-29 20:12:31 +04:00
xmlDocPtr doc ;
int ret = 1 ;
2024-01-04 15:59:23 +03:00
ctxt = xmlNewParserCtxt ( ) ;
xmlCtxtSetErrorHandler ( ctxt , testErrorHandler , NULL ) ;
2008-07-29 20:12:31 +04:00
/*
* In case of Namespace errors , libxml2 will still parse the document
2019-09-30 18:04:54 +03:00
* but log a Namespace error .
2008-07-29 20:12:31 +04:00
*/
2024-01-04 15:59:23 +03:00
doc = xmlCtxtReadFile ( ctxt , filename , NULL , options ) ;
2008-07-29 20:12:31 +04:00
if ( doc = = NULL ) {
test_log ( " test %s : %s failed to parse the XML \n " ,
id , filename ) ;
nb_errors + + ;
ret = 0 ;
} else {
2023-09-22 00:52:52 +03:00
const xmlError * error = xmlGetLastError ( ) ;
2023-09-20 16:49:03 +03:00
if ( ( error - > code = = XML_ERR_OK ) | |
( error - > domain ! = XML_FROM_NAMESPACE ) ) {
2008-07-29 20:12:31 +04:00
test_log ( " test %s : %s failed to detect namespace error \n " ,
id , filename ) ;
nb_errors + + ;
ret = 0 ;
}
xmlFreeDoc ( doc ) ;
}
2024-01-04 15:59:23 +03:00
xmlFreeParserCtxt ( ctxt ) ;
2008-07-29 20:12:31 +04:00
return ( ret ) ;
}
static int
xmlconfTestNotWF ( const char * id , const char * filename , int options ) {
2024-01-04 15:59:23 +03:00
xmlParserCtxtPtr ctxt ;
2008-07-29 20:12:31 +04:00
xmlDocPtr doc ;
int ret = 1 ;
2024-01-04 15:59:23 +03:00
ctxt = xmlNewParserCtxt ( ) ;
xmlCtxtSetErrorHandler ( ctxt , testErrorHandler , NULL ) ;
doc = xmlCtxtReadFile ( ctxt , filename , NULL , options ) ;
2008-07-29 20:12:31 +04:00
if ( doc ! = NULL ) {
test_log ( " test %s : %s failed to detect not well formedness \n " ,
id , filename ) ;
nb_errors + + ;
xmlFreeDoc ( doc ) ;
ret = 0 ;
}
2024-01-04 15:59:23 +03:00
xmlFreeParserCtxt ( ctxt ) ;
2008-07-29 20:12:31 +04:00
return ( ret ) ;
}
static int
xmlconfTestItem ( xmlDocPtr doc , xmlNodePtr cur ) {
int ret = - 1 ;
xmlChar * type = NULL ;
xmlChar * filename = NULL ;
xmlChar * uri = NULL ;
xmlChar * base = NULL ;
xmlChar * id = NULL ;
xmlChar * rec = NULL ;
2008-07-31 23:54:59 +04:00
xmlChar * version = NULL ;
2008-07-29 20:12:31 +04:00
xmlChar * entities = NULL ;
xmlChar * edition = NULL ;
int options = 0 ;
int nstest = 0 ;
int mem , final ;
2008-07-31 12:20:02 +04:00
int i ;
2008-07-29 20:12:31 +04:00
2008-07-31 12:20:02 +04:00
testErrorsSize = 0 ; testErrors [ 0 ] = 0 ;
2008-07-31 23:54:59 +04:00
nbError = 0 ;
nbFatal = 0 ;
2008-07-29 20:12:31 +04:00
id = xmlGetProp ( cur , BAD_CAST " ID " ) ;
if ( id = = NULL ) {
test_log ( " test missing ID, line %ld \n " , xmlGetLineNo ( cur ) ) ;
goto error ;
}
2008-07-31 12:20:02 +04:00
for ( i = 0 ; skipped_tests [ i ] ! = NULL ; i + + ) {
if ( ! strcmp ( skipped_tests [ i ] , ( char * ) id ) ) {
test_log ( " Skipping test %s from skipped list \n " , ( char * ) id ) ;
ret = 0 ;
nb_skipped + + ;
goto error ;
}
}
2008-07-29 20:12:31 +04:00
type = xmlGetProp ( cur , BAD_CAST " TYPE " ) ;
if ( type = = NULL ) {
test_log ( " test %s missing TYPE \n " , ( char * ) id ) ;
goto error ;
}
uri = xmlGetProp ( cur , BAD_CAST " URI " ) ;
if ( uri = = NULL ) {
test_log ( " test %s missing URI \n " , ( char * ) id ) ;
goto error ;
}
base = xmlNodeGetBase ( doc , cur ) ;
filename = composeDir ( base , uri ) ;
if ( ! checkTestFile ( ( char * ) filename ) ) {
test_log ( " test %s missing file %s \n " , id ,
( filename ? ( char * ) filename : " NULL " ) ) ;
goto error ;
}
2008-07-31 23:54:59 +04:00
version = xmlGetProp ( cur , BAD_CAST " VERSION " ) ;
2008-07-29 20:12:31 +04:00
entities = xmlGetProp ( cur , BAD_CAST " ENTITIES " ) ;
if ( ! xmlStrEqual ( entities , BAD_CAST " none " ) ) {
options | = XML_PARSE_DTDLOAD ;
2008-07-30 16:35:40 +04:00
options | = XML_PARSE_NOENT ;
2008-07-29 20:12:31 +04:00
}
rec = xmlGetProp ( cur , BAD_CAST " RECOMMENDATION " ) ;
if ( ( rec = = NULL ) | |
( xmlStrEqual ( rec , BAD_CAST " XML1.0 " ) ) | |
( xmlStrEqual ( rec , BAD_CAST " XML1.0-errata2e " ) ) | |
( xmlStrEqual ( rec , BAD_CAST " XML1.0-errata3e " ) ) | |
( xmlStrEqual ( rec , BAD_CAST " XML1.0-errata4e " ) ) ) {
2008-07-31 23:54:59 +04:00
if ( ( version ! = NULL ) & & ( ! xmlStrEqual ( version , BAD_CAST " 1.0 " ) ) ) {
test_log ( " Skipping test %s for %s \n " , ( char * ) id ,
( char * ) version ) ;
ret = 0 ;
nb_skipped + + ;
goto error ;
}
2008-07-29 20:12:31 +04:00
ret = 1 ;
} else if ( ( xmlStrEqual ( rec , BAD_CAST " NS1.0 " ) ) | |
( xmlStrEqual ( rec , BAD_CAST " NS1.0-errata1e " ) ) ) {
ret = 1 ;
nstest = 1 ;
} else {
test_log ( " Skipping test %s for REC %s \n " , ( char * ) id , ( char * ) rec ) ;
ret = 0 ;
nb_skipped + + ;
goto error ;
}
edition = xmlGetProp ( cur , BAD_CAST " EDITION " ) ;
if ( ( edition ! = NULL ) & & ( xmlStrchr ( edition , ' 5 ' ) = = NULL ) ) {
/* test limited to all versions before 5th */
options | = XML_PARSE_OLD10 ;
}
/*
* Reset errors and check memory usage before the test
*/
xmlResetLastError ( ) ;
testErrorsSize = 0 ; testErrors [ 0 ] = 0 ;
mem = xmlMemUsed ( ) ;
if ( xmlStrEqual ( type , BAD_CAST " not-wf " ) ) {
if ( nstest = = 0 )
xmlconfTestNotWF ( ( char * ) id , ( char * ) filename , options ) ;
2012-09-11 09:26:36 +04:00
else
2008-07-29 20:12:31 +04:00
xmlconfTestNotNSWF ( ( char * ) id , ( char * ) filename , options ) ;
} else if ( xmlStrEqual ( type , BAD_CAST " valid " ) ) {
2008-07-31 23:54:59 +04:00
options | = XML_PARSE_DTDVALID ;
xmlconfTestValid ( ( char * ) id , ( char * ) filename , options ) ;
2008-07-29 20:12:31 +04:00
} else if ( xmlStrEqual ( type , BAD_CAST " invalid " ) ) {
2008-07-31 23:54:59 +04:00
options | = XML_PARSE_DTDVALID ;
xmlconfTestInvalid ( ( char * ) id , ( char * ) filename , options ) ;
2008-07-29 20:12:31 +04:00
} else if ( xmlStrEqual ( type , BAD_CAST " error " ) ) {
2008-07-31 23:54:59 +04:00
test_log ( " Skipping error test %s \n " , ( char * ) id ) ;
ret = 0 ;
nb_skipped + + ;
goto error ;
2008-07-29 20:12:31 +04:00
} else {
test_log ( " test %s unknown TYPE value %s \n " , ( char * ) id , ( char * ) type ) ;
ret = - 1 ;
goto error ;
}
/*
* Reset errors and check memory usage after the test
*/
xmlResetLastError ( ) ;
final = xmlMemUsed ( ) ;
if ( final > mem ) {
test_log ( " test %s : %s leaked %d bytes \n " ,
id , filename , final - mem ) ;
nb_leaks + + ;
}
nb_tests + + ;
error :
if ( type ! = NULL )
xmlFree ( type ) ;
if ( entities ! = NULL )
xmlFree ( entities ) ;
if ( edition ! = NULL )
xmlFree ( edition ) ;
2008-07-31 23:54:59 +04:00
if ( version ! = NULL )
xmlFree ( version ) ;
2008-07-29 20:12:31 +04:00
if ( filename ! = NULL )
xmlFree ( filename ) ;
if ( uri ! = NULL )
xmlFree ( uri ) ;
if ( base ! = NULL )
xmlFree ( base ) ;
if ( id ! = NULL )
xmlFree ( id ) ;
if ( rec ! = NULL )
xmlFree ( rec ) ;
return ( ret ) ;
}
static int
2008-08-25 18:53:31 +04:00
xmlconfTestCases ( xmlDocPtr doc , xmlNodePtr cur , int level ) {
2008-07-29 20:12:31 +04:00
xmlChar * profile ;
int ret = 0 ;
int tests = 0 ;
2008-08-25 18:53:31 +04:00
int output = 0 ;
if ( level = = 1 ) {
profile = xmlGetProp ( cur , BAD_CAST " PROFILE " ) ;
if ( profile ! = NULL ) {
output = 1 ;
level + + ;
printf ( " Test cases: %s \n " , ( char * ) profile ) ;
xmlFree ( profile ) ;
}
2008-07-29 20:12:31 +04:00
}
cur = cur - > children ;
while ( cur ! = NULL ) {
/* look only at elements we ignore everything else */
if ( cur - > type = = XML_ELEMENT_NODE ) {
if ( xmlStrEqual ( cur - > name , BAD_CAST " TESTCASES " ) ) {
2008-08-25 18:53:31 +04:00
ret + = xmlconfTestCases ( doc , cur , level ) ;
2008-07-29 20:12:31 +04:00
} else if ( xmlStrEqual ( cur - > name , BAD_CAST " TEST " ) ) {
if ( xmlconfTestItem ( doc , cur ) > = 0 )
ret + + ;
tests + + ;
} else {
fprintf ( stderr , " Unhandled element %s \n " , ( char * ) cur - > name ) ;
}
}
cur = cur - > next ;
}
2008-08-25 18:53:31 +04:00
if ( output = = 1 ) {
if ( tests > 0 )
printf ( " Test cases: %d tests \n " , tests ) ;
}
2008-07-29 20:12:31 +04:00
return ( ret ) ;
}
static int
xmlconfTestSuite ( xmlDocPtr doc , xmlNodePtr cur ) {
xmlChar * profile ;
int ret = 0 ;
profile = xmlGetProp ( cur , BAD_CAST " PROFILE " ) ;
if ( profile ! = NULL ) {
printf ( " Test suite: %s \n " , ( char * ) profile ) ;
xmlFree ( profile ) ;
} else
printf ( " Test suite \n " ) ;
cur = cur - > children ;
while ( cur ! = NULL ) {
/* look only at elements we ignore everything else */
if ( cur - > type = = XML_ELEMENT_NODE ) {
if ( xmlStrEqual ( cur - > name , BAD_CAST " TESTCASES " ) ) {
2008-08-25 18:53:31 +04:00
ret + = xmlconfTestCases ( doc , cur , 1 ) ;
2008-07-29 20:12:31 +04:00
} else {
fprintf ( stderr , " Unhandled element %s \n " , ( char * ) cur - > name ) ;
}
}
cur = cur - > next ;
}
return ( ret ) ;
}
static void
xmlconfInfo ( void ) {
fprintf ( stderr , " you need to fetch and extract the \n " ) ;
fprintf ( stderr , " latest XML Conformance Test Suites \n " ) ;
2011-05-10 14:06:09 +04:00
fprintf ( stderr , " http://www.w3.org/XML/Test/xmlts20080827.tar.gz \n " ) ;
2020-03-08 19:19:42 +03:00
fprintf ( stderr , " see http://www.w3.org/XML/Test/ for information \n " ) ;
2008-07-29 20:12:31 +04:00
}
static int
xmlconfTest ( void ) {
const char * confxml = " xmlconf/xmlconf.xml " ;
xmlDocPtr doc ;
xmlNodePtr cur ;
int ret = 0 ;
if ( ! checkTestFile ( confxml ) ) {
fprintf ( stderr , " %s is missing \n " , confxml ) ;
xmlconfInfo ( ) ;
return ( - 1 ) ;
}
doc = xmlReadFile ( confxml , NULL , XML_PARSE_NOENT ) ;
if ( doc = = NULL ) {
fprintf ( stderr , " %s is corrupted \n " , confxml ) ;
xmlconfInfo ( ) ;
return ( - 1 ) ;
}
cur = xmlDocGetRootElement ( doc ) ;
if ( ( cur = = NULL ) | | ( ! xmlStrEqual ( cur - > name , BAD_CAST " TESTSUITE " ) ) ) {
fprintf ( stderr , " Unexpected format %s \n " , confxml ) ;
xmlconfInfo ( ) ;
ret = - 1 ;
} else {
ret = xmlconfTestSuite ( doc , cur ) ;
}
xmlFreeDoc ( doc ) ;
return ( ret ) ;
}
/************************************************************************
* *
* The driver for the tests *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int
main ( int argc ATTRIBUTE_UNUSED , char * * argv ATTRIBUTE_UNUSED ) {
int ret = 0 ;
int old_errors , old_tests , old_leaks ;
logfile = fopen ( LOGFILE , " w " ) ;
if ( logfile = = NULL ) {
fprintf ( stderr ,
" Could not open the log file, running in verbose mode \n " ) ;
verbose = 1 ;
}
initializeLibxml2 ( ) ;
if ( ( argc > = 2 ) & & ( ! strcmp ( argv [ 1 ] , " -v " ) ) )
verbose = 1 ;
old_errors = nb_errors ;
old_tests = nb_tests ;
old_leaks = nb_leaks ;
xmlconfTest ( ) ;
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 ) ;
if ( ( nb_errors = = 0 ) & & ( nb_leaks = = 0 ) ) {
ret = 0 ;
printf ( " Total %d tests, no errors \n " ,
nb_tests ) ;
} else {
2008-09-01 17:08:57 +04:00
ret = 1 ;
2008-07-29 20:12:31 +04:00
printf ( " Total %d tests, %d errors, %d leaks \n " ,
nb_tests , nb_errors , nb_leaks ) ;
2008-08-25 18:53:31 +04:00
printf ( " See %s for detailed output \n " , LOGFILE ) ;
2008-09-01 17:08:57 +04:00
if ( ( nb_leaks = = 0 ) & & ( nb_errors = = NB_EXPECTED_ERRORS ) ) {
printf ( " %d errors were expected \n " , nb_errors ) ;
ret = 0 ;
}
2008-07-29 20:12:31 +04:00
}
xmlXPathFreeContext ( ctxtXPath ) ;
xmlCleanupParser ( ) ;
if ( logfile ! = NULL )
fclose ( logfile ) ;
return ( ret ) ;
}
2008-09-25 19:36:43 +04:00
# else /* ! LIBXML_XPATH_ENABLED */
int
2022-04-21 07:03:22 +03:00
main ( int argc ATTRIBUTE_UNUSED , char * * argv ) {
2023-09-21 02:29:40 +03:00
fprintf ( stderr , " %s need XPath and validation support \n " , argv [ 0 ] ) ;
2023-09-21 01:44:50 +03:00
return ( 0 ) ;
2008-09-25 19:36:43 +04:00
}
# endif