VirtualBox

source: vbox/trunk/src/libs/libxml2-2.12.6/gentest.py

Last change on this file was 104106, checked in by vboxsync, 8 weeks ago

libxml2-2.9.14: Applied and adjusted our libxml2 changes to 2.9.14. bugref:10640

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

© 2023 Oracle
ContactPrivacy policyTerms of Use