1#!/usr/bin/python -u 2# 3# generate a tester program for the API 4# 5import sys 6import os 7import string 8try: 9 import libxml2 10except: 11 print "libxml2 python bindings not available, skipping testapi.c generation" 12 sys.exit(0) 13 14if len(sys.argv) > 1: 15 srcPref = sys.argv[1] + '/' 16else: 17 srcPref = '' 18 19# 20# Modules we want to skip in API test 21# 22skipped_modules = [ "SAX", "xlink", "threads", "globals", 23 "xmlmemory", "xmlversion", "xmlexports", 24 #deprecated 25 "DOCBparser", 26] 27 28# 29# defines for each module 30# 31modules_defines = { 32 "HTMLparser": "LIBXML_HTML_ENABLED", 33 "catalog": "LIBXML_CATALOG_ENABLED", 34 "xmlreader": "LIBXML_READER_ENABLED", 35 "relaxng": "LIBXML_SCHEMAS_ENABLED", 36 "schemasInternals": "LIBXML_SCHEMAS_ENABLED", 37 "xmlschemas": "LIBXML_SCHEMAS_ENABLED", 38 "xmlschemastypes": "LIBXML_SCHEMAS_ENABLED", 39 "xpath": "LIBXML_XPATH_ENABLED", 40 "xpathInternals": "LIBXML_XPATH_ENABLED", 41 "xinclude": "LIBXML_XINCLUDE_ENABLED", 42 "xpointer": "LIBXML_XPTR_ENABLED", 43 "xmlregexp" : "LIBXML_REGEXP_ENABLED", 44 "xmlautomata" : "LIBXML_AUTOMATA_ENABLED", 45 "xmlsave" : "LIBXML_OUTPUT_ENABLED", 46 "DOCBparser" : "LIBXML_DOCB_ENABLED", 47 "xmlmodule" : "LIBXML_MODULES_ENABLED", 48 "pattern" : "LIBXML_PATTERN_ENABLED", 49 "schematron" : "LIBXML_SCHEMATRON_ENABLED", 50} 51 52# 53# defines for specific functions 54# 55function_defines = { 56 "htmlDefaultSAXHandlerInit": "LIBXML_HTML_ENABLED", 57 "xmlSAX2EndElement" : "LIBXML_SAX1_ENABLED", 58 "xmlSAX2StartElement" : "LIBXML_SAX1_ENABLED", 59 "xmlSAXDefaultVersion" : "LIBXML_SAX1_ENABLED", 60 "UTF8Toisolat1" : "LIBXML_OUTPUT_ENABLED", 61 "xmlCleanupPredefinedEntities": "LIBXML_LEGACY_ENABLED", 62 "xmlInitializePredefinedEntities": "LIBXML_LEGACY_ENABLED", 63 "xmlSetFeature": "LIBXML_LEGACY_ENABLED", 64 "xmlGetFeature": "LIBXML_LEGACY_ENABLED", 65 "xmlGetFeaturesList": "LIBXML_LEGACY_ENABLED", 66 "xmlIOParseDTD": "LIBXML_VALID_ENABLED", 67 "xmlParseDTD": "LIBXML_VALID_ENABLED", 68 "xmlParseDoc": "LIBXML_SAX1_ENABLED", 69 "xmlParseMemory": "LIBXML_SAX1_ENABLED", 70 "xmlRecoverDoc": "LIBXML_SAX1_ENABLED", 71 "xmlParseFile": "LIBXML_SAX1_ENABLED", 72 "xmlRecoverFile": "LIBXML_SAX1_ENABLED", 73 "xmlRecoverMemory": "LIBXML_SAX1_ENABLED", 74 "xmlSAXParseFileWithData": "LIBXML_SAX1_ENABLED", 75 "xmlSAXParseMemory": "LIBXML_SAX1_ENABLED", 76 "xmlSAXUserParseMemory": "LIBXML_SAX1_ENABLED", 77 "xmlSAXParseDoc": "LIBXML_SAX1_ENABLED", 78 "xmlSAXParseDTD": "LIBXML_SAX1_ENABLED", 79 "xmlSAXUserParseFile": "LIBXML_SAX1_ENABLED", 80 "xmlParseEntity": "LIBXML_SAX1_ENABLED", 81 "xmlParseExternalEntity": "LIBXML_SAX1_ENABLED", 82 "xmlSAXParseMemoryWithData": "LIBXML_SAX1_ENABLED", 83 "xmlParseBalancedChunkMemory": "LIBXML_SAX1_ENABLED", 84 "xmlParseBalancedChunkMemoryRecover": "LIBXML_SAX1_ENABLED", 85 "xmlSetupParserForBuffer": "LIBXML_SAX1_ENABLED", 86 "xmlStopParser": "LIBXML_PUSH_ENABLED", 87 "xmlAttrSerializeTxtContent": "LIBXML_OUTPUT_ENABLED", 88 "xmlSAXParseFile": "LIBXML_SAX1_ENABLED", 89 "xmlSAXParseEntity": "LIBXML_SAX1_ENABLED", 90 "xmlNewTextChild": "LIBXML_TREE_ENABLED", 91 "xmlNewDocRawNode": "LIBXML_TREE_ENABLED", 92 "xmlNewProp": "LIBXML_TREE_ENABLED", 93 "xmlReconciliateNs": "LIBXML_TREE_ENABLED", 94 "xmlValidateNCName": "LIBXML_TREE_ENABLED", 95 "xmlValidateNMToken": "LIBXML_TREE_ENABLED", 96 "xmlValidateName": "LIBXML_TREE_ENABLED", 97 "xmlNewChild": "LIBXML_TREE_ENABLED", 98 "xmlValidateQName": "LIBXML_TREE_ENABLED", 99 "xmlSprintfElementContent": "LIBXML_OUTPUT_ENABLED", 100 "xmlValidGetPotentialChildren" : "LIBXML_VALID_ENABLED", 101 "xmlValidGetValidElements" : "LIBXML_VALID_ENABLED", 102 "docbDefaultSAXHandlerInit" : "LIBXML_DOCB_ENABLED", 103 "xmlTextReaderPreservePattern" : "LIBXML_PATTERN_ENABLED", 104} 105 106# 107# Some functions really need to be skipped for the tests. 108# 109skipped_functions = [ 110# block on I/O 111"xmlFdRead", "xmlReadFd", "xmlCtxtReadFd", 112"htmlFdRead", "htmlReadFd", "htmlCtxtReadFd", 113"xmlReaderNewFd", "xmlReaderForFd", 114"xmlIORead", "xmlReadIO", "xmlCtxtReadIO", 115"htmlIORead", "htmlReadIO", "htmlCtxtReadIO", 116"xmlReaderNewIO", "xmlBufferDump", "xmlNanoFTPConnect", 117"xmlNanoFTPConnectTo", "xmlNanoHTTPMethod", "xmlNanoHTTPMethodRedir", 118# Complex I/O APIs 119"xmlCreateIOParserCtxt", "xmlParserInputBufferCreateIO", 120"xmlRegisterInputCallbacks", "xmlReaderForIO", 121"xmlOutputBufferCreateIO", "xmlRegisterOutputCallbacks", 122"xmlSaveToIO", "xmlIOHTTPOpenW", 123# library state cleanup, generate false leak informations and other 124# troubles, heavillyb tested otherwise. 125"xmlCleanupParser", "xmlRelaxNGCleanupTypes", "xmlSetListDoc", 126"xmlSetTreeDoc", "xmlUnlinkNode", 127# hard to avoid leaks in the tests 128"xmlStrcat", "xmlStrncat", "xmlCatalogAddLocal", "xmlNewTextWriterDoc", 129"xmlXPathNewValueTree", "xmlXPathWrapString", 130# unimplemented 131"xmlTextReaderReadInnerXml", "xmlTextReaderReadOuterXml", 132"xmlTextReaderReadString", 133# destructor 134"xmlListDelete", "xmlOutputBufferClose", "xmlNanoFTPClose", "xmlNanoHTTPClose", 135# deprecated 136"xmlCatalogGetPublic", "xmlCatalogGetSystem", "xmlEncodeEntities", 137"xmlNewGlobalNs", "xmlHandleEntity", "xmlNamespaceParseNCName", 138"xmlNamespaceParseNSDef", "xmlNamespaceParseQName", 139"xmlParseNamespace", "xmlParseQuotedString", "xmlParserHandleReference", 140"xmlScanName", 141"xmlDecodeEntities", 142# allocators 143"xmlMemFree", 144# verbosity 145"xmlCatalogSetDebug", "xmlShellPrintXPathError", "xmlShellPrintNode", 146# Internal functions, no user space should really call them 147"xmlParseAttribute", "xmlParseAttributeListDecl", "xmlParseName", 148"xmlParseNmtoken", "xmlParseEntityValue", "xmlParseAttValue", 149"xmlParseSystemLiteral", "xmlParsePubidLiteral", "xmlParseCharData", 150"xmlParseExternalID", "xmlParseComment", "xmlParsePITarget", "xmlParsePI", 151"xmlParseNotationDecl", "xmlParseEntityDecl", "xmlParseDefaultDecl", 152"xmlParseNotationType", "xmlParseEnumerationType", "xmlParseEnumeratedType", 153"xmlParseAttributeType", "xmlParseAttributeListDecl", 154"xmlParseElementMixedContentDecl", "xmlParseElementChildrenContentDecl", 155"xmlParseElementContentDecl", "xmlParseElementDecl", "xmlParseMarkupDecl", 156"xmlParseCharRef", "xmlParseEntityRef", "xmlParseReference", 157"xmlParsePEReference", "xmlParseDocTypeDecl", "xmlParseAttribute", 158"xmlParseStartTag", "xmlParseEndTag", "xmlParseCDSect", "xmlParseContent", 159"xmlParseElement", "xmlParseVersionNum", "xmlParseVersionInfo", 160"xmlParseEncName", "xmlParseEncodingDecl", "xmlParseSDDecl", 161"xmlParseXMLDecl", "xmlParseTextDecl", "xmlParseMisc", 162"xmlParseExternalSubset", "xmlParserHandlePEReference", 163"xmlSkipBlankChars", 164] 165 166# 167# These functions have side effects on the global state 168# and hence generate errors on memory allocation tests 169# 170skipped_memcheck = [ "xmlLoadCatalog", "xmlAddEncodingAlias", 171 "xmlSchemaInitTypes", "xmlNanoFTPProxy", "xmlNanoFTPScanProxy", 172 "xmlNanoHTTPScanProxy", "xmlResetLastError", "xmlCatalogConvert", 173 "xmlCatalogRemove", "xmlLoadCatalogs", "xmlCleanupCharEncodingHandlers", 174 "xmlInitCharEncodingHandlers", "xmlCatalogCleanup", 175 "xmlSchemaGetBuiltInType", 176 "htmlParseFile", "htmlCtxtReadFile", # loads the catalogs 177 "xmlTextReaderSchemaValidate", "xmlSchemaCleanupTypes", # initialize the schemas type system 178 "xmlCatalogResolve", "xmlIOParseDTD" # loads the catalogs 179] 180 181# 182# Extra code needed for some test cases 183# 184extra_pre_call = { 185 "xmlSAXUserParseFile": """ 186#ifdef LIBXML_SAX1_ENABLED 187 if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL; 188#endif 189""", 190 "xmlSAXUserParseMemory": """ 191#ifdef LIBXML_SAX1_ENABLED 192 if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL; 193#endif 194""", 195 "xmlParseBalancedChunkMemory": """ 196#ifdef LIBXML_SAX1_ENABLED 197 if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL; 198#endif 199""", 200 "xmlParseBalancedChunkMemoryRecover": """ 201#ifdef LIBXML_SAX1_ENABLED 202 if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL; 203#endif 204""", 205 "xmlParserInputBufferCreateFd": 206 "if (fd >= 0) fd = -1;", 207} 208extra_post_call = { 209 "xmlAddChild": 210 "if (ret_val == NULL) { xmlFreeNode(cur) ; cur = NULL ; }", 211 "xmlAddEntity": 212 "if (ret_val != NULL) { xmlFreeNode(ret_val) ; ret_val = NULL; }", 213 "xmlAddChildList": 214 "if (ret_val == NULL) { xmlFreeNodeList(cur) ; cur = NULL ; }", 215 "xmlAddSibling": 216 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }", 217 "xmlAddNextSibling": 218 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }", 219 "xmlAddPrevSibling": 220 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }", 221 "xmlDocSetRootElement": 222 "if (doc == NULL) { xmlFreeNode(root) ; root = NULL ; }", 223 "xmlReplaceNode": 224 """if (cur != NULL) { 225 xmlUnlinkNode(cur); 226 xmlFreeNode(cur) ; cur = NULL ; } 227 if (old != NULL) { 228 xmlUnlinkNode(old); 229 xmlFreeNode(old) ; old = NULL ; } 230 ret_val = NULL;""", 231 "xmlTextMerge": 232 """if ((first != NULL) && (first->type != XML_TEXT_NODE)) { 233 xmlUnlinkNode(second); 234 xmlFreeNode(second) ; second = NULL ; }""", 235 "xmlBuildQName": 236 """if ((ret_val != NULL) && (ret_val != ncname) && 237 (ret_val != prefix) && (ret_val != memory)) 238 xmlFree(ret_val); 239 ret_val = NULL;""", 240 "xmlNewDocElementContent": 241 """xmlFreeDocElementContent(doc, ret_val); ret_val = NULL;""", 242 "xmlDictReference": "xmlDictFree(dict);", 243 # Functions which deallocates one of their parameters 244 "xmlXPathConvertBoolean": """val = NULL;""", 245 "xmlXPathConvertNumber": """val = NULL;""", 246 "xmlXPathConvertString": """val = NULL;""", 247 "xmlSaveFileTo": """buf = NULL;""", 248 "xmlSaveFormatFileTo": """buf = NULL;""", 249 "xmlIOParseDTD": "input = NULL;", 250 "xmlRemoveProp": "cur = NULL;", 251 "xmlNewNs": "if ((node == NULL) && (ret_val != NULL)) xmlFreeNs(ret_val);", 252 "xmlCopyNamespace": "if (ret_val != NULL) xmlFreeNs(ret_val);", 253 "xmlCopyNamespaceList": "if (ret_val != NULL) xmlFreeNsList(ret_val);", 254 "xmlNewTextWriter": "if (ret_val != NULL) out = NULL;", 255 "xmlNewTextWriterPushParser": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;} if (ret_val != NULL) ctxt = NULL;", 256 "xmlNewIOInputStream": "if (ret_val != NULL) input = NULL;", 257 "htmlParseChunk": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}", 258 "htmlParseDocument": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}", 259 "xmlParseDocument": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}", 260 "xmlParseChunk": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}", 261 "xmlParseExtParsedEnt": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}", 262 "xmlDOMWrapAdoptNode": "if ((node != NULL) && (node->parent == NULL)) {xmlUnlinkNode(node);xmlFreeNode(node);node = NULL;}", 263 "xmlBufferSetAllocationScheme": "if ((buf != NULL) && (scheme == XML_BUFFER_ALLOC_IMMUTABLE) && (buf->content != NULL) && (buf->content != static_buf_content)) { xmlFree(buf->content); buf->content = NULL;}" 264} 265 266modules = [] 267 268def is_skipped_module(name): 269 for mod in skipped_modules: 270 if mod == name: 271 return 1 272 return 0 273 274def is_skipped_function(name): 275 for fun in skipped_functions: 276 if fun == name: 277 return 1 278 # Do not test destructors 279 if string.find(name, 'Free') != -1: 280 return 1 281 return 0 282 283def is_skipped_memcheck(name): 284 for fun in skipped_memcheck: 285 if fun == name: 286 return 1 287 return 0 288 289missing_types = {} 290def add_missing_type(name, func): 291 try: 292 list = missing_types[name] 293 list.append(func) 294 except: 295 missing_types[name] = [func] 296 297generated_param_types = [] 298def add_generated_param_type(name): 299 generated_param_types.append(name) 300 301generated_return_types = [] 302def add_generated_return_type(name): 303 generated_return_types.append(name) 304 305missing_functions = {} 306missing_functions_nr = 0 307def add_missing_functions(name, module): 308 global missing_functions_nr 309 310 missing_functions_nr = missing_functions_nr + 1 311 try: 312 list = missing_functions[module] 313 list.append(name) 314 except: 315 missing_functions[module] = [name] 316 317# 318# Provide the type generators and destructors for the parameters 319# 320 321def type_convert(str, name, info, module, function, pos): 322# res = string.replace(str, " ", " ") 323# res = string.replace(str, " ", " ") 324# res = string.replace(str, " ", " ") 325 res = string.replace(str, " *", "_ptr") 326# res = string.replace(str, "*", "_ptr") 327 res = string.replace(res, " ", "_") 328 if res == 'const_char_ptr': 329 if string.find(name, "file") != -1 or \ 330 string.find(name, "uri") != -1 or \ 331 string.find(name, "URI") != -1 or \ 332 string.find(info, "filename") != -1 or \ 333 string.find(info, "URI") != -1 or \ 334 string.find(info, "URL") != -1: 335 if string.find(function, "Save") != -1 or \ 336 string.find(function, "Create") != -1 or \ 337 string.find(function, "Write") != -1 or \ 338 string.find(function, "Fetch") != -1: 339 return('fileoutput') 340 return('filepath') 341 if res == 'void_ptr': 342 if module == 'nanoftp' and name == 'ctx': 343 return('xmlNanoFTPCtxtPtr') 344 if function == 'xmlNanoFTPNewCtxt' or \ 345 function == 'xmlNanoFTPConnectTo' or \ 346 function == 'xmlNanoFTPOpen': 347 return('xmlNanoFTPCtxtPtr') 348 if module == 'nanohttp' and name == 'ctx': 349 return('xmlNanoHTTPCtxtPtr') 350 if function == 'xmlNanoHTTPMethod' or \ 351 function == 'xmlNanoHTTPMethodRedir' or \ 352 function == 'xmlNanoHTTPOpen' or \ 353 function == 'xmlNanoHTTPOpenRedir': 354 return('xmlNanoHTTPCtxtPtr'); 355 if function == 'xmlIOHTTPOpen': 356 return('xmlNanoHTTPCtxtPtr') 357 if string.find(name, "data") != -1: 358 return('userdata') 359 if string.find(name, "user") != -1: 360 return('userdata') 361 if res == 'xmlDoc_ptr': 362 res = 'xmlDocPtr' 363 if res == 'xmlNode_ptr': 364 res = 'xmlNodePtr' 365 if res == 'xmlDict_ptr': 366 res = 'xmlDictPtr' 367 if res == 'xmlNodePtr' and pos != 0: 368 if (function == 'xmlAddChild' and pos == 2) or \ 369 (function == 'xmlAddChildList' and pos == 2) or \ 370 (function == 'xmlAddNextSibling' and pos == 2) or \ 371 (function == 'xmlAddSibling' and pos == 2) or \ 372 (function == 'xmlDocSetRootElement' and pos == 2) or \ 373 (function == 'xmlReplaceNode' and pos == 2) or \ 374 (function == 'xmlTextMerge') or \ 375 (function == 'xmlAddPrevSibling' and pos == 2): 376 return('xmlNodePtr_in'); 377 if res == 'const xmlBufferPtr': 378 res = 'xmlBufferPtr' 379 if res == 'xmlChar_ptr' and name == 'name' and \ 380 string.find(function, "EatName") != -1: 381 return('eaten_name') 382 if res == 'void_ptr*': 383 res = 'void_ptr_ptr' 384 if res == 'char_ptr*': 385 res = 'char_ptr_ptr' 386 if res == 'xmlChar_ptr*': 387 res = 'xmlChar_ptr_ptr' 388 if res == 'const_xmlChar_ptr*': 389 res = 'const_xmlChar_ptr_ptr' 390 if res == 'const_char_ptr*': 391 res = 'const_char_ptr_ptr' 392 if res == 'FILE_ptr' and module == 'debugXML': 393 res = 'debug_FILE_ptr'; 394 if res == 'int' and name == 'options': 395 if module == 'parser' or module == 'xmlreader': 396 res = 'parseroptions' 397 398 return res 399 400known_param_types = [] 401 402def is_known_param_type(name, rtype): 403 global test 404 for type in known_param_types: 405 if type == name: 406 return 1 407 for type in generated_param_types: 408 if type == name: 409 return 1 410 411 if name[-3:] == 'Ptr' or name[-4:] == '_ptr': 412 if rtype[0:6] == 'const ': 413 crtype = rtype[6:] 414 else: 415 crtype = rtype 416 417 define = 0 418 if modules_defines.has_key(module): 419 test.write("#ifdef %s\n" % (modules_defines[module])) 420 define = 1 421 test.write(""" 422#define gen_nb_%s 1 423static %s gen_%s(int no ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) { 424 return(NULL); 425} 426static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) { 427} 428""" % (name, crtype, name, name, rtype)) 429 if define == 1: 430 test.write("#endif\n\n") 431 add_generated_param_type(name) 432 return 1 433 434 return 0 435 436# 437# Provide the type destructors for the return values 438# 439 440known_return_types = [] 441 442def is_known_return_type(name): 443 for type in known_return_types: 444 if type == name: 445 return 1 446 return 0 447 448# 449# Copy the beginning of the C test program result 450# 451 452try: 453 input = open("testapi.c", "r") 454except: 455 input = open(srcPref + "testapi.c", "r") 456test = open('testapi.c.new', 'w') 457 458def compare_and_save(): 459 global test 460 461 test.close() 462 try: 463 input = open("testapi.c", "r").read() 464 except: 465 input = '' 466 test = open('testapi.c.new', "r").read() 467 if input != test: 468 try: 469 os.system("rm testapi.c; mv testapi.c.new testapi.c") 470 except: 471 os.system("mv testapi.c.new testapi.c") 472 print("Updated testapi.c") 473 else: 474 print("Generated testapi.c is identical") 475 476line = input.readline() 477while line != "": 478 if line == "/* CUT HERE: everything below that line is generated */\n": 479 break; 480 if line[0:15] == "#define gen_nb_": 481 type = string.split(line[15:])[0] 482 known_param_types.append(type) 483 if line[0:19] == "static void desret_": 484 type = string.split(line[19:], '(')[0] 485 known_return_types.append(type) 486 test.write(line) 487 line = input.readline() 488input.close() 489 490if line == "": 491 print "Could not find the CUT marker in testapi.c skipping generation" 492 test.close() 493 sys.exit(0) 494 495print("Scanned testapi.c: found %d parameters types and %d return types\n" % ( 496 len(known_param_types), len(known_return_types))) 497test.write("/* CUT HERE: everything below that line is generated */\n") 498 499 500# 501# Open the input API description 502# 503doc = libxml2.readFile(srcPref + 'doc/libxml2-api.xml', None, 0) 504if doc == None: 505 print "Failed to load doc/libxml2-api.xml" 506 sys.exit(1) 507ctxt = doc.xpathNewContext() 508 509# 510# Generate a list of all function parameters and select only 511# those used in the api tests 512# 513argtypes = {} 514args = ctxt.xpathEval("/api/symbols/function/arg") 515for arg in args: 516 mod = arg.xpathEval('string(../@file)') 517 func = arg.xpathEval('string(../@name)') 518 if (mod not in skipped_modules) and (func not in skipped_functions): 519 type = arg.xpathEval('string(@type)') 520 if not argtypes.has_key(type): 521 argtypes[type] = func 522 523# similarly for return types 524rettypes = {} 525rets = ctxt.xpathEval("/api/symbols/function/return") 526for ret in rets: 527 mod = ret.xpathEval('string(../@file)') 528 func = ret.xpathEval('string(../@name)') 529 if (mod not in skipped_modules) and (func not in skipped_functions): 530 type = ret.xpathEval('string(@type)') 531 if not rettypes.has_key(type): 532 rettypes[type] = func 533 534# 535# Generate constructors and return type handling for all enums 536# which are used as function parameters 537# 538enums = ctxt.xpathEval("/api/symbols/typedef[@type='enum']") 539for enum in enums: 540 module = enum.xpathEval('string(@file)') 541 name = enum.xpathEval('string(@name)') 542 # 543 # Skip any enums which are not in our filtered lists 544 # 545 if (name == None) or ((name not in argtypes) and (name not in rettypes)): 546 continue; 547 define = 0 548 549 if argtypes.has_key(name) and is_known_param_type(name, name) == 0: 550 values = ctxt.xpathEval("/api/symbols/enum[@type='%s']" % name) 551 i = 0 552 vals = [] 553 for value in values: 554 vname = value.xpathEval('string(@name)') 555 if vname == None: 556 continue; 557 i = i + 1 558 if i >= 5: 559 break; 560 vals.append(vname) 561 if vals == []: 562 print "Didn't find any value for enum %s" % (name) 563 continue 564 if modules_defines.has_key(module): 565 test.write("#ifdef %s\n" % (modules_defines[module])) 566 define = 1 567 test.write("#define gen_nb_%s %d\n" % (name, len(vals))) 568 test.write("""static %s gen_%s(int no, int nr ATTRIBUTE_UNUSED) {\n""" % 569 (name, name)) 570 i = 1 571 for value in vals: 572 test.write(" if (no == %d) return(%s);\n" % (i, value)) 573 i = i + 1 574 test.write(""" return(0); 575} 576 577static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) { 578} 579 580""" % (name, name)); 581 known_param_types.append(name) 582 583 if (is_known_return_type(name) == 0) and (name in rettypes): 584 if define == 0 and modules_defines.has_key(module): 585 test.write("#ifdef %s\n" % (modules_defines[module])) 586 define = 1 587 test.write("""static void desret_%s(%s val ATTRIBUTE_UNUSED) { 588} 589 590""" % (name, name)) 591 known_return_types.append(name) 592 if define == 1: 593 test.write("#endif\n\n") 594 595# 596# Load the interfaces 597# 598headers = ctxt.xpathEval("/api/files/file") 599for file in headers: 600 name = file.xpathEval('string(@name)') 601 if (name == None) or (name == ''): 602 continue 603 604 # 605 # Some module may be skipped because they don't really consists 606 # of user callable APIs 607 # 608 if is_skipped_module(name): 609 continue 610 611 # 612 # do not test deprecated APIs 613 # 614 desc = file.xpathEval('string(description)') 615 if string.find(desc, 'DEPRECATED') != -1: 616 print "Skipping deprecated interface %s" % name 617 continue; 618 619 test.write("#include <libxml/%s.h>\n" % name) 620 modules.append(name) 621 622# 623# Generate the callers signatures 624# 625for module in modules: 626 test.write("static int test_%s(void);\n" % module); 627 628# 629# Generate the top caller 630# 631 632test.write(""" 633/** 634 * testlibxml2: 635 * 636 * Main entry point of the tester for the full libxml2 module, 637 * it calls all the tester entry point for each module. 638 * 639 * Returns the number of error found 640 */ 641static int 642testlibxml2(void) 643{ 644 int test_ret = 0; 645 646""") 647 648for module in modules: 649 test.write(" test_ret += test_%s();\n" % module) 650 651test.write(""" 652 printf("Total: %d functions, %d tests, %d errors\\n", 653 function_tests, call_tests, test_ret); 654 return(test_ret); 655} 656 657""") 658 659# 660# How to handle a function 661# 662nb_tests = 0 663 664def generate_test(module, node): 665 global test 666 global nb_tests 667 nb_cond = 0 668 no_gen = 0 669 670 name = node.xpathEval('string(@name)') 671 if is_skipped_function(name): 672 return 673 674 # 675 # check we know how to handle the args and return values 676 # and store the informations for the generation 677 # 678 try: 679 args = node.xpathEval("arg") 680 except: 681 args = [] 682 t_args = [] 683 n = 0 684 for arg in args: 685 n = n + 1 686 rtype = arg.xpathEval("string(@type)") 687 if rtype == 'void': 688 break; 689 info = arg.xpathEval("string(@info)") 690 nam = arg.xpathEval("string(@name)") 691 type = type_convert(rtype, nam, info, module, name, n) 692 if is_known_param_type(type, rtype) == 0: 693 add_missing_type(type, name); 694 no_gen = 1 695 if (type[-3:] == 'Ptr' or type[-4:] == '_ptr') and \ 696 rtype[0:6] == 'const ': 697 crtype = rtype[6:] 698 else: 699 crtype = rtype 700 t_args.append((nam, type, rtype, crtype, info)) 701 702 try: 703 rets = node.xpathEval("return") 704 except: 705 rets = [] 706 t_ret = None 707 for ret in rets: 708 rtype = ret.xpathEval("string(@type)") 709 info = ret.xpathEval("string(@info)") 710 type = type_convert(rtype, 'return', info, module, name, 0) 711 if rtype == 'void': 712 break 713 if is_known_return_type(type) == 0: 714 add_missing_type(type, name); 715 no_gen = 1 716 t_ret = (type, rtype, info) 717 break 718 719 test.write(""" 720static int 721test_%s(void) { 722 int test_ret = 0; 723 724""" % (name)) 725 726 if no_gen == 1: 727 add_missing_functions(name, module) 728 test.write(""" 729 /* missing type support */ 730 return(test_ret); 731} 732 733""") 734 return 735 736 try: 737 conds = node.xpathEval("cond") 738 for cond in conds: 739 test.write("#if %s\n" % (cond.get_content())) 740 nb_cond = nb_cond + 1 741 except: 742 pass 743 744 define = 0 745 if function_defines.has_key(name): 746 test.write("#ifdef %s\n" % (function_defines[name])) 747 define = 1 748 749 # Declare the memory usage counter 750 no_mem = is_skipped_memcheck(name) 751 if no_mem == 0: 752 test.write(" int mem_base;\n"); 753 754 # Declare the return value 755 if t_ret != None: 756 test.write(" %s ret_val;\n" % (t_ret[1])) 757 758 # Declare the arguments 759 for arg in t_args: 760 (nam, type, rtype, crtype, info) = arg; 761 # add declaration 762 test.write(" %s %s; /* %s */\n" % (crtype, nam, info)) 763 test.write(" int n_%s;\n" % (nam)) 764 test.write("\n") 765 766 # Cascade loop on of each argument list of values 767 for arg in t_args: 768 (nam, type, rtype, crtype, info) = arg; 769 # 770 test.write(" for (n_%s = 0;n_%s < gen_nb_%s;n_%s++) {\n" % ( 771 nam, nam, type, nam)) 772 773 # log the memory usage 774 if no_mem == 0: 775 test.write(" mem_base = xmlMemBlocks();\n"); 776 777 # prepare the call 778 i = 0; 779 for arg in t_args: 780 (nam, type, rtype, crtype, info) = arg; 781 # 782 test.write(" %s = gen_%s(n_%s, %d);\n" % (nam, type, nam, i)) 783 i = i + 1; 784 785 # do the call, and clanup the result 786 if extra_pre_call.has_key(name): 787 test.write(" %s\n"% (extra_pre_call[name])) 788 if t_ret != None: 789 test.write("\n ret_val = %s(" % (name)) 790 need = 0 791 for arg in t_args: 792 (nam, type, rtype, crtype, info) = arg 793 if need: 794 test.write(", ") 795 else: 796 need = 1 797 if rtype != crtype: 798 test.write("(%s)" % rtype) 799 test.write("%s" % nam); 800 test.write(");\n") 801 if extra_post_call.has_key(name): 802 test.write(" %s\n"% (extra_post_call[name])) 803 test.write(" desret_%s(ret_val);\n" % t_ret[0]) 804 else: 805 test.write("\n %s(" % (name)); 806 need = 0; 807 for arg in t_args: 808 (nam, type, rtype, crtype, info) = arg; 809 if need: 810 test.write(", ") 811 else: 812 need = 1 813 if rtype != crtype: 814 test.write("(%s)" % rtype) 815 test.write("%s" % nam) 816 test.write(");\n") 817 if extra_post_call.has_key(name): 818 test.write(" %s\n"% (extra_post_call[name])) 819 820 test.write(" call_tests++;\n"); 821 822 # Free the arguments 823 i = 0; 824 for arg in t_args: 825 (nam, type, rtype, crtype, info) = arg; 826 # This is a hack to prevent generating a destructor for the 827 # 'input' argument in xmlTextReaderSetup. There should be 828 # a better, more generic way to do this! 829 if string.find(info, 'destroy') == -1: 830 test.write(" des_%s(n_%s, " % (type, nam)) 831 if rtype != crtype: 832 test.write("(%s)" % rtype) 833 test.write("%s, %d);\n" % (nam, i)) 834 i = i + 1; 835 836 test.write(" xmlResetLastError();\n"); 837 # Check the memory usage 838 if no_mem == 0: 839 test.write(""" if (mem_base != xmlMemBlocks()) { 840 printf("Leak of %%d blocks found in %s", 841 xmlMemBlocks() - mem_base); 842 test_ret++; 843""" % (name)); 844 for arg in t_args: 845 (nam, type, rtype, crtype, info) = arg; 846 test.write(""" printf(" %%d", n_%s);\n""" % (nam)) 847 test.write(""" printf("\\n");\n""") 848 test.write(" }\n") 849 850 for arg in t_args: 851 test.write(" }\n") 852 853 test.write(" function_tests++;\n") 854 # 855 # end of conditional 856 # 857 while nb_cond > 0: 858 test.write("#endif\n") 859 nb_cond = nb_cond -1 860 if define == 1: 861 test.write("#endif\n") 862 863 nb_tests = nb_tests + 1; 864 865 test.write(""" 866 return(test_ret); 867} 868 869""") 870 871# 872# Generate all module callers 873# 874for module in modules: 875 # gather all the functions exported by that module 876 try: 877 functions = ctxt.xpathEval("/api/symbols/function[@file='%s']" % (module)) 878 except: 879 print "Failed to gather functions from module %s" % (module) 880 continue; 881 882 # iterate over all functions in the module generating the test 883 i = 0 884 nb_tests_old = nb_tests 885 for function in functions: 886 i = i + 1 887 generate_test(module, function); 888 889 # header 890 test.write("""static int 891test_%s(void) { 892 int test_ret = 0; 893 894 if (quiet == 0) printf("Testing %s : %d of %d functions ...\\n"); 895""" % (module, module, nb_tests - nb_tests_old, i)) 896 897 # iterate over all functions in the module generating the call 898 for function in functions: 899 name = function.xpathEval('string(@name)') 900 if is_skipped_function(name): 901 continue 902 test.write(" test_ret += test_%s();\n" % (name)) 903 904 # footer 905 test.write(""" 906 if (test_ret != 0) 907 printf("Module %s: %%d errors\\n", test_ret); 908 return(test_ret); 909} 910""" % (module)) 911 912# 913# Generate direct module caller 914# 915test.write("""static int 916test_module(const char *module) { 917"""); 918for module in modules: 919 test.write(""" if (!strcmp(module, "%s")) return(test_%s());\n""" % ( 920 module, module)) 921test.write(""" return(0); 922} 923"""); 924 925print "Generated test for %d modules and %d functions" %(len(modules), nb_tests) 926 927compare_and_save() 928 929missing_list = [] 930for missing in missing_types.keys(): 931 if missing == 'va_list' or missing == '...': 932 continue; 933 934 n = len(missing_types[missing]) 935 missing_list.append((n, missing)) 936 937def compare_missing(a, b): 938 return b[0] - a[0] 939 940missing_list.sort(compare_missing) 941print "Missing support for %d functions and %d types see missing.lst" % (missing_functions_nr, len(missing_list)) 942lst = open("missing.lst", "w") 943lst.write("Missing support for %d types" % (len(missing_list))) 944lst.write("\n") 945for miss in missing_list: 946 lst.write("%s: %d :" % (miss[1], miss[0])) 947 i = 0 948 for n in missing_types[miss[1]]: 949 i = i + 1 950 if i > 5: 951 lst.write(" ...") 952 break 953 lst.write(" %s" % (n)) 954 lst.write("\n") 955lst.write("\n") 956lst.write("\n") 957lst.write("Missing support per module"); 958for module in missing_functions.keys(): 959 lst.write("module %s:\n %s\n" % (module, missing_functions[module])) 960 961lst.close() 962 963 964