diff options
Diffstat (limited to 'gentest.py')
-rwxr-xr-x | gentest.py | 889 |
1 files changed, 889 insertions, 0 deletions
diff --git a/gentest.py b/gentest.py new file mode 100755 index 0000000..8975cd9 --- /dev/null +++ b/gentest.py @@ -0,0 +1,889 @@ +#!/usr/bin/python -u +# +# generate a tester program for the API +# +import sys +import os +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", "xlink", "threads", "globals", + "xmlmemory", "xmlversion", "xmlexports", + #deprecated + "DOCBparser", +] + +# +# defines for each module +# +modules_defines = { + "HTMLparser": "LIBXML_HTML_ENABLED", + "catalog": "LIBXML_CATALOG_ENABLED", + "xmlreader": "LIBXML_READER_ENABLED", + "relaxng": "LIBXML_SCHEMAS_ENABLED", + "schemasInternals": "LIBXML_SCHEMAS_ENABLED", + "xmlschemas": "LIBXML_SCHEMAS_ENABLED", + "xmlschemastypes": "LIBXML_SCHEMAS_ENABLED", + "xpath": "LIBXML_XPATH_ENABLED", + "xpathInternals": "LIBXML_XPATH_ENABLED", + "xinclude": "LIBXML_XINCLUDE_ENABLED", + "xpointer": "LIBXML_XPTR_ENABLED", + "xmlregexp" : "LIBXML_REGEXP_ENABLED", + "xmlautomata" : "LIBXML_AUTOMATA_ENABLED", + "xmlsave" : "LIBXML_OUTPUT_ENABLED", + "DOCBparser" : "LIBXML_DOCB_ENABLED", +} + +# +# defines for specific functions +# +function_defines = { + "htmlDefaultSAXHandlerInit": "LIBXML_HTML_ENABLED", + "xmlSAX2EndElement" : "LIBXML_SAX1_ENABLED", + "xmlSAX2StartElement" : "LIBXML_SAX1_ENABLED", + "xmlSAXDefaultVersion" : "LIBXML_SAX1_ENABLED", + "UTF8Toisolat1" : "LIBXML_OUTPUT_ENABLED", + "xmlCleanupPredefinedEntities": "LIBXML_LEGACY_ENABLED", + "xmlInitializePredefinedEntities": "LIBXML_LEGACY_ENABLED", + "xmlSetFeature": "LIBXML_LEGACY_ENABLED", + "xmlGetFeature": "LIBXML_LEGACY_ENABLED", + "xmlGetFeaturesList": "LIBXML_LEGACY_ENABLED", + "xmlIOParseDTD": "LIBXML_VALID_ENABLED", + "xmlParseDTD": "LIBXML_VALID_ENABLED", + "xmlParseDoc": "LIBXML_SAX1_ENABLED", + "xmlParseMemory": "LIBXML_SAX1_ENABLED", + "xmlRecoverDoc": "LIBXML_SAX1_ENABLED", + "xmlParseFile": "LIBXML_SAX1_ENABLED", + "xmlRecoverFile": "LIBXML_SAX1_ENABLED", + "xmlRecoverMemory": "LIBXML_SAX1_ENABLED", + "xmlSAXParseFileWithData": "LIBXML_SAX1_ENABLED", + "xmlSAXParseMemory": "LIBXML_SAX1_ENABLED", + "xmlSAXUserParseMemory": "LIBXML_SAX1_ENABLED", + "xmlSAXParseDoc": "LIBXML_SAX1_ENABLED", + "xmlSAXParseDTD": "LIBXML_SAX1_ENABLED", + "xmlSAXUserParseFile": "LIBXML_SAX1_ENABLED", + "xmlParseEntity": "LIBXML_SAX1_ENABLED", + "xmlParseExternalEntity": "LIBXML_SAX1_ENABLED", + "xmlSAXParseMemoryWithData": "LIBXML_SAX1_ENABLED", + "xmlParseBalancedChunkMemory": "LIBXML_SAX1_ENABLED", + "xmlParseBalancedChunkMemoryRecover": "LIBXML_SAX1_ENABLED", + "xmlSetupParserForBuffer": "LIBXML_SAX1_ENABLED", + "xmlStopParser": "LIBXML_PUSH_ENABLED", + "xmlAttrSerializeTxtContent": "LIBXML_OUTPUT_ENABLED", + "xmlSAXParseFile": "LIBXML_SAX1_ENABLED", + "xmlSAXParseEntity": "LIBXML_SAX1_ENABLED", + "xmlNewTextChild": "LIBXML_TREE_ENABLED", + "xmlNewDocRawNode": "LIBXML_TREE_ENABLED", + "xmlNewProp": "LIBXML_TREE_ENABLED", + "xmlReconciliateNs": "LIBXML_TREE_ENABLED", + "xmlValidateNCName": "LIBXML_TREE_ENABLED", + "xmlValidateNMToken": "LIBXML_TREE_ENABLED", + "xmlValidateName": "LIBXML_TREE_ENABLED", + "xmlNewChild": "LIBXML_TREE_ENABLED", + "xmlValidateQName": "LIBXML_TREE_ENABLED", + "xmlSprintfElementContent": "LIBXML_OUTPUT_ENABLED", + "xmlValidGetPotentialChildren" : "LIBXML_VALID_ENABLED", + "xmlValidGetValidElements" : "LIBXML_VALID_ENABLED", + "docbDefaultSAXHandlerInit" : "LIBXML_DOCB_ENABLED", + "xmlTextReaderPreservePattern" : "LIBXML_PATTERN_ENABLED", +} + +# +# Some function really need to be skipped for the tests. +# +skipped_functions = [ +# block on I/O +"xmlFdRead", "xmlReadFd", "xmlCtxtReadFd", +"htmlFdRead", "htmlReadFd", "htmlCtxtReadFd", +"xmlReaderNewFd", "xmlReaderForFd", +"xmlIORead", "xmlReadIO", "xmlCtxtReadIO", +"htmlIORead", "htmlReadIO", "htmlCtxtReadIO", +"xmlReaderNewIO", "xmlBufferDump", "xmlNanoFTPConnect", +"xmlNanoFTPConnectTo", +# Complex I/O APIs +"xmlCreateIOParserCtxt", "xmlParserInputBufferCreateIO", +"xmlRegisterInputCallbacks", "xmlReaderForIO", +"xmlOutputBufferCreateIO", "xmlRegisterOutputCallbacks", +"xmlSaveToIO", +# library state cleanup, generate false leak informations and other +# troubles, heavillyb tested otherwise. +"xmlCleanupParser", "xmlRelaxNGCleanupTypes", "xmlSetListDoc", +"xmlSetTreeDoc", "xmlUnlinkNode", +# hard to avoid leaks in the tests +"xmlStrcat", "xmlStrncat", "xmlCatalogAddLocal", "xmlNewTextWriterDoc", +"xmlXPathNewValueTree", "xmlXPathWrapString", +# unimplemented +"xmlTextReaderReadInnerXml", "xmlTextReaderReadOuterXml", +"xmlTextReaderReadString", +# destructor +"xmlListDelete", "xmlOutputBufferClose", "xmlNanoFTPClose", +# deprecated +"xmlCatalogGetPublic", "xmlCatalogGetSystem", "xmlEncodeEntities", +"xmlNewGlobalNs", "xmlHandleEntity", "xmlNamespaceParseNCName", +"xmlNamespaceParseNSDef", "xmlNamespaceParseQName", +"xmlParseNamespace", "xmlParseQuotedString", "xmlParserHandleReference", +"xmlScanName", +"xmlDecodeEntities", +# allocators +"xmlMemFree", +# verbosity +"xmlCatalogSetDebug", "xmlShellPrintXPathError", "xmlShellPrintNode", +# Internal functions, no user space should really call them +"xmlParseAttribute", "xmlParseAttributeListDecl", "xmlParseName", +"xmlParseNmtoken", "xmlParseEntityValue", "xmlParseAttValue", +"xmlParseSystemLiteral", "xmlParsePubidLiteral", "xmlParseCharData", +"xmlParseExternalID", "xmlParseComment", "xmlParsePITarget", "xmlParsePI", +"xmlParseNotationDecl", "xmlParseEntityDecl", "xmlParseDefaultDecl", +"xmlParseNotationType", "xmlParseEnumerationType", "xmlParseEnumeratedType", +"xmlParseAttributeType", "xmlParseAttributeListDecl", +"xmlParseElementMixedContentDecl", "xmlParseElementChildrenContentDecl", +"xmlParseElementContentDecl", "xmlParseElementDecl", "xmlParseMarkupDecl", +"xmlParseCharRef", "xmlParseEntityRef", "xmlParseReference", +"xmlParsePEReference", "xmlParseDocTypeDecl", "xmlParseAttribute", +"xmlParseStartTag", "xmlParseEndTag", "xmlParseCDSect", "xmlParseContent", +"xmlParseElement", "xmlParseVersionNum", "xmlParseVersionInfo", +"xmlParseEncName", "xmlParseEncodingDecl", "xmlParseSDDecl", +"xmlParseXMLDecl", "xmlParseTextDecl", "xmlParseMisc", +"xmlParseExternalSubset", "xmlParserHandlePEReference", +"xmlSkipBlankChars", +] + +# +# 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", + "xmlInitCharEncodingHandlers", "xmlCatalogCleanup", + "xmlSchemaGetBuiltInType", + "htmlParseFile", # loads the catalogs +] + +# +# Extra code needed for some test cases +# +extra_pre_call = { + "xmlSAXUserParseFile": """ +#ifdef LIBXML_SAX1_ENABLED + if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL; +#endif +""", + "xmlSAXUserParseMemory": """ +#ifdef LIBXML_SAX1_ENABLED + if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL; +#endif +""", + "xmlParseBalancedChunkMemory": """ +#ifdef LIBXML_SAX1_ENABLED + if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL; +#endif +""", + "xmlParseBalancedChunkMemoryRecover": """ +#ifdef LIBXML_SAX1_ENABLED + if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL; +#endif +""", + "xmlParserInputBufferCreateFd": + "if (fd >= 0) fd = -1;", +} +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 (cur != NULL) { + xmlUnlinkNode(cur); + xmlFreeNode(cur) ; cur = NULL ; } + if (old != NULL) { + xmlUnlinkNode(old); + xmlFreeNode(old) ; old = NULL ; } + ret_val = NULL;""", + "xmlTextMerge": + """if ((first != NULL) && (first->type != XML_TEXT_NODE)) { + xmlUnlinkNode(second); + xmlFreeNode(second) ; second = NULL ; }""", + "xmlBuildQName": + """if ((ret_val != NULL) && (ret_val != ncname) && + (ret_val != prefix) && (ret_val != memory)) + xmlFree(ret_val); + ret_val = NULL;""", + "xmlDictReference": "xmlDictFree(dict);", + # Functions which deallocates one of their parameters + "xmlXPathConvertBoolean": """val = NULL;""", + "xmlXPathConvertNumber": """val = NULL;""", + "xmlXPathConvertString": """val = NULL;""", + "xmlSaveFileTo": """buf = NULL;""", + "xmlSaveFormatFileTo": """buf = NULL;""", + "xmlIOParseDTD": "input = NULL;", + "xmlRemoveProp": "cur = NULL;", + "xmlNewNs": "if ((node == NULL) && (ret_val != NULL)) xmlFreeNs(ret_val);", + "xmlCopyNamespace": "if (ret_val != NULL) xmlFreeNs(ret_val);", + "xmlCopyNamespaceList": "if (ret_val != NULL) xmlFreeNsList(ret_val);", + "xmlNewTextWriter": "if (ret_val != NULL) out = NULL;", + "xmlNewTextWriterPushParser": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;} if (ret_val != NULL) ctxt = NULL;", + "xmlNewIOInputStream": "if (ret_val != NULL) input = NULL;", + "htmlParseChunk": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}", + "htmlParseDocument": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}", + "xmlParseDocument": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}", + "xmlParseChunk": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}", + "xmlParseExtParsedEnt": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}", +} + +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] + +generated_param_types = [] +def add_generated_param_type(name): + generated_param_types.append(name) + +generated_return_types = [] +def add_generated_return_type(name): + generated_return_types.append(name) + +missing_functions = {} +missing_functions_nr = 0 +def add_missing_functions(name, module): + global missing_functions_nr + + missing_functions_nr = missing_functions_nr + 1 + try: + list = missing_functions[module] + list.append(name) + except: + missing_functions[module] = [name] + +# +# Provide the type generators and destructors for the parameters +# + +def type_convert(str, name, info, module, function, pos): +# res = string.replace(str, " ", " ") +# res = string.replace(str, " ", " ") +# res = string.replace(str, " ", " ") + res = string.replace(str, " *", "_ptr") +# res = string.replace(str, "*", "_ptr") + res = string.replace(res, " ", "_") + 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 or \ + string.find(function, "Create") != -1 or \ + string.find(function, "Write") != -1: + return('fileoutput') + return('filepath') + if res == 'void_ptr': + if module == 'nanoftp' and name == 'ctx': + return('xmlNanoFTPCtxtPtr') + if function == 'xmlNanoFTPNewCtxt': + return('xmlNanoFTPCtxtPtr') + if module == 'nanohttp' and name == 'ctx': + return('xmlNanoHTTPCtxtPtr') + if function == 'xmlIOHTTPOpenW': + return('xmlNanoHTTPCtxtPtr') + if string.find(name, "data") != -1: + return('userdata'); + if string.find(name, "user") != -1: + return('userdata'); + if res == 'xmlDoc_ptr': + res = 'xmlDocPtr'; + if res == 'xmlNode_ptr': + res = 'xmlNodePtr'; + if res == 'xmlDict_ptr': + res = 'xmlDictPtr'; + 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'); + if res == 'const xmlBufferPtr': + res = 'xmlBufferPtr'; + if res == 'xmlChar_ptr' and name == 'name' and \ + string.find(function, "EatName") != -1: + return('eaten_name') + if res == 'void_ptr*': + res = 'void_ptr_ptr' + if res == 'char_ptr*': + res = 'char_ptr_ptr' + if res == 'xmlChar_ptr*': + res = 'xmlChar_ptr_ptr' + if res == 'const_xmlChar_ptr*': + res = 'const_xmlChar_ptr_ptr' + if res == 'const_char_ptr*': + res = 'const_char_ptr_ptr' + if res == 'FILE_ptr' and module == 'debugXML': + res = 'debug_FILE_ptr'; + if res == 'int' and name == 'options': + if module == 'parser' or module == 'xmlreader': + res = 'parseroptions' + + return res + +known_param_types = [] + +def is_known_param_type(name, rtype): + global test + for type in known_param_types: + if type == name: + return 1 + for type in generated_param_types: + if type == name: + return 1 + + if name[-3:] == 'Ptr' or name[-4:] == '_ptr': + if rtype[0:6] == 'const ': + crtype = rtype[6:] + else: + crtype = rtype + + define = 0 + if modules_defines.has_key(module): + test.write("#ifdef %s\n" % (modules_defines[module])) + define = 1 + test.write(""" +#define gen_nb_%s 1 +static %s gen_%s(int no ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) { + return(NULL); +} +static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) { +} +""" % (name, crtype, name, name, rtype)) + if define == 1: + test.write("#endif\n\n") + add_generated_param_type(name) + return 1 + + return 0 + +# +# Provide the type destructors for the return values +# + +known_return_types = [] + +def is_known_return_type(name): + for type in known_return_types: + if type == name: + return 1 + return 0 + +# +# Copy the beginning of the C test program result +# + +input = open("testapi.c", "r") +test = open('testapi.c.new', 'w') + +def compare_and_save(): + global test + + test.close() + input = open("testapi.c", "r").read() + test = open('testapi.c.new', "r").read() + if input != test: + os.system("rm testapi.c ; mv testapi.c.new testapi.c") + print("Updated testapi.c") + else: + print("Generated testapi.c is identical") + +line = input.readline() +while line != "": + if line == "/* CUT HERE: everything below that line is generated */\n": + break; + if line[0:15] == "#define gen_nb_": + type = string.split(line[15:])[0] + known_param_types.append(type) + if line[0:19] == "static void desret_": + type = string.split(line[19:], '(')[0] + known_return_types.append(type) + test.write(line) + line = input.readline() +input.close() + +if line == "": + print "Could not find the CUT marker in testapi.c skipping generation" + test.close() + sys.exit(0) + +print("Scanned testapi.c: found %d parameters types and %d return types\n" % ( + len(known_param_types), len(known_return_types))) +test.write("/* CUT HERE: everything below that line is generated */\n") + + +# +# Open the input API description +# +doc = libxml2.readFile('doc/libxml2-api.xml', None, 0) +if doc == None: + print "Failed to load doc/libxml2-api.xml" + sys.exit(1) +ctxt = doc.xpathNewContext() + +# +# Generate constructors and return type handling for all enums +# +enums = ctxt.xpathEval("/api/symbols/typedef[@type='enum']") +for enum in enums: + name = enum.xpathEval('string(@name)') + if name == None: + continue; + module = enum.xpathEval('string(@file)') + define = 0 + + if is_known_param_type(name, name) == 0: + values = ctxt.xpathEval("/api/symbols/enum[@type='%s']" % name) + i = 0 + vals = [] + for value in values: + vname = value.xpathEval('string(@name)') + if vname == None: + continue; + i = i + 1 + if i >= 5: + break; + vals.append(vname) + if vals == []: + print "Didn't found any value for enum %s" % (name) + continue + if modules_defines.has_key(module): + test.write("#ifdef %s\n" % (modules_defines[module])) + define = 1 + test.write("#define gen_nb_%s %d\n" % (name, len(vals))) + test.write("""static %s gen_%s(int no, int nr ATTRIBUTE_UNUSED) {\n""" % + (name, name)) + i = 1 + for value in vals: + test.write(" if (no == %d) return(%s);\n" % (i, value)) + i = i + 1 + test.write(""" return(0); +} +"""); + known_param_types.append(name) + + if is_known_return_type(name) == 0: + if define == 0 and modules_defines.has_key(module): + test.write("#ifdef %s\n" % (modules_defines[module])) + define = 1 + test.write("""static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) { +} +static void desret_%s(%s val ATTRIBUTE_UNUSED) { +} + +""" % (name, name, name, name)) + known_return_types.append(name) + if define == 1: + test.write("#endif\n\n") + +# +# Load the interfaces +# +headers = ctxt.xpathEval("/api/files/file") +for file in headers: + name = file.xpathEval('string(@name)') + if (name == None) or (name == ''): + continue + + # + # Some module may be skipped because they don't really consists + # of user callable APIs + # + if is_skipped_module(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; + + 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); + +# +# 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 test_ret = 0; + +""") + +for module in modules: + test.write(" test_ret += test_%s();\n" % module) + +test.write(""" + printf("Total: %d functions, %d tests, %d errors\\n", + function_tests, call_tests, test_ret); + return(test_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 + + # + # 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 = [] + n = 0 + for arg in args: + n = n + 1 + rtype = arg.xpathEval("string(@type)") + if rtype == 'void': + break; + info = arg.xpathEval("string(@info)") + nam = arg.xpathEval("string(@name)") + type = type_convert(rtype, nam, info, module, name, n) + if is_known_param_type(type, rtype) == 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)") + type = type_convert(rtype, 'return', info, module, name, 0) + 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 + + test.write(""" +static int +test_%s(void) { + int test_ret = 0; + +""" % (name)) + + if no_gen == 1: + add_missing_functions(name, module) + test.write(""" + /* missing type support */ + return(test_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 + + define = 0 + if function_defines.has_key(name): + test.write("#ifdef %s\n" % (function_defines[name])) + define = 1 + + # 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; + if (type[-3:] == 'Ptr' or type[-4:] == '_ptr') and \ + rtype[0:6] == 'const ': + crtype = rtype[6:] + else: + crtype = rtype + # add declaration + test.write(" %s %s; /* %s */\n" % (crtype, 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 + i = 0; + for arg in t_args: + (nam, type, rtype, info) = arg; + # + test.write(" %s = gen_%s(n_%s, %d);\n" % (nam, type, nam, i)) + i = i + 1; + + # do the call, and clanup the result + if extra_pre_call.has_key(name): + test.write(" %s\n"% (extra_pre_call[name])) + 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); + 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]) + 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") + if extra_post_call.has_key(name): + test.write(" %s\n"% (extra_post_call[name])) + + test.write(" call_tests++;\n"); + + # Free the arguments + i = 0; + for arg in t_args: + (nam, type, rtype, info) = arg; + # + test.write(" des_%s(n_%s, %s, %d);\n" % (type, nam, nam, i)) + i = i + 1; + + test.write(" xmlResetLastError();\n"); + # Check the memory usage + if no_mem == 0: + test.write(""" if (mem_base != xmlMemBlocks()) { + printf("Leak of %%d blocks found in %s", + xmlMemBlocks() - mem_base); + test_ret++; +""" % (name)); + 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") + + for arg in t_args: + test.write(" }\n") + + test.write(" function_tests++;\n") + # + # end of conditional + # + while nb_cond > 0: + test.write("#endif\n") + nb_cond = nb_cond -1 + if define == 1: + test.write("#endif\n") + + nb_tests = nb_tests + 1; + + test.write(""" + return(test_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 + i = 0 + nb_tests_old = nb_tests + for function in functions: + i = i + 1 + generate_test(module, function); + + # header + test.write("""static int +test_%s(void) { + int test_ret = 0; + + if (quiet == 0) printf("Testing %s : %d of %d functions ...\\n"); +""" % (module, module, nb_tests - nb_tests_old, i)) + + # 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(" test_ret += test_%s();\n" % (name)) + + # footer + test.write(""" + if (test_ret != 0) + printf("Module %s: %%d errors\\n", test_ret); + return(test_ret); +} +""" % (module)) + +# +# Generate direct module caller +# +test.write("""static int +test_module(const char *module) { +"""); +for module in modules: + test.write(""" if (!strcmp(module, "%s")) return(test_%s());\n""" % ( + module, module)) +test.write(""" return(0); +} +"""); + +print "Generated test for %d modules and %d functions" %(len(modules), nb_tests) + +compare_and_save() + +missing_list = [] +for missing in missing_types.keys(): + if missing == 'va_list' or missing == '...': + continue; + + n = len(missing_types[missing]) + missing_list.append((n, missing)) + +def compare_missing(a, b): + return b[0] - a[0] + +missing_list.sort(compare_missing) +print "Missing support for %d functions and %d types see missing.lst" % (missing_functions_nr, len(missing_list)) +lst = open("missing.lst", "w") +lst.write("Missing support for %d types" % (len(missing_list))) +lst.write("\n") +for miss in missing_list: + lst.write("%s: %d :" % (miss[1], miss[0])) + i = 0 + for n in missing_types[miss[1]]: + i = i + 1 + if i > 5: + lst.write(" ...") + break + lst.write(" %s" % (n)) + lst.write("\n") +lst.write("\n") +lst.write("\n") +lst.write("Missing support per module"); +for module in missing_functions.keys(): + lst.write("module %s:\n %s\n" % (module, missing_functions[module])) + +lst.close() + + |