VirtualBox

source: vbox/trunk/src/libs/libxml2-2.13.2/gentest.py@ 106580

Last change on this file since 106580 was 105420, checked in by vboxsync, 4 months ago

libxml2-2.12.6: Applied and adjusted our libxml2 changes to 2.12.6. bugref:10730

  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 30.1 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 "xmlAddChildList":
217 "if (ret_val == NULL) { xmlFreeNodeList(cur) ; cur = NULL ; }",
218 "xmlAddSibling":
219 "if (ret_val == NULL) { xmlFreeNode(cur) ; cur = NULL ; }",
220 "xmlAddNextSibling":
221 "if (ret_val == NULL) { xmlFreeNode(cur) ; cur = NULL ; }",
222 "xmlAddPrevSibling":
223 "if (ret_val == NULL) { xmlFreeNode(cur) ; cur = NULL ; }",
224 "xmlDocSetRootElement":
225 "if (doc == NULL) { xmlFreeNode(root) ; root = NULL ; }",
226 "xmlReplaceNode":
227 """if (cur != NULL) {
228 xmlUnlinkNode(cur);
229 xmlFreeNode(cur) ; cur = NULL ; }
230 if (old != NULL) {
231 xmlUnlinkNode(old);
232 xmlFreeNode(old) ; old = NULL ; }
233\t ret_val = NULL;""",
234 "xmlTextMerge":
235 """if (ret_val == NULL) {
236 xmlUnlinkNode(second);
237 xmlFreeNode(second) ; second = NULL ;
238 ret_val = first; }""",
239 "xmlBuildQName":
240 """if ((ret_val != NULL) && (ret_val != ncname) &&
241 (ret_val != prefix) && (ret_val != memory))
242 xmlFree(ret_val);
243\t ret_val = NULL;""",
244 "xmlNewDocElementContent":
245 """xmlFreeDocElementContent(doc, ret_val); ret_val = NULL;""",
246 "xmlDictReference": "xmlDictFree(dict);",
247 # Functions which deallocates one of their parameters
248 "xmlXPathConvertBoolean": """val = NULL;""",
249 "xmlXPathConvertNumber": """val = NULL;""",
250 "xmlXPathConvertString": """val = NULL;""",
251 "xmlSaveFileTo": """buf = NULL;""",
252 "xmlSaveFormatFileTo": """buf = NULL;""",
253 "xmlIOParseDTD": "input = NULL;",
254 "xmlRemoveProp": "cur = NULL;",
255 "xmlNewNs": "if ((node == NULL) && (ret_val != NULL)) xmlFreeNs(ret_val);",
256 "xmlCopyNamespace": "if (ret_val != NULL) xmlFreeNs(ret_val);",
257 "xmlCopyNamespaceList": "if (ret_val != NULL) xmlFreeNsList(ret_val);",
258 "xmlNewTextWriter": "if (ret_val != NULL) out = NULL;",
259 "xmlNewTextWriterPushParser": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;} if (ret_val != NULL) ctxt = NULL;",
260 "xmlNewIOInputStream": "if (ret_val != NULL) buf = NULL;",
261 "htmlParseChunk": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}",
262 "htmlParseDocument": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}",
263 "xmlParseDocument": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}",
264 "xmlParseChunk": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}",
265 "xmlParseExtParsedEnt": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}",
266 "xmlDOMWrapAdoptNode": "if ((node != NULL) && (node->parent == NULL)) {xmlUnlinkNode(node);xmlFreeNode(node);node = NULL;}",
267 "xmlSAXDefaultVersion": """
268 (void)xmlSAXDefaultVersion(original_version);
269 }
270""",
271}
272
273modules = []
274
275def is_skipped_module(name):
276 for mod in skipped_modules:
277 if mod == name:
278 return 1
279 return 0
280
281def is_skipped_function(name):
282 for fun in skipped_functions:
283 if fun == name:
284 return 1
285 # Do not test destructors
286 if name.find('Free') != -1:
287 return 1
288 return 0
289
290def is_skipped_memcheck(name):
291 for fun in skipped_memcheck:
292 if fun == name:
293 return 1
294 return 0
295
296missing_types = {}
297def add_missing_type(name, func):
298 try:
299 list = missing_types[name]
300 list.append(func)
301 except:
302 missing_types[name] = [func]
303
304generated_param_types = []
305def add_generated_param_type(name):
306 generated_param_types.append(name)
307
308generated_return_types = []
309def add_generated_return_type(name):
310 generated_return_types.append(name)
311
312missing_functions = {}
313missing_functions_nr = 0
314def add_missing_functions(name, module):
315 global missing_functions_nr
316
317 missing_functions_nr = missing_functions_nr + 1
318 try:
319 list = missing_functions[module]
320 list.append(name)
321 except:
322 missing_functions[module] = [name]
323
324#
325# Provide the type generators and destructors for the parameters
326#
327
328def type_convert(str, name, info, module, function, pos):
329# res = str.replace(" ", " ")
330# res = str.replace(" ", " ")
331# res = str.replace(" ", " ")
332 res = str.replace(" *", "_ptr")
333# res = str.replace("*", "_ptr")
334 res = res.replace(" ", "_")
335 if res == 'const_char_ptr':
336 if name.find("file") != -1 or \
337 name.find("uri") != -1 or \
338 name.find("URI") != -1 or \
339 info.find("filename") != -1 or \
340 info.find("URI") != -1 or \
341 info.find("URL") != -1:
342 if function.find("Save") != -1 or \
343 function.find("Create") != -1 or \
344 function.find("Write") != -1 or \
345 function.find("Fetch") != -1:
346 return('fileoutput')
347 return('filepath')
348 if res == 'void_ptr':
349 if module == 'nanoftp' and name == 'ctx':
350 return('xmlNanoFTPCtxtPtr')
351 if function == 'xmlNanoFTPNewCtxt' or \
352 function == 'xmlNanoFTPConnectTo' or \
353 function == 'xmlNanoFTPOpen':
354 return('xmlNanoFTPCtxtPtr')
355 if module == 'nanohttp' and name == 'ctx':
356 return('xmlNanoHTTPCtxtPtr')
357 if function == 'xmlNanoHTTPMethod' or \
358 function == 'xmlNanoHTTPMethodRedir' or \
359 function == 'xmlNanoHTTPOpen' or \
360 function == 'xmlNanoHTTPOpenRedir':
361 return('xmlNanoHTTPCtxtPtr');
362 if function == 'xmlIOHTTPOpen':
363 return('xmlNanoHTTPCtxtPtr')
364 if name.find("data") != -1:
365 return('userdata')
366 if name.find("user") != -1:
367 return('userdata')
368 if res == 'xmlDoc_ptr':
369 res = 'xmlDocPtr'
370 if res == 'xmlNode_ptr':
371 res = 'xmlNodePtr'
372 if res == 'xmlDict_ptr':
373 res = 'xmlDictPtr'
374 if res == 'xmlNodePtr' and pos != 0:
375 if (function == 'xmlAddChild' and pos == 2) or \
376 (function == 'xmlAddChildList' and pos == 2) or \
377 (function == 'xmlAddNextSibling' and pos == 2) or \
378 (function == 'xmlAddSibling' and pos == 2) or \
379 (function == 'xmlDocSetRootElement' and pos == 2) or \
380 (function == 'xmlReplaceNode' and pos == 2) or \
381 (function == 'xmlTextMerge') or \
382 (function == 'xmlAddPrevSibling' and pos == 2):
383 return('xmlNodePtr_in');
384 if res == 'const xmlBufferPtr':
385 res = 'xmlBufferPtr'
386 if res == 'xmlChar_ptr' and name == 'name' and \
387 function.find("EatName") != -1:
388 return('eaten_name')
389 if res == 'void_ptr*':
390 res = 'void_ptr_ptr'
391 if res == 'char_ptr*':
392 res = 'char_ptr_ptr'
393 if res == 'xmlChar_ptr*':
394 res = 'xmlChar_ptr_ptr'
395 if res == 'const_xmlChar_ptr*':
396 res = 'const_xmlChar_ptr_ptr'
397 if res == 'const_char_ptr*':
398 res = 'const_char_ptr_ptr'
399 if res == 'FILE_ptr' and module == 'debugXML':
400 res = 'debug_FILE_ptr';
401 if res == 'int' and name == 'options':
402 if module == 'parser' or module == 'xmlreader':
403 res = 'parseroptions'
404
405 return res
406
407known_param_types = []
408
409def is_known_param_type(name):
410 for type in known_param_types:
411 if type == name:
412 return 1
413 return name[-3:] == 'Ptr' or name[-4:] == '_ptr'
414
415def generate_param_type(name, rtype):
416 global test
417 for type in known_param_types:
418 if type == name:
419 return
420 for type in generated_param_types:
421 if type == name:
422 return
423
424 if name[-3:] == 'Ptr' or name[-4:] == '_ptr':
425 define = 0
426 if module in modules_defines:
427 test.write("#ifdef %s\n" % (modules_defines[module]))
428 define = 1
429 test.write("""
430#define gen_nb_%s 1
431#define gen_%s(no, nr) NULL
432#define des_%s(no, val, nr)
433""" % (name, name, name))
434 if define == 1:
435 test.write("#endif\n\n")
436 add_generated_param_type(name)
437
438#
439# Provide the type destructors for the return values
440#
441
442known_return_types = []
443
444def is_known_return_type(name):
445 for type in known_return_types:
446 if type == name:
447 return 1
448 return 0
449
450#
451# Copy the beginning of the C test program result
452#
453
454try:
455 input = open("testapi.c", "r")
456except:
457 input = open(srcPref + "testapi.c", "r")
458test = open('testapi.c.new', 'w')
459
460def compare_and_save():
461 global test
462
463 test.close()
464 try:
465 input = open("testapi.c", "r").read()
466 except:
467 input = ''
468 test = open('testapi.c.new', "r").read()
469 if input != test:
470 try:
471 os.system("rm testapi.c; mv testapi.c.new testapi.c")
472 except:
473 os.system("mv testapi.c.new testapi.c")
474 print("Updated testapi.c")
475 else:
476 print("Generated testapi.c is identical")
477
478line = input.readline()
479while line != "":
480 if line == "/* CUT HERE: everything below that line is generated */\n":
481 break;
482 if line[0:15] == "#define gen_nb_":
483 type = line[15:].split()[0]
484 known_param_types.append(type)
485 if line[0:19] == "static void desret_":
486 type = line[19:].split('(')[0]
487 known_return_types.append(type)
488 test.write(line)
489 line = input.readline()
490input.close()
491
492if line == "":
493 print("Could not find the CUT marker in testapi.c skipping generation")
494 test.close()
495 sys.exit(0)
496
497print("Scanned testapi.c: found %d parameters types and %d return types\n" % (
498 len(known_param_types), len(known_return_types)))
499test.write("/* CUT HERE: everything below that line is generated */\n")
500
501
502#
503# Open the input API description
504#
505doc = libxml2.readFile(srcPref + 'doc/libxml2-api.xml', None, 0)
506if doc == None:
507 print("Failed to load doc/libxml2-api.xml")
508 sys.exit(1)
509ctxt = doc.xpathNewContext()
510
511#
512# Generate a list of all function parameters and select only
513# those used in the api tests
514#
515argtypes = {}
516args = ctxt.xpathEval("/api/symbols/function/arg")
517for arg in args:
518 mod = arg.xpathEval('string(../@file)')
519 func = arg.xpathEval('string(../@name)')
520 if (mod not in skipped_modules) and (func not in skipped_functions):
521 type = arg.xpathEval('string(@type)')
522 if type not in argtypes:
523 argtypes[type] = func
524
525# similarly for return types
526rettypes = {}
527rets = ctxt.xpathEval("/api/symbols/function/return")
528for ret in rets:
529 mod = ret.xpathEval('string(../@file)')
530 func = ret.xpathEval('string(../@name)')
531 if (mod not in skipped_modules) and (func not in skipped_functions):
532 type = ret.xpathEval('string(@type)')
533 if type not in rettypes:
534 rettypes[type] = func
535
536#
537# Generate constructors and return type handling for all enums
538# which are used as function parameters
539#
540enums = ctxt.xpathEval("/api/symbols/typedef[@type='enum']")
541for enum in enums:
542 module = enum.xpathEval('string(@file)')
543 name = enum.xpathEval('string(@name)')
544 #
545 # Skip any enums which are not in our filtered lists
546 #
547 if (name == None) or ((name not in argtypes) and (name not in rettypes)):
548 continue;
549 define = 0
550
551 if (name in argtypes) and is_known_param_type(name) == 0:
552 values = ctxt.xpathEval("/api/symbols/enum[@type='%s']" % name)
553 i = 0
554 vals = []
555 for value in values:
556 vname = value.xpathEval('string(@name)')
557 if vname == None:
558 continue;
559 i = i + 1
560 if i >= 5:
561 break;
562 vals.append(vname)
563 if vals == []:
564 print("Didn't find any value for enum %s" % (name))
565 continue
566 if module in modules_defines:
567 test.write("#ifdef %s\n" % (modules_defines[module]))
568 define = 1
569 test.write("#define gen_nb_%s %d\n" % (name, len(vals)))
570 test.write("""static %s gen_%s(int no, int nr ATTRIBUTE_UNUSED) {\n""" %
571 (name, name))
572 i = 1
573 for value in vals:
574 test.write(" if (no == %d) return(%s);\n" % (i, value))
575 i = i + 1
576 test.write(""" return(0);
577}
578
579static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
580}
581
582""" % (name, name));
583 known_param_types.append(name)
584
585 if (is_known_return_type(name) == 0) and (name in rettypes):
586 if define == 0 and (module in modules_defines):
587 test.write("#ifdef %s\n" % (modules_defines[module]))
588 define = 1
589 test.write("""static void desret_%s(%s val ATTRIBUTE_UNUSED) {
590}
591
592""" % (name, name))
593 known_return_types.append(name)
594 if define == 1:
595 test.write("#endif\n\n")
596
597#
598# Load the interfaces
599#
600headers = ctxt.xpathEval("/api/files/file")
601for file in headers:
602 name = file.xpathEval('string(@name)')
603 if (name == None) or (name == ''):
604 continue
605
606 #
607 # Some module may be skipped because they don't really consists
608 # of user callable APIs
609 #
610 if is_skipped_module(name):
611 continue
612
613 #
614 # do not test deprecated APIs
615 #
616 desc = file.xpathEval('string(description)')
617 if desc.find('DEPRECATED') != -1:
618 print("Skipping deprecated interface %s" % name)
619 continue;
620
621 test.write("#include <libxml/%s.h>\n" % name)
622 modules.append(name)
623
624#
625# Generate the callers signatures
626#
627for module in modules:
628 test.write("static int test_%s(void);\n" % module);
629
630#
631# Generate the top caller
632#
633
634test.write("""
635/**
636 * testlibxml2:
637 *
638 * Main entry point of the tester for the full libxml2 module,
639 * it calls all the tester entry point for each module.
640 *
641 * Returns the number of error found
642 */
643static int
644testlibxml2(void)
645{
646 int test_ret = 0;
647
648""")
649
650for module in modules:
651 test.write(" test_ret += test_%s();\n" % module)
652
653test.write("""
654 printf("Total: %d functions, %d tests, %d errors\\n",
655 function_tests, call_tests, test_ret);
656 return(test_ret);
657}
658
659""")
660
661#
662# How to handle a function
663#
664nb_tests = 0
665
666def generate_test(module, node):
667 global test
668 global nb_tests
669 nb_cond = 0
670 no_gen = 0
671
672 name = node.xpathEval('string(@name)')
673 if is_skipped_function(name):
674 return
675
676 #
677 # check we know how to handle the args and return values
678 # and store the information for the generation
679 #
680 try:
681 args = node.xpathEval("arg")
682 except:
683 args = []
684 t_args = []
685 n = 0
686 for arg in args:
687 n = n + 1
688 rtype = arg.xpathEval("string(@type)")
689 if rtype == 'void':
690 break;
691 info = arg.xpathEval("string(@info)")
692 nam = arg.xpathEval("string(@name)")
693 type = type_convert(rtype, nam, info, module, name, n)
694 if is_known_param_type(type) == 0:
695 add_missing_type(type, name);
696 no_gen = 1
697 t_args.append((nam, type, rtype, info))
698
699 try:
700 rets = node.xpathEval("return")
701 except:
702 rets = []
703 t_ret = None
704 for ret in rets:
705 rtype = ret.xpathEval("string(@type)")
706 info = ret.xpathEval("string(@info)")
707 type = type_convert(rtype, 'return', info, module, name, 0)
708 if rtype == 'void':
709 break
710 if is_known_return_type(type) == 0:
711 add_missing_type(type, name);
712 no_gen = 1
713 t_ret = (type, rtype, info)
714 break
715
716 if no_gen == 0:
717 for t_arg in t_args:
718 (nam, type, rtype, info) = t_arg
719 generate_param_type(type, rtype)
720
721 test.write("""
722static int
723test_%s(void) {
724 int test_ret = 0;
725
726""" % (name))
727
728 if no_gen == 1:
729 add_missing_functions(name, module)
730 test.write("""
731 /* missing type support */
732 return(test_ret);
733}
734
735""")
736 return
737
738 try:
739 conds = node.xpathEval("cond")
740 for cond in conds:
741 test.write("#if %s\n" % (cond.get_content()))
742 nb_cond = nb_cond + 1
743 except:
744 pass
745
746 define = 0
747 if name in function_defines:
748 test.write("#ifdef %s\n" % (function_defines[name]))
749 define = 1
750
751 # Declare the memory usage counter
752 no_mem = is_skipped_memcheck(name)
753 if no_mem == 0:
754 test.write(" int mem_base;\n");
755
756 # Declare the return value
757 if t_ret != None:
758 test.write(" %s ret_val;\n" % (t_ret[1]))
759
760 # Declare the arguments
761 for arg in t_args:
762 (nam, type, rtype, info) = arg;
763 # add declaration
764 test.write(" %s %s; /* %s */\n" % (rtype, nam, info))
765 test.write(" int n_%s;\n" % (nam))
766 test.write("\n")
767
768 # Cascade loop on of each argument list of values
769 for arg in t_args:
770 (nam, type, rtype, info) = arg;
771 #
772 test.write(" for (n_%s = 0;n_%s < gen_nb_%s;n_%s++) {\n" % (
773 nam, nam, type, nam))
774
775 # log the memory usage
776 if no_mem == 0:
777 test.write(" mem_base = xmlMemBlocks();\n");
778
779 # prepare the call
780 i = 0;
781 for arg in t_args:
782 (nam, type, rtype, info) = arg;
783 #
784 test.write(" %s = gen_%s(n_%s, %d);\n" % (nam, type, nam, i))
785 i = i + 1;
786
787 # add checks to avoid out-of-bounds array access
788 i = 0;
789 for arg in t_args:
790 (nam, type, rtype, info) = arg;
791 # assume that "size", "len", and "start" parameters apply to either
792 # the nearest preceding or following char pointer
793 if type == "int" and (nam == "size" or nam == "len" or nam == "start"):
794 for j in (list(range(i - 1, -1, -1)) + list(range(i + 1, len(t_args)))):
795 (bnam, btype) = t_args[j][:2]
796 if btype == "const_char_ptr" or btype == "const_xmlChar_ptr":
797 test.write(
798 " if ((%s != NULL) &&\n"
799 " (%s > xmlStrlen(BAD_CAST %s)))\n"
800 " %s = 0;\n"
801 % (bnam, nam, bnam, nam))
802 break
803 i = i + 1;
804
805 # do the call, and clanup the result
806 if name in extra_pre_call:
807 test.write(" %s\n"% (extra_pre_call[name]))
808 if t_ret != None:
809 test.write("\n ret_val = %s(" % (name))
810 need = 0
811 for arg in t_args:
812 (nam, type, rtype, info) = arg
813 if need:
814 test.write(", ")
815 else:
816 need = 1
817 test.write("%s" % nam);
818 test.write(");\n")
819 if name in extra_post_call:
820 test.write(" %s\n"% (extra_post_call[name]))
821 test.write(" desret_%s(ret_val);\n" % t_ret[0])
822 else:
823 test.write("\n %s(" % (name));
824 need = 0;
825 for arg in t_args:
826 (nam, type, rtype, info) = arg;
827 if need:
828 test.write(", ")
829 else:
830 need = 1
831 test.write("%s" % nam)
832 test.write(");\n")
833 if name in extra_post_call:
834 test.write(" %s\n"% (extra_post_call[name]))
835
836 test.write(" call_tests++;\n");
837
838 # Free the arguments
839 i = 0;
840 for arg in t_args:
841 (nam, type, rtype, info) = arg;
842 # This is a hack to prevent generating a destructor for the
843 # 'input' argument in xmlTextReaderSetup. There should be
844 # a better, more generic way to do this!
845 if info.find('destroy') == -1:
846 test.write(" des_%s(n_%s, " % (type, nam))
847 test.write("%s, %d);\n" % (nam, i))
848 i = i + 1;
849
850 test.write(" xmlResetLastError();\n");
851 # Check the memory usage
852 if no_mem == 0:
853 test.write(""" if (mem_base != xmlMemBlocks()) {
854 printf("Leak of %%d blocks found in %s",
855\t xmlMemBlocks() - mem_base);
856\t test_ret++;
857""" % (name));
858 for arg in t_args:
859 (nam, type, rtype, info) = arg;
860 test.write(""" printf(" %%d", n_%s);\n""" % (nam))
861 test.write(""" printf("\\n");\n""")
862 test.write(" }\n")
863
864 for arg in t_args:
865 test.write(" }\n")
866
867 test.write(" function_tests++;\n")
868 #
869 # end of conditional
870 #
871 while nb_cond > 0:
872 test.write("#endif\n")
873 nb_cond = nb_cond -1
874 if define == 1:
875 test.write("#endif\n")
876
877 nb_tests = nb_tests + 1;
878
879 test.write("""
880 return(test_ret);
881}
882
883""")
884
885#
886# Generate all module callers
887#
888for module in modules:
889 # gather all the functions exported by that module
890 try:
891 functions = ctxt.xpathEval("/api/symbols/function[@file='%s']" % (module))
892 except:
893 print("Failed to gather functions from module %s" % (module))
894 continue;
895
896 # iterate over all functions in the module generating the test
897 i = 0
898 nb_tests_old = nb_tests
899 for function in functions:
900 i = i + 1
901 generate_test(module, function);
902
903 # header
904 test.write("""static int
905test_%s(void) {
906 int test_ret = 0;
907
908 if (quiet == 0) printf("Testing %s : %d of %d functions ...\\n");
909""" % (module, module, nb_tests - nb_tests_old, i))
910
911 # iterate over all functions in the module generating the call
912 for function in functions:
913 name = function.xpathEval('string(@name)')
914 if is_skipped_function(name):
915 continue
916 test.write(" test_ret += test_%s();\n" % (name))
917
918 # footer
919 test.write("""
920 if (test_ret != 0)
921\tprintf("Module %s: %%d errors\\n", test_ret);
922 return(test_ret);
923}
924""" % (module))
925
926#
927# Generate direct module caller
928#
929test.write("""static int
930test_module(const char *module) {
931""");
932for module in modules:
933 test.write(""" if (!strcmp(module, "%s")) return(test_%s());\n""" % (
934 module, module))
935test.write(""" return(0);
936}
937""");
938
939print("Generated test for %d modules and %d functions" %(len(modules), nb_tests))
940
941compare_and_save()
942
943missing_list = []
944for missing in missing_types.keys():
945 if missing == 'va_list' or missing == '...':
946 continue;
947
948 n = len(missing_types[missing])
949 missing_list.append((n, missing))
950
951missing_list.sort(key=lambda a: a[0])
952print("Missing support for %d functions and %d types see missing.lst" % (missing_functions_nr, len(missing_list)))
953lst = open("missing.lst", "w")
954lst.write("Missing support for %d types" % (len(missing_list)))
955lst.write("\n")
956for miss in missing_list:
957 lst.write("%s: %d :" % (miss[1], miss[0]))
958 i = 0
959 for n in missing_types[miss[1]]:
960 i = i + 1
961 if i > 5:
962 lst.write(" ...")
963 break
964 lst.write(" %s" % (n))
965 lst.write("\n")
966lst.write("\n")
967lst.write("\n")
968lst.write("Missing support per module");
969for module in missing_functions.keys():
970 lst.write("module %s:\n %s\n" % (module, missing_functions[module]))
971
972lst.close()
973
974
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette