2004-11-02 17:52:23 +03:00
#!/usr/bin/python -u
#
# generate a tester program for the API
#
import sys
import string
try :
import libxml2
except :
print " libxml2 python bindings not available, skipping testapi.c generation "
sys . exit ( 0 )
#
# Modules we don't want skip in API test
#
skipped_modules = [ " SAX " , " SAX2 " , " xlink " , " threads " , " globals " ,
" xpathInternals " , " xmlunicode " , " parserInternals " , " xmlmemory " ,
2004-11-03 17:20:29 +03:00
" xmlversion " , " debugXML " , " xmlexports " ]
2004-11-02 17:52:23 +03:00
#
# Some function really need to be skipped for the tests.
#
2004-11-03 17:20:29 +03:00
skipped_functions = [
# block on I/O
" xmlFdRead " , " xmlReadFd " , " xmlCtxtReadFd " ,
" htmlFdRead " , " htmlReadFd " , " htmlCtxtReadFd " ,
" xmlReaderNewFd " ,
# library state cleanup, generate false leak informations and other
# troubles, heavillyb tested otherwise.
" xmlCleanupParser " , " xmlRelaxNGCleanupTypes " ,
# hard to avoid leaks in the tests
" xmlStrcat " , " xmlStrncat " ,
# unimplemented
" xmlTextReaderReadInnerXml " , " xmlTextReaderReadOuterXml " ,
" xmlTextReaderReadString "
]
2004-11-02 17:52:23 +03:00
#
# Those functions have side effect on the global state
# and hence generate errors on memory allocation tests
#
skipped_memcheck = [ " xmlLoadCatalog " , " xmlAddEncodingAlias " ,
" xmlSchemaInitTypes " , " xmlNanoFTPProxy " , " xmlNanoFTPScanProxy " ,
" xmlNanoHTTPScanProxy " , " xmlResetLastError " , " xmlCatalogConvert " ,
" xmlCatalogRemove " , " xmlLoadCatalogs " , " xmlCleanupCharEncodingHandlers " ,
2004-11-02 21:45:30 +03:00
" xmlInitCharEncodingHandlers " , " xmlCatalogCleanup " ,
" htmlParseFile " # loads the catalogs
]
#
# Extra code needed for some test cases
#
extra_post_call = {
" xmlAddChild " :
" if (ret_val == NULL) { xmlFreeNode(cur) ; cur = NULL ; } " ,
" xmlAddChildList " :
" if (ret_val == NULL) { xmlFreeNodeList(cur) ; cur = NULL ; } " ,
" xmlAddSibling " :
" if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; } " ,
" xmlAddNextSibling " :
" if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; } " ,
" xmlAddPrevSibling " :
" if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; } " ,
" xmlDocSetRootElement " :
" if (doc == NULL) { xmlFreeNode(root) ; root = NULL ; } " ,
" xmlReplaceNode " :
""" if ((old == NULL) || (old->parent == NULL)) {
xmlFreeNode ( cur ) ; cur = NULL ; } """ ,
" xmlTextMerge " :
""" if ((first != NULL) && (first->type != XML_TEXT_NODE)) {
xmlFreeNode ( second ) ; second = NULL ; } """ ,
2004-11-03 01:10:16 +03:00
" xmlBuildQName " :
""" if ((ret_val != NULL) && (ret_val != ncname) &&
( ret_val != prefix ) & & ( ret_val != memory ) )
xmlFree ( ret_val ) ;
ret_val = NULL ; """ ,
2004-11-02 21:45:30 +03:00
}
2004-11-02 17:52:23 +03:00
modules = [ ]
def is_skipped_module ( name ) :
for mod in skipped_modules :
if mod == name :
return 1
return 0
def is_skipped_function ( name ) :
for fun in skipped_functions :
if fun == name :
return 1
# Do not test destructors
if string . find ( name , ' Free ' ) != - 1 :
return 1
return 0
def is_skipped_memcheck ( name ) :
for fun in skipped_memcheck :
if fun == name :
return 1
return 0
missing_types = { }
def add_missing_type ( name , func ) :
try :
list = missing_types [ name ]
list . append ( func )
except :
missing_types [ name ] = [ func ]
#
# Open the input API description and the C test program result
#
doc = libxml2 . readFile ( ' doc/libxml2-api.xml ' , None , 0 )
if doc == None :
print " Failed to load doc/libxml2-api.xml "
sys . exit ( 1 )
test = open ( ' testapi.c ' , ' w ' )
ctxt = doc . xpathNewContext ( )
headers = ctxt . xpathEval ( " /api/files/file " )
#
# Generate the test header
#
test . write ( """ /*
* testapi . c : libxml2 API tester program .
*
* Automatically generated by gentest . py from libxml2 - api . xml
*
* See Copyright for the status of this software .
*
* daniel @veillard.com
* /
#include <stdio.h>
#include <libxml/xmlerror.h>
static int testlibxml2 ( void ) ;
static int generic_errors = 0 ;
static int call_tests = 0 ;
2004-11-03 01:34:52 +03:00
static xmlChar chartab [ 1024 ] = " chartab \\ n " ;
2004-11-03 01:10:16 +03:00
2004-11-02 17:52:23 +03:00
static void
structured_errors ( void * userData ATTRIBUTE_UNUSED ,
xmlErrorPtr error ATTRIBUTE_UNUSED ) {
generic_errors + + ;
}
int main ( void ) {
int ret ;
int blocks , mem ;
2004-11-02 21:45:30 +03:00
xmlInitParser ( ) ;
2004-11-03 17:20:29 +03:00
xmlRelaxNGInitTypes ( ) ;
2004-11-02 21:45:30 +03:00
2004-11-02 17:52:23 +03:00
LIBXML_TEST_VERSION
xmlSetStructuredErrorFunc ( NULL , structured_errors ) ;
ret = testlibxml2 ( ) ;
xmlCleanupParser ( ) ;
blocks = xmlMemBlocks ( ) ;
mem = xmlMemUsed ( ) ;
if ( ( blocks != 0 ) | | ( mem != 0 ) ) {
printf ( " testapi leaked %d bytes in %d blocks \\ n " , mem , blocks ) ;
}
xmlMemoryDump ( ) ;
return ( ret != 0 ) ;
}
""" );
#
# Load the interfaces
#
for file in headers :
name = file . xpathEval ( ' string(@name) ' )
if ( name == None ) or ( name == ' ' ) :
continue
#
# do not test deprecated APIs
#
desc = file . xpathEval ( ' string(description) ' )
if string . find ( desc , ' DEPRECATED ' ) != - 1 :
print " Skipping deprecated interface %s " % name
continue ;
#
# Some module may be skipped because they don't really consists
# of user callable APIs
#
if is_skipped_module ( name ) :
continue
test . write ( " #include <libxml/ %s .h> \n " % name )
modules . append ( name )
#
# Generate the callers signatures
#
for module in modules :
test . write ( " static int test_ %s (void); \n " % module ) ;
#
# Provide the type generators and destructors for the parameters
#
2004-11-02 21:45:30 +03:00
def type_convert ( str , name , info , module , function , pos ) :
2004-11-02 17:52:23 +03:00
res = string . replace ( str , " * " , " _ptr " )
res = string . replace ( res , " " , " _ " )
2004-11-02 21:45:30 +03:00
res = string . replace ( res , " htmlNode " , " xmlNode " )
res = string . replace ( res , " htmlDoc " , " xmlDoc " )
res = string . replace ( res , " htmlParser " , " xmlParser " )
2004-11-02 17:52:23 +03:00
if res == ' const_char_ptr ' :
if string . find ( name , " file " ) != - 1 or \
string . find ( name , " uri " ) != - 1 or \
string . find ( name , " URI " ) != - 1 or \
string . find ( info , " filename " ) != - 1 or \
string . find ( info , " URI " ) != - 1 or \
string . find ( info , " URL " ) != - 1 :
if string . find ( function , " Save " ) != - 1 :
return ( ' fileoutput ' )
return ( ' filepath ' )
if res == ' void_ptr ' :
if module == ' nanoftp ' and name == ' ctx ' :
return ( ' xmlNanoFTPCtxtPtr ' )
if module == ' nanohttp ' and name == ' ctx ' :
return ( ' xmlNanoHTTPCtxtPtr ' )
2004-11-03 01:10:16 +03:00
if string . find ( name , " data " ) != - 1 :
return ( ' userdata ' ) ;
2004-11-02 21:45:30 +03:00
if res == ' xmlNodePtr ' and pos != 0 :
if ( function == ' xmlAddChild ' and pos == 2 ) or \
( function == ' xmlAddChildList ' and pos == 2 ) or \
( function == ' xmlAddNextSibling ' and pos == 2 ) or \
( function == ' xmlAddSibling ' and pos == 2 ) or \
( function == ' xmlDocSetRootElement ' and pos == 2 ) or \
( function == ' xmlReplaceNode ' and pos == 2 ) or \
( function == ' xmlTextMerge ' ) or \
( function == ' xmlAddPrevSibling ' and pos == 2 ) :
return ( ' xmlNodePtr_in ' ) ;
2004-11-02 17:52:23 +03:00
return res
known_param_types = [ " int " , " const_char_ptr " , " const_xmlChar_ptr " ,
2004-11-03 14:50:29 +03:00
" xmlParserCtxtPtr " , " xmlDocPtr " , " filepath " , " fileoutput " ,
" xmlNodePtr " , " xmlNodePtr_in " , " userdata " , " xmlChar_ptr " ,
2004-11-03 17:20:29 +03:00
" xmlTextWriterPtr " , " xmlTextReaderPtr " ] ;
2004-11-02 17:52:23 +03:00
def is_known_param_type ( name ) :
for type in known_param_types :
if type == name :
return 1
return 0
test . write ( """
2004-11-03 01:10:16 +03:00
#define gen_nb_userdata 3
static void * gen_userdata ( int no ) {
if ( no == 0 ) return ( ( void * ) & call_tests ) ;
if ( no == 1 ) return ( ( void * ) - 1 ) ;
return ( NULL ) ;
}
static void des_userdata ( int no ATTRIBUTE_UNUSED , void * val ATTRIBUTE_UNUSED ) {
}
2004-11-02 17:52:23 +03:00
#define gen_nb_int 4
static int gen_int ( int no ) {
if ( no == 0 ) return ( 0 ) ;
if ( no == 1 ) return ( 1 ) ;
if ( no == 2 ) return ( 122 ) ;
return ( - 1 ) ;
}
static void des_int ( int no ATTRIBUTE_UNUSED , int val ATTRIBUTE_UNUSED ) {
}
#define gen_nb_const_char_ptr 4
static const char * gen_const_char_ptr ( int no ) {
if ( no == 0 ) return ( " foo " ) ;
if ( no == 1 ) return ( " <foo/> " ) ;
if ( no == 2 ) return ( " test/ent2 " ) ;
return ( NULL ) ;
}
static void des_const_char_ptr ( int no ATTRIBUTE_UNUSED , const char * val ATTRIBUTE_UNUSED ) {
}
2004-11-03 01:10:16 +03:00
#define gen_nb_xmlChar_ptr 2
static xmlChar * gen_xmlChar_ptr ( int no ) {
if ( no == 0 ) return ( & chartab ) ;
return ( NULL ) ;
}
static void des_xmlChar_ptr ( int no ATTRIBUTE_UNUSED , xmlChar * val ATTRIBUTE_UNUSED ) {
}
2004-11-02 17:52:23 +03:00
#define gen_nb_const_xmlChar_ptr 5
static const xmlChar * gen_const_xmlChar_ptr ( int no ) {
if ( no == 0 ) return ( ( const xmlChar * ) " foo " ) ;
if ( no == 1 ) return ( ( const xmlChar * ) " <foo/> " ) ;
if ( no == 2 ) return ( ( const xmlChar * ) " n<EFBFBD> ne " ) ;
if ( no == 3 ) return ( ( const xmlChar * ) " 2ab " ) ;
return ( NULL ) ;
}
static void des_const_xmlChar_ptr ( int no ATTRIBUTE_UNUSED , const xmlChar * val ATTRIBUTE_UNUSED ) {
}
#define gen_nb_filepath 8
static const char * gen_filepath ( int no ) {
if ( no == 0 ) return ( " missing.xml " ) ;
if ( no == 1 ) return ( " <foo/> " ) ;
if ( no == 2 ) return ( " test/ent2 " ) ;
if ( no == 3 ) return ( " test/valid/REC-xml-19980210.xml " ) ;
if ( no == 4 ) return ( " test/valid/xhtml1-strict.dtd " ) ;
if ( no == 5 ) return ( " http://missing.example.org/ " ) ;
if ( no == 6 ) return ( " http://missing. example.org/ " ) ;
return ( NULL ) ;
}
static void des_filepath ( int no ATTRIBUTE_UNUSED , const char * val ATTRIBUTE_UNUSED ) {
}
#define gen_nb_fileoutput 6
static const char * gen_fileoutput ( int no ) {
if ( no == 0 ) return ( " /missing.xml " ) ;
if ( no == 1 ) return ( " <foo/> " ) ;
if ( no == 2 ) return ( " ftp://missing.example.org/foo " ) ;
if ( no == 3 ) return ( " http://missing.example.org/ " ) ;
if ( no == 4 ) return ( " http://missing. example.org/ " ) ;
return ( NULL ) ;
}
static void des_fileoutput ( int no ATTRIBUTE_UNUSED , const char * val ATTRIBUTE_UNUSED ) {
}
#define gen_nb_xmlParserCtxtPtr 2
static xmlParserCtxtPtr gen_xmlParserCtxtPtr ( int no ) {
if ( no == 0 ) return ( xmlNewParserCtxt ( ) ) ;
return ( NULL ) ;
}
static void des_xmlParserCtxtPtr ( int no ATTRIBUTE_UNUSED , xmlParserCtxtPtr val ) {
if ( val != NULL )
xmlFreeParserCtxt ( val ) ;
}
2004-11-02 21:45:30 +03:00
#define gen_nb_xmlDocPtr 3
2004-11-02 17:52:23 +03:00
static xmlDocPtr gen_xmlDocPtr ( int no ) {
if ( no == 0 ) return ( xmlNewDoc ( BAD_CAST " 1.0 " ) ) ;
2004-11-02 21:45:30 +03:00
if ( no == 1 ) return ( xmlReadMemory ( " <foo/> " , 6 , " test " , NULL , 0 ) ) ;
2004-11-02 17:52:23 +03:00
return ( NULL ) ;
}
static void des_xmlDocPtr ( int no ATTRIBUTE_UNUSED , xmlDocPtr val ) {
if ( val != NULL )
xmlFreeDoc ( val ) ;
}
2004-11-02 21:45:30 +03:00
#define gen_nb_xmlNodePtr 2
static xmlNodePtr gen_xmlNodePtr ( int no ) {
if ( no == 0 ) return ( xmlNewPI ( BAD_CAST " test " , NULL ) ) ;
return ( NULL ) ;
}
static void des_xmlNodePtr ( int no ATTRIBUTE_UNUSED , xmlNodePtr val ) {
if ( val != NULL ) {
xmlUnlinkNode ( val ) ;
xmlFreeNode ( val ) ;
}
}
#define gen_nb_xmlNodePtr_in 3
static xmlNodePtr gen_xmlNodePtr_in ( int no ) {
if ( no == 0 ) return ( xmlNewPI ( BAD_CAST " test " , NULL ) ) ;
if ( no == 0 ) return ( xmlNewText ( BAD_CAST " text " ) ) ;
return ( NULL ) ;
}
static void des_xmlNodePtr_in ( int no ATTRIBUTE_UNUSED , xmlNodePtr val ATTRIBUTE_UNUSED ) {
}
2004-11-03 14:50:29 +03:00
#define gen_nb_xmlTextWriterPtr 2
static xmlTextWriterPtr gen_xmlTextWriterPtr ( int no ) {
if ( no == 0 ) return ( xmlNewTextWriterFilename ( " test.out " , 0 ) ) ;
return ( NULL ) ;
}
static void des_xmlTextWriterPtr ( int no ATTRIBUTE_UNUSED , xmlTextWriterPtr val ) {
if ( val != NULL ) xmlFreeTextWriter ( val ) ;
}
2004-11-03 17:20:29 +03:00
#define gen_nb_xmlTextReaderPtr 4
static xmlTextReaderPtr gen_xmlTextReaderPtr ( int no ) {
if ( no == 0 ) return ( xmlNewTextReaderFilename ( " test/ent2 " ) ) ;
if ( no == 1 ) return ( xmlNewTextReaderFilename ( " test/valid/REC-xml-19980210.xml " ) ) ;
if ( no == 2 ) return ( xmlNewTextReaderFilename ( " test/valid/dtds/xhtml1-strict.dtd " ) ) ;
return ( NULL ) ;
}
static void des_xmlTextReaderPtr ( int no ATTRIBUTE_UNUSED , xmlTextReaderPtr val ) {
if ( val != NULL ) xmlFreeTextReader ( val ) ;
}
2004-11-02 17:52:23 +03:00
""" );
#
# Provide the type destructors for the return values
#
2004-11-03 01:10:16 +03:00
known_return_types = [ " int " , " const_char_ptr " , " xmlDocPtr " , " xmlNodePtr " ,
" xmlChar_ptr " ] ;
2004-11-02 17:52:23 +03:00
def is_known_return_type ( name ) :
for type in known_return_types :
if type == name :
return 1
return 0
test . write ( """
static void desret_int ( int val ATTRIBUTE_UNUSED ) {
}
static void desret_const_char_ptr ( const char * val ATTRIBUTE_UNUSED ) {
}
2004-11-03 01:10:16 +03:00
static void desret_xmlChar_ptr ( xmlChar * val ) {
if ( val != NULL )
xmlFree ( val ) ;
}
2004-11-02 17:52:23 +03:00
static void desret_xmlDocPtr ( xmlDocPtr val ) {
xmlFreeDoc ( val ) ;
}
static void desret_xmlNodePtr ( xmlNodePtr val ) {
xmlUnlinkNode ( val ) ;
xmlFreeNode ( val ) ;
}
""" );
#
# Generate the top caller
#
test . write ( """
/ * *
* testlibxml2 :
*
* Main entry point of the tester for the full libxml2 module ,
* it calls all the tester entry point for each module .
*
* Returns the number of error found
* /
static int
testlibxml2 ( void )
{
int ret = 0 ;
""" )
for module in modules :
test . write ( " ret += test_ %s (); \n " % module )
test . write ( """
printf ( " Total: %d tests, %d errors \\ n " , call_tests , ret ) ;
return ( ret ) ;
}
""" )
#
# How to handle a function
#
nb_tests = 0
def generate_test ( module , node ) :
global test
global nb_tests
nb_cond = 0
no_gen = 0
name = node . xpathEval ( ' string(@name) ' )
if is_skipped_function ( name ) :
return
test . write ( """
static int
test_ % s ( void ) {
int ret = 0 ;
""" % (name))
#
# check we know how to handle the args and return values
# and store the informations for the generation
#
try :
args = node . xpathEval ( " arg " )
except :
args = [ ]
t_args = [ ]
2004-11-02 21:45:30 +03:00
n = 0
2004-11-02 17:52:23 +03:00
for arg in args :
2004-11-02 21:45:30 +03:00
n = n + 1
2004-11-02 17:52:23 +03:00
rtype = arg . xpathEval ( " string(@type) " )
if rtype == ' void ' :
break ;
info = arg . xpathEval ( " string(@info) " )
nam = arg . xpathEval ( " string(@name) " )
2004-11-02 21:45:30 +03:00
type = type_convert ( rtype , nam , info , module , name , n )
2004-11-02 17:52:23 +03:00
if is_known_param_type ( type ) == 0 :
add_missing_type ( type , name ) ;
no_gen = 1
t_args . append ( ( nam , type , rtype , info ) )
try :
rets = node . xpathEval ( " return " )
except :
rets = [ ]
t_ret = None
for ret in rets :
rtype = ret . xpathEval ( " string(@type) " )
info = ret . xpathEval ( " string(@info) " )
2004-11-02 21:45:30 +03:00
type = type_convert ( rtype , ' return ' , info , module , name , 0 )
2004-11-02 17:52:23 +03:00
if rtype == ' void ' :
break
if is_known_return_type ( type ) == 0 :
add_missing_type ( type , name ) ;
no_gen = 1
t_ret = ( type , rtype , info )
break
if no_gen == 1 :
test . write ( """
/ * missing type support * /
return ( ret ) ;
}
""" )
return
try :
conds = node . xpathEval ( " cond " )
for cond in conds :
test . write ( " #ifdef %s \n " % ( cond . get_content ( ) ) )
nb_cond = nb_cond + 1
except :
pass
# Declare the memory usage counter
no_mem = is_skipped_memcheck ( name )
if no_mem == 0 :
test . write ( " int mem_base; \n " ) ;
# Declare the return value
if t_ret != None :
test . write ( " %s ret_val; \n " % ( t_ret [ 1 ] ) )
# Declare the arguments
for arg in t_args :
( nam , type , rtype , info ) = arg ;
# add declaration
test . write ( " %s %s ; /* %s */ \n " % ( rtype , nam , info ) )
test . write ( " int n_ %s ; \n " % ( nam ) )
test . write ( " \n " )
# Cascade loop on of each argument list of values
for arg in t_args :
( nam , type , rtype , info ) = arg ;
#
test . write ( " for (n_ %s = 0;n_ %s < gen_nb_ %s ;n_ %s ++) { \n " % (
nam , nam , type , nam ) )
# log the memory usage
if no_mem == 0 :
test . write ( " mem_base = xmlMemBlocks(); \n " ) ;
# prepare the call
for arg in t_args :
( nam , type , rtype , info ) = arg ;
#
test . write ( " %s = gen_ %s (n_ %s ); \n " % ( nam , type , nam ) )
# do the call, and clanup the result
if t_ret != None :
test . write ( " \n ret_val = %s ( " % ( name ) )
need = 0
for arg in t_args :
( nam , type , rtype , info ) = arg
if need :
test . write ( " , " )
else :
need = 1
test . write ( " %s " % nam ) ;
2004-11-03 01:10:16 +03:00
test . write ( " ); \n " )
if extra_post_call . has_key ( name ) :
test . write ( " %s \n " % ( extra_post_call [ name ] ) )
test . write ( " desret_ %s (ret_val); \n " % t_ret [ 0 ] )
2004-11-02 17:52:23 +03:00
else :
test . write ( " \n %s ( " % ( name ) ) ;
need = 0 ;
for arg in t_args :
( nam , type , rtype , info ) = arg ;
if need :
test . write ( " , " )
else :
need = 1
test . write ( " %s " % nam )
test . write ( " ); \n " )
2004-11-03 01:10:16 +03:00
if extra_post_call . has_key ( name ) :
test . write ( " %s \n " % ( extra_post_call [ name ] ) )
2004-11-02 17:52:23 +03:00
2004-11-03 01:10:16 +03:00
test . write ( " call_tests++; \n " ) ;
2004-11-02 21:45:30 +03:00
2004-11-02 17:52:23 +03:00
# Free the arguments
for arg in t_args :
( nam , type , rtype , info ) = arg ;
#
test . write ( " des_ %s (n_ %s , %s ); \n " % ( type , nam , nam ) )
test . write ( " xmlResetLastError(); \n " ) ;
# Check the memory usage
if no_mem == 0 :
test . write ( """ if (mem_base != xmlMemBlocks()) {
2004-11-02 21:45:30 +03:00
printf ( " Leak of %% d blocks found in %s " ,
2004-11-02 17:52:23 +03:00
xmlMemBlocks ( ) - mem_base ) ;
ret + + ;
""" % (name));
2004-11-02 21:45:30 +03:00
for arg in t_args :
( nam , type , rtype , info ) = arg ;
test . write ( """ printf( " %% d " , n_ %s ); \n """ % ( nam ) )
test . write ( """ printf( " \\ n " ); \n """ )
test . write ( " } \n " )
2004-11-02 17:52:23 +03:00
for arg in t_args :
test . write ( " } \n " )
#
# end of conditional
#
while nb_cond > 0 :
test . write ( " #endif \n " )
nb_cond = nb_cond - 1
nb_tests = nb_tests + 1 ;
test . write ( """
return ( ret ) ;
}
""" )
#
# Generate all module callers
#
for module in modules :
# gather all the functions exported by that module
try :
functions = ctxt . xpathEval ( " /api/symbols/function[@file= ' %s ' ] " % ( module ) )
except :
print " Failed to gather functions from module %s " % ( module )
continue ;
# iterate over all functions in the module generating the test
for function in functions :
generate_test ( module , function ) ;
# header
test . write ( """ static int
test_ % s ( void ) {
int ret = 0 ;
printf ( " Testing %s ... \\ n " ) ;
""" % (module, module))
# iterate over all functions in the module generating the call
for function in functions :
name = function . xpathEval ( ' string(@name) ' )
if is_skipped_function ( name ) :
continue
test . write ( " ret += test_ %s (); \n " % ( name ) )
# footer
test . write ( """
if ( ret != 0 )
printf ( " Module %s : %% d errors \\ n " , ret ) ;
return ( ret ) ;
}
""" % (module))
print " Generated test for %d modules and %d functions " % ( len ( modules ) , nb_tests )
nr = 0
miss = ' none '
for missing in missing_types . keys ( ) :
n = len ( missing_types [ missing ] )
if n > nr :
miss = missing
nr = n
if nr > 0 :
print " most needed type support: %s %d times " % ( miss , nr )