123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963 |
- #!/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)
- if len(sys.argv) > 1:
- srcPref = sys.argv[1] + '/'
- else:
- srcPref = ''
- #
- # Modules we want to 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",
- "xmlmodule" : "LIBXML_MODULES_ENABLED",
- "pattern" : "LIBXML_PATTERN_ENABLED",
- "schematron" : "LIBXML_SCHEMATRON_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 functions 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", "xmlNanoHTTPMethod", "xmlNanoHTTPMethodRedir",
- # Complex I/O APIs
- "xmlCreateIOParserCtxt", "xmlParserInputBufferCreateIO",
- "xmlRegisterInputCallbacks", "xmlReaderForIO",
- "xmlOutputBufferCreateIO", "xmlRegisterOutputCallbacks",
- "xmlSaveToIO", "xmlIOHTTPOpenW",
- # 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", "xmlNanoHTTPClose",
- # 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",
- ]
- #
- # These functions have side effects 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", "htmlCtxtReadFile", # loads the catalogs
- "xmlTextReaderSchemaValidate", "xmlSchemaCleanupTypes", # initialize the schemas type system
- "xmlCatalogResolve", "xmlIOParseDTD" # 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 ; }",
- "xmlAddEntity":
- "if (ret_val != NULL) { xmlFreeNode(ret_val) ; ret_val = 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;""",
- "xmlNewDocElementContent":
- """xmlFreeDocElementContent(doc, 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;}",
- "xmlDOMWrapAdoptNode": "if ((node != NULL) && (node->parent == NULL)) {xmlUnlinkNode(node);xmlFreeNode(node);node = NULL;}",
- "xmlBufferSetAllocationScheme": "if ((buf != NULL) && (scheme == XML_BUFFER_ALLOC_IMMUTABLE) && (buf->content != NULL) && (buf->content != static_buf_content)) { xmlFree(buf->content); buf->content = 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 or \
- string.find(function, "Fetch") != -1:
- return('fileoutput')
- return('filepath')
- if res == 'void_ptr':
- if module == 'nanoftp' and name == 'ctx':
- return('xmlNanoFTPCtxtPtr')
- if function == 'xmlNanoFTPNewCtxt' or \
- function == 'xmlNanoFTPConnectTo' or \
- function == 'xmlNanoFTPOpen':
- return('xmlNanoFTPCtxtPtr')
- if module == 'nanohttp' and name == 'ctx':
- return('xmlNanoHTTPCtxtPtr')
- if function == 'xmlNanoHTTPMethod' or \
- function == 'xmlNanoHTTPMethodRedir' or \
- function == 'xmlNanoHTTPOpen' or \
- function == 'xmlNanoHTTPOpenRedir':
- return('xmlNanoHTTPCtxtPtr');
- if function == 'xmlIOHTTPOpen':
- 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
- #
- try:
- input = open("testapi.c", "r")
- except:
- input = open(srcPref + "testapi.c", "r")
- test = open('testapi.c.new', 'w')
- def compare_and_save():
- global test
- test.close()
- try:
- input = open("testapi.c", "r").read()
- except:
- input = ''
- test = open('testapi.c.new', "r").read()
- if input != test:
- try:
- os.system("rm testapi.c; mv testapi.c.new testapi.c")
- except:
- os.system("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(srcPref + 'doc/libxml2-api.xml', None, 0)
- if doc == None:
- print "Failed to load doc/libxml2-api.xml"
- sys.exit(1)
- ctxt = doc.xpathNewContext()
- #
- # Generate a list of all function parameters and select only
- # those used in the api tests
- #
- argtypes = {}
- args = ctxt.xpathEval("/api/symbols/function/arg")
- for arg in args:
- mod = arg.xpathEval('string(../@file)')
- func = arg.xpathEval('string(../@name)')
- if (mod not in skipped_modules) and (func not in skipped_functions):
- type = arg.xpathEval('string(@type)')
- if not argtypes.has_key(type):
- argtypes[type] = func
- # similarly for return types
- rettypes = {}
- rets = ctxt.xpathEval("/api/symbols/function/return")
- for ret in rets:
- mod = ret.xpathEval('string(../@file)')
- func = ret.xpathEval('string(../@name)')
- if (mod not in skipped_modules) and (func not in skipped_functions):
- type = ret.xpathEval('string(@type)')
- if not rettypes.has_key(type):
- rettypes[type] = func
- #
- # Generate constructors and return type handling for all enums
- # which are used as function parameters
- #
- enums = ctxt.xpathEval("/api/symbols/typedef[@type='enum']")
- for enum in enums:
- module = enum.xpathEval('string(@file)')
- name = enum.xpathEval('string(@name)')
- #
- # Skip any enums which are not in our filtered lists
- #
- if (name == None) or ((name not in argtypes) and (name not in rettypes)):
- continue;
- define = 0
- if argtypes.has_key(name) and 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 find 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);
- }
- static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
- }
- """ % (name, name));
- known_param_types.append(name)
- if (is_known_return_type(name) == 0) and (name in rettypes):
- if define == 0 and modules_defines.has_key(module):
- test.write("#ifdef %s\n" % (modules_defines[module]))
- define = 1
- test.write("""static void desret_%s(%s val ATTRIBUTE_UNUSED) {
- }
- """ % (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
- if (type[-3:] == 'Ptr' or type[-4:] == '_ptr') and \
- rtype[0:6] == 'const ':
- crtype = rtype[6:]
- else:
- crtype = rtype
- t_args.append((nam, type, rtype, crtype, 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("#if %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, crtype, info) = arg;
- # 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, crtype, 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, crtype, 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, crtype, info) = arg
- if need:
- test.write(", ")
- else:
- need = 1
- if rtype != crtype:
- test.write("(%s)" % rtype)
- 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, crtype, info) = arg;
- if need:
- test.write(", ")
- else:
- need = 1
- if rtype != crtype:
- test.write("(%s)" % rtype)
- 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, crtype, info) = arg;
- # This is a hack to prevent generating a destructor for the
- # 'input' argument in xmlTextReaderSetup. There should be
- # a better, more generic way to do this!
- if string.find(info, 'destroy') == -1:
- test.write(" des_%s(n_%s, " % (type, nam))
- if rtype != crtype:
- test.write("(%s)" % rtype)
- test.write("%s, %d);\n" % (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, crtype, 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()
|