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