3 # generate a tester program for the API
11 print "libxml2 python bindings not available, skipping testapi.c generation"
15 srcPref = sys.argv[1] + '/'
20 # Modules we want to skip in API test
22 skipped_modules = [ "SAX", "xlink", "threads", "globals",
23 "xmlmemory", "xmlversion", "xmlexports",
29 # defines for each module
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",
53 # defines for specific functions
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",
107 # Some functions really need to be skipped for the tests.
109 skipped_functions = [
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",
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",
131 "xmlTextReaderReadInnerXml", "xmlTextReaderReadOuterXml",
132 "xmlTextReaderReadString",
134 "xmlListDelete", "xmlOutputBufferClose", "xmlNanoFTPClose", "xmlNanoHTTPClose",
136 "xmlCatalogGetPublic", "xmlCatalogGetSystem", "xmlEncodeEntities",
137 "xmlNewGlobalNs", "xmlHandleEntity", "xmlNamespaceParseNCName",
138 "xmlNamespaceParseNSDef", "xmlNamespaceParseQName",
139 "xmlParseNamespace", "xmlParseQuotedString", "xmlParserHandleReference",
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",
167 # These functions have side effects on the global state
168 # and hence generate errors on memory allocation tests
170 skipped_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
182 # Extra code needed for some test cases
185 "xmlSAXUserParseFile": """
186 #ifdef LIBXML_SAX1_ENABLED
187 if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;
190 "xmlSAXUserParseMemory": """
191 #ifdef LIBXML_SAX1_ENABLED
192 if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;
195 "xmlParseBalancedChunkMemory": """
196 #ifdef LIBXML_SAX1_ENABLED
197 if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;
200 "xmlParseBalancedChunkMemoryRecover": """
201 #ifdef LIBXML_SAX1_ENABLED
202 if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;
205 "xmlParserInputBufferCreateFd":
206 "if (fd >= 0) fd = -1;",
210 "if (ret_val == NULL) { xmlFreeNode(cur) ; cur = NULL ; }",
212 "if (ret_val != NULL) { xmlFreeNode(ret_val) ; ret_val = NULL; }",
214 "if (ret_val == NULL) { xmlFreeNodeList(cur) ; cur = NULL ; }",
216 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
218 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
220 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
221 "xmlDocSetRootElement":
222 "if (doc == NULL) { xmlFreeNode(root) ; root = NULL ; }",
224 """if (cur != NULL) {
226 xmlFreeNode(cur) ; cur = NULL ; }
229 xmlFreeNode(old) ; old = NULL ; }
232 """if ((first != NULL) && (first->type != XML_TEXT_NODE)) {
233 xmlUnlinkNode(second);
234 xmlFreeNode(second) ; second = NULL ; }""",
236 """if ((ret_val != NULL) && (ret_val != ncname) &&
237 (ret_val != prefix) && (ret_val != memory))
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;}"
268 def is_skipped_module(name):
269 for mod in skipped_modules:
274 def is_skipped_function(name):
275 for fun in skipped_functions:
278 # Do not test destructors
279 if string.find(name, 'Free') != -1:
283 def is_skipped_memcheck(name):
284 for fun in skipped_memcheck:
290 def add_missing_type(name, func):
292 list = missing_types[name]
295 missing_types[name] = [func]
297 generated_param_types = []
298 def add_generated_param_type(name):
299 generated_param_types.append(name)
301 generated_return_types = []
302 def add_generated_return_type(name):
303 generated_return_types.append(name)
305 missing_functions = {}
306 missing_functions_nr = 0
307 def add_missing_functions(name, module):
308 global missing_functions_nr
310 missing_functions_nr = missing_functions_nr + 1
312 list = missing_functions[module]
315 missing_functions[module] = [name]
318 # Provide the type generators and destructors for the parameters
321 def 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:
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:
359 if string.find(name, "user") != -1:
361 if res == 'xmlDoc_ptr':
363 if res == 'xmlNode_ptr':
365 if res == 'xmlDict_ptr':
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':
379 if res == 'xmlChar_ptr' and name == 'name' and \
380 string.find(function, "EatName") != -1:
382 if res == 'void_ptr*':
384 if res == 'char_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'
400 known_param_types = []
402 def is_known_param_type(name, rtype):
404 for type in known_param_types:
407 for type in generated_param_types:
411 if name[-3:] == 'Ptr' or name[-4:] == '_ptr':
412 if rtype[0:6] == 'const ':
418 if modules_defines.has_key(module):
419 test.write("#ifdef %s\n" % (modules_defines[module]))
423 static %s gen_%s(int no ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
426 static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
428 """ % (name, crtype, name, name, rtype))
430 test.write("#endif\n\n")
431 add_generated_param_type(name)
437 # Provide the type destructors for the return values
440 known_return_types = []
442 def is_known_return_type(name):
443 for type in known_return_types:
449 # Copy the beginning of the C test program result
453 input = open("testapi.c", "r")
455 input = open(srcPref + "testapi.c", "r")
456 test = open('testapi.c.new', 'w')
458 def compare_and_save():
463 input = open("testapi.c", "r").read()
466 test = open('testapi.c.new', "r").read()
469 os.system("rm testapi.c; mv testapi.c.new testapi.c")
471 os.system("mv testapi.c.new testapi.c")
472 print("Updated testapi.c")
474 print("Generated testapi.c is identical")
476 line = input.readline()
478 if line == "/* CUT HERE: everything below that line is generated */\n":
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)
487 line = input.readline()
491 print "Could not find the CUT marker in testapi.c skipping generation"
495 print("Scanned testapi.c: found %d parameters types and %d return types\n" % (
496 len(known_param_types), len(known_return_types)))
497 test.write("/* CUT HERE: everything below that line is generated */\n")
501 # Open the input API description
503 doc = libxml2.readFile(srcPref + 'doc/libxml2-api.xml', None, 0)
505 print "Failed to load doc/libxml2-api.xml"
507 ctxt = doc.xpathNewContext()
510 # Generate a list of all function parameters and select only
511 # those used in the api tests
514 args = ctxt.xpathEval("/api/symbols/function/arg")
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
523 # similarly for return types
525 rets = ctxt.xpathEval("/api/symbols/function/return")
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
535 # Generate constructors and return type handling for all enums
536 # which are used as function parameters
538 enums = ctxt.xpathEval("/api/symbols/typedef[@type='enum']")
540 module = enum.xpathEval('string(@file)')
541 name = enum.xpathEval('string(@name)')
543 # Skip any enums which are not in our filtered lists
545 if (name == None) or ((name not in argtypes) and (name not in rettypes)):
549 if argtypes.has_key(name) and is_known_param_type(name, name) == 0:
550 values = ctxt.xpathEval("/api/symbols/enum[@type='%s']" % name)
554 vname = value.xpathEval('string(@name)')
562 print "Didn't find any value for enum %s" % (name)
564 if modules_defines.has_key(module):
565 test.write("#ifdef %s\n" % (modules_defines[module]))
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""" %
572 test.write(" if (no == %d) return(%s);\n" % (i, value))
574 test.write(""" return(0);
577 static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
581 known_param_types.append(name)
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]))
587 test.write("""static void desret_%s(%s val ATTRIBUTE_UNUSED) {
591 known_return_types.append(name)
593 test.write("#endif\n\n")
596 # Load the interfaces
598 headers = ctxt.xpathEval("/api/files/file")
600 name = file.xpathEval('string(@name)')
601 if (name == None) or (name == ''):
605 # Some module may be skipped because they don't really consists
606 # of user callable APIs
608 if is_skipped_module(name):
612 # do not test deprecated APIs
614 desc = file.xpathEval('string(description)')
615 if string.find(desc, 'DEPRECATED') != -1:
616 print "Skipping deprecated interface %s" % name
619 test.write("#include <libxml/%s.h>\n" % name)
623 # Generate the callers signatures
625 for module in modules:
626 test.write("static int test_%s(void);\n" % module);
629 # Generate the top caller
636 * Main entry point of the tester for the full libxml2 module,
637 * it calls all the tester entry point for each module.
639 * Returns the number of error found
648 for module in modules:
649 test.write(" test_ret += test_%s();\n" % module)
652 printf("Total: %d functions, %d tests, %d errors\\n",
653 function_tests, call_tests, test_ret);
660 # How to handle a function
664 def generate_test(module, node):
670 name = node.xpathEval('string(@name)')
671 if is_skipped_function(name):
675 # check we know how to handle the args and return values
676 # and store the informations for the generation
679 args = node.xpathEval("arg")
686 rtype = arg.xpathEval("string(@type)")
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);
695 if (type[-3:] == 'Ptr' or type[-4:] == '_ptr') and \
696 rtype[0:6] == 'const ':
700 t_args.append((nam, type, rtype, crtype, info))
703 rets = node.xpathEval("return")
708 rtype = ret.xpathEval("string(@type)")
709 info = ret.xpathEval("string(@info)")
710 type = type_convert(rtype, 'return', info, module, name, 0)
713 if is_known_return_type(type) == 0:
714 add_missing_type(type, name);
716 t_ret = (type, rtype, info)
727 add_missing_functions(name, module)
729 /* missing type support */
737 conds = node.xpathEval("cond")
739 test.write("#if %s\n" % (cond.get_content()))
740 nb_cond = nb_cond + 1
745 if function_defines.has_key(name):
746 test.write("#ifdef %s\n" % (function_defines[name]))
749 # Declare the memory usage counter
750 no_mem = is_skipped_memcheck(name)
752 test.write(" int mem_base;\n");
754 # Declare the return value
756 test.write(" %s ret_val;\n" % (t_ret[1]))
758 # Declare the arguments
760 (nam, type, rtype, crtype, info) = arg;
762 test.write(" %s %s; /* %s */\n" % (crtype, nam, info))
763 test.write(" int n_%s;\n" % (nam))
766 # Cascade loop on of each argument list of values
768 (nam, type, rtype, crtype, info) = arg;
770 test.write(" for (n_%s = 0;n_%s < gen_nb_%s;n_%s++) {\n" % (
771 nam, nam, type, nam))
773 # log the memory usage
775 test.write(" mem_base = xmlMemBlocks();\n");
780 (nam, type, rtype, crtype, info) = arg;
782 test.write(" %s = gen_%s(n_%s, %d);\n" % (nam, type, nam, i))
785 # add checks to avoid out-of-bounds array access
788 (nam, type, rtype, crtype, info) = arg;
789 # assume that "size", "len", and "start" parameters apply to either
790 # the nearest preceding or following char pointer
791 if type == "int" and (nam == "size" or nam == "len" or nam == "start"):
792 for j in range(i - 1, -1, -1) + range(i + 1, len(t_args)):
793 (bnam, btype) = t_args[j][:2]
794 if btype == "const_char_ptr" or btype == "const_xmlChar_ptr":
796 " if ((%s != NULL) &&\n"
797 " (%s > (int) strlen((const char *) %s) + 1))\n"
803 # do the call, and clanup the result
804 if extra_pre_call.has_key(name):
805 test.write(" %s\n"% (extra_pre_call[name]))
807 test.write("\n ret_val = %s(" % (name))
810 (nam, type, rtype, crtype, info) = arg
816 test.write("(%s)" % rtype)
817 test.write("%s" % nam);
819 if extra_post_call.has_key(name):
820 test.write(" %s\n"% (extra_post_call[name]))
821 test.write(" desret_%s(ret_val);\n" % t_ret[0])
823 test.write("\n %s(" % (name));
826 (nam, type, rtype, crtype, info) = arg;
832 test.write("(%s)" % rtype)
833 test.write("%s" % nam)
835 if extra_post_call.has_key(name):
836 test.write(" %s\n"% (extra_post_call[name]))
838 test.write(" call_tests++;\n");
843 (nam, type, rtype, crtype, info) = arg;
844 # This is a hack to prevent generating a destructor for the
845 # 'input' argument in xmlTextReaderSetup. There should be
846 # a better, more generic way to do this!
847 if string.find(info, 'destroy') == -1:
848 test.write(" des_%s(n_%s, " % (type, nam))
850 test.write("(%s)" % rtype)
851 test.write("%s, %d);\n" % (nam, i))
854 test.write(" xmlResetLastError();\n");
855 # Check the memory usage
857 test.write(""" if (mem_base != xmlMemBlocks()) {
858 printf("Leak of %%d blocks found in %s",
859 xmlMemBlocks() - mem_base);
863 (nam, type, rtype, crtype, info) = arg;
864 test.write(""" printf(" %%d", n_%s);\n""" % (nam))
865 test.write(""" printf("\\n");\n""")
871 test.write(" function_tests++;\n")
876 test.write("#endif\n")
879 test.write("#endif\n")
881 nb_tests = nb_tests + 1;
890 # Generate all module callers
892 for module in modules:
893 # gather all the functions exported by that module
895 functions = ctxt.xpathEval("/api/symbols/function[@file='%s']" % (module))
897 print "Failed to gather functions from module %s" % (module)
900 # iterate over all functions in the module generating the test
902 nb_tests_old = nb_tests
903 for function in functions:
905 generate_test(module, function);
908 test.write("""static int
912 if (quiet == 0) printf("Testing %s : %d of %d functions ...\\n");
913 """ % (module, module, nb_tests - nb_tests_old, i))
915 # iterate over all functions in the module generating the call
916 for function in functions:
917 name = function.xpathEval('string(@name)')
918 if is_skipped_function(name):
920 test.write(" test_ret += test_%s();\n" % (name))
925 printf("Module %s: %%d errors\\n", test_ret);
931 # Generate direct module caller
933 test.write("""static int
934 test_module(const char *module) {
936 for module in modules:
937 test.write(""" if (!strcmp(module, "%s")) return(test_%s());\n""" % (
939 test.write(""" return(0);
943 print "Generated test for %d modules and %d functions" %(len(modules), nb_tests)
948 for missing in missing_types.keys():
949 if missing == 'va_list' or missing == '...':
952 n = len(missing_types[missing])
953 missing_list.append((n, missing))
955 def compare_missing(a, b):
958 missing_list.sort(compare_missing)
959 print "Missing support for %d functions and %d types see missing.lst" % (missing_functions_nr, len(missing_list))
960 lst = open("missing.lst", "w")
961 lst.write("Missing support for %d types" % (len(missing_list)))
963 for miss in missing_list:
964 lst.write("%s: %d :" % (miss[1], miss[0]))
966 for n in missing_types[miss[1]]:
971 lst.write(" %s" % (n))
975 lst.write("Missing support per module");
976 for module in missing_functions.keys():
977 lst.write("module %s:\n %s\n" % (module, missing_functions[module]))