source: trunk/third/libxml2/gentest.py @ 21532

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