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