blob: 8975cd9ca2e6c720377db0efa713742bc422c367 [file] [log] [blame]
Daniel Veillard36e5cd52004-11-02 14:52:23 +00001#!/usr/bin/python -u
2#
3# generate a tester program for the API
4#
5import sys
Daniel Veillard34099b42004-11-04 17:34:35 +00006import os
Daniel Veillard36e5cd52004-11-02 14:52:23 +00007import string
8try:
9 import libxml2
10except:
11 print "libxml2 python bindings not available, skipping testapi.c generation"
12 sys.exit(0)
13
14#
15# Modules we don't want skip in API test
16#
Daniel Veillard2a4fb5a2004-11-08 14:02:18 +000017skipped_modules = [ "SAX", "xlink", "threads", "globals",
Daniel Veillarda82b1822004-11-08 16:24:57 +000018 "xmlmemory", "xmlversion", "xmlexports",
19 #deprecated
20 "DOCBparser",
Daniel Veillardd005b9e2004-11-03 17:07:05 +000021]
Daniel Veillard36e5cd52004-11-02 14:52:23 +000022
23#
Daniel Veillarda521d282004-11-09 14:59:59 +000024# defines for each module
25#
26modules_defines = {
27 "HTMLparser": "LIBXML_HTML_ENABLED",
28 "catalog": "LIBXML_CATALOG_ENABLED",
29 "xmlreader": "LIBXML_READER_ENABLED",
30 "relaxng": "LIBXML_SCHEMAS_ENABLED",
31 "schemasInternals": "LIBXML_SCHEMAS_ENABLED",
32 "xmlschemas": "LIBXML_SCHEMAS_ENABLED",
33 "xmlschemastypes": "LIBXML_SCHEMAS_ENABLED",
34 "xpath": "LIBXML_XPATH_ENABLED",
35 "xpathInternals": "LIBXML_XPATH_ENABLED",
36 "xinclude": "LIBXML_XINCLUDE_ENABLED",
37 "xpointer": "LIBXML_XPTR_ENABLED",
38 "xmlregexp" : "LIBXML_REGEXP_ENABLED",
39 "xmlautomata" : "LIBXML_AUTOMATA_ENABLED",
40 "xmlsave" : "LIBXML_OUTPUT_ENABLED",
41 "DOCBparser" : "LIBXML_DOCB_ENABLED",
42}
43
44#
45# defines for specific functions
46#
47function_defines = {
48 "htmlDefaultSAXHandlerInit": "LIBXML_HTML_ENABLED",
49 "xmlSAX2EndElement" : "LIBXML_SAX1_ENABLED",
50 "xmlSAX2StartElement" : "LIBXML_SAX1_ENABLED",
51 "xmlSAXDefaultVersion" : "LIBXML_SAX1_ENABLED",
52 "UTF8Toisolat1" : "LIBXML_OUTPUT_ENABLED",
53 "xmlCleanupPredefinedEntities": "LIBXML_LEGACY_ENABLED",
54 "xmlInitializePredefinedEntities": "LIBXML_LEGACY_ENABLED",
55 "xmlSetFeature": "LIBXML_LEGACY_ENABLED",
56 "xmlGetFeature": "LIBXML_LEGACY_ENABLED",
57 "xmlGetFeaturesList": "LIBXML_LEGACY_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 "docbDefaultSAXHandlerInit" : "LIBXML_DOCB_ENABLED",
Daniel Veillardd0cf7f62004-11-09 16:17:02 +000095 "xmlTextReaderPreservePattern" : "LIBXML_PATTERN_ENABLED",
Daniel Veillarda521d282004-11-09 14:59:59 +000096}
97
98#
Daniel Veillard36e5cd52004-11-02 14:52:23 +000099# Some function really need to be skipped for the tests.
100#
Daniel Veillarddd6d3002004-11-03 14:20:29 +0000101skipped_functions = [
102# block on I/O
103"xmlFdRead", "xmlReadFd", "xmlCtxtReadFd",
104"htmlFdRead", "htmlReadFd", "htmlCtxtReadFd",
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000105"xmlReaderNewFd", "xmlReaderForFd",
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000106"xmlIORead", "xmlReadIO", "xmlCtxtReadIO",
107"htmlIORead", "htmlReadIO", "htmlCtxtReadIO",
Daniel Veillard27f20102004-11-05 11:50:11 +0000108"xmlReaderNewIO", "xmlBufferDump", "xmlNanoFTPConnect",
109"xmlNanoFTPConnectTo",
Daniel Veillard42595322004-11-08 10:52:06 +0000110# Complex I/O APIs
111"xmlCreateIOParserCtxt", "xmlParserInputBufferCreateIO",
112"xmlRegisterInputCallbacks", "xmlReaderForIO",
113"xmlOutputBufferCreateIO", "xmlRegisterOutputCallbacks",
114"xmlSaveToIO",
Daniel Veillarddd6d3002004-11-03 14:20:29 +0000115# library state cleanup, generate false leak informations and other
116# troubles, heavillyb tested otherwise.
Daniel Veillardce244ad2004-11-05 10:03:46 +0000117"xmlCleanupParser", "xmlRelaxNGCleanupTypes", "xmlSetListDoc",
118"xmlSetTreeDoc", "xmlUnlinkNode",
Daniel Veillarddd6d3002004-11-03 14:20:29 +0000119# hard to avoid leaks in the tests
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000120"xmlStrcat", "xmlStrncat", "xmlCatalogAddLocal", "xmlNewTextWriterDoc",
Daniel Veillarda82b1822004-11-08 16:24:57 +0000121"xmlXPathNewValueTree", "xmlXPathWrapString",
Daniel Veillarddd6d3002004-11-03 14:20:29 +0000122# unimplemented
123"xmlTextReaderReadInnerXml", "xmlTextReaderReadOuterXml",
Daniel Veillardd005b9e2004-11-03 17:07:05 +0000124"xmlTextReaderReadString",
125# destructor
Daniel Veillard27f20102004-11-05 11:50:11 +0000126"xmlListDelete", "xmlOutputBufferClose", "xmlNanoFTPClose",
Daniel Veillardd005b9e2004-11-03 17:07:05 +0000127# deprecated
128"xmlCatalogGetPublic", "xmlCatalogGetSystem", "xmlEncodeEntities",
Daniel Veillard2a4fb5a2004-11-08 14:02:18 +0000129"xmlNewGlobalNs", "xmlHandleEntity", "xmlNamespaceParseNCName",
130"xmlNamespaceParseNSDef", "xmlNamespaceParseQName",
131"xmlParseNamespace", "xmlParseQuotedString", "xmlParserHandleReference",
132"xmlScanName",
Daniel Veillarda82b1822004-11-08 16:24:57 +0000133"xmlDecodeEntities",
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000134# allocators
135"xmlMemFree",
Daniel Veillardc2c894f2004-11-07 12:17:35 +0000136# verbosity
Daniel Veillarda82b1822004-11-08 16:24:57 +0000137"xmlCatalogSetDebug", "xmlShellPrintXPathError", "xmlShellPrintNode",
Daniel Veillard2a4fb5a2004-11-08 14:02:18 +0000138# Internal functions, no user space should really call them
139"xmlParseAttribute", "xmlParseAttributeListDecl", "xmlParseName",
140"xmlParseNmtoken", "xmlParseEntityValue", "xmlParseAttValue",
141"xmlParseSystemLiteral", "xmlParsePubidLiteral", "xmlParseCharData",
142"xmlParseExternalID", "xmlParseComment", "xmlParsePITarget", "xmlParsePI",
143"xmlParseNotationDecl", "xmlParseEntityDecl", "xmlParseDefaultDecl",
144"xmlParseNotationType", "xmlParseEnumerationType", "xmlParseEnumeratedType",
145"xmlParseAttributeType", "xmlParseAttributeListDecl",
146"xmlParseElementMixedContentDecl", "xmlParseElementChildrenContentDecl",
147"xmlParseElementContentDecl", "xmlParseElementDecl", "xmlParseMarkupDecl",
148"xmlParseCharRef", "xmlParseEntityRef", "xmlParseReference",
149"xmlParsePEReference", "xmlParseDocTypeDecl", "xmlParseAttribute",
150"xmlParseStartTag", "xmlParseEndTag", "xmlParseCDSect", "xmlParseContent",
151"xmlParseElement", "xmlParseVersionNum", "xmlParseVersionInfo",
152"xmlParseEncName", "xmlParseEncodingDecl", "xmlParseSDDecl",
153"xmlParseXMLDecl", "xmlParseTextDecl", "xmlParseMisc",
154"xmlParseExternalSubset", "xmlParserHandlePEReference",
155"xmlSkipBlankChars",
Daniel Veillarddd6d3002004-11-03 14:20:29 +0000156]
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000157
158#
159# Those functions have side effect on the global state
160# and hence generate errors on memory allocation tests
161#
162skipped_memcheck = [ "xmlLoadCatalog", "xmlAddEncodingAlias",
163 "xmlSchemaInitTypes", "xmlNanoFTPProxy", "xmlNanoFTPScanProxy",
164 "xmlNanoHTTPScanProxy", "xmlResetLastError", "xmlCatalogConvert",
165 "xmlCatalogRemove", "xmlLoadCatalogs", "xmlCleanupCharEncodingHandlers",
Daniel Veillarda03e3652004-11-02 18:45:30 +0000166 "xmlInitCharEncodingHandlers", "xmlCatalogCleanup",
Daniel Veillard42595322004-11-08 10:52:06 +0000167 "xmlSchemaGetBuiltInType",
168 "htmlParseFile", # loads the catalogs
Daniel Veillarda03e3652004-11-02 18:45:30 +0000169]
170
171#
172# Extra code needed for some test cases
173#
Daniel Veillard34099b42004-11-04 17:34:35 +0000174extra_pre_call = {
Daniel Veillarda521d282004-11-09 14:59:59 +0000175 "xmlSAXUserParseFile": """
176#ifdef LIBXML_SAX1_ENABLED
177 if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;
178#endif
179""",
180 "xmlSAXUserParseMemory": """
181#ifdef LIBXML_SAX1_ENABLED
182 if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;
183#endif
184""",
185 "xmlParseBalancedChunkMemory": """
186#ifdef LIBXML_SAX1_ENABLED
187 if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;
188#endif
189""",
190 "xmlParseBalancedChunkMemoryRecover": """
191#ifdef LIBXML_SAX1_ENABLED
192 if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;
193#endif
194""",
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000195 "xmlParserInputBufferCreateFd":
196 "if (fd >= 0) fd = -1;",
Daniel Veillard34099b42004-11-04 17:34:35 +0000197}
Daniel Veillarda03e3652004-11-02 18:45:30 +0000198extra_post_call = {
199 "xmlAddChild":
200 "if (ret_val == NULL) { xmlFreeNode(cur) ; cur = NULL ; }",
201 "xmlAddChildList":
202 "if (ret_val == NULL) { xmlFreeNodeList(cur) ; cur = NULL ; }",
203 "xmlAddSibling":
204 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
205 "xmlAddNextSibling":
206 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
207 "xmlAddPrevSibling":
208 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
209 "xmlDocSetRootElement":
210 "if (doc == NULL) { xmlFreeNode(root) ; root = NULL ; }",
211 "xmlReplaceNode":
Daniel Veillardce244ad2004-11-05 10:03:46 +0000212 """if (cur != NULL) {
213 xmlUnlinkNode(cur);
214 xmlFreeNode(cur) ; cur = NULL ; }
215 if (old != NULL) {
216 xmlUnlinkNode(old);
217 xmlFreeNode(old) ; old = NULL ; }
218 ret_val = NULL;""",
Daniel Veillarda03e3652004-11-02 18:45:30 +0000219 "xmlTextMerge":
220 """if ((first != NULL) && (first->type != XML_TEXT_NODE)) {
Daniel Veillardce244ad2004-11-05 10:03:46 +0000221 xmlUnlinkNode(second);
Daniel Veillarda03e3652004-11-02 18:45:30 +0000222 xmlFreeNode(second) ; second = NULL ; }""",
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000223 "xmlBuildQName":
224 """if ((ret_val != NULL) && (ret_val != ncname) &&
225 (ret_val != prefix) && (ret_val != memory))
226 xmlFree(ret_val);
227 ret_val = NULL;""",
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000228 "xmlDictReference": "xmlDictFree(dict);",
Daniel Veillard3d97e662004-11-04 10:49:00 +0000229 # Functions which deallocates one of their parameters
230 "xmlXPathConvertBoolean": """val = NULL;""",
231 "xmlXPathConvertNumber": """val = NULL;""",
232 "xmlXPathConvertString": """val = NULL;""",
233 "xmlSaveFileTo": """buf = NULL;""",
Daniel Veillard34099b42004-11-04 17:34:35 +0000234 "xmlSaveFormatFileTo": """buf = NULL;""",
235 "xmlIOParseDTD": "input = NULL;",
Daniel Veillardce244ad2004-11-05 10:03:46 +0000236 "xmlRemoveProp": "cur = NULL;",
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000237 "xmlNewNs": "if ((node == NULL) && (ret_val != NULL)) xmlFreeNs(ret_val);",
238 "xmlCopyNamespace": "if (ret_val != NULL) xmlFreeNs(ret_val);",
239 "xmlCopyNamespaceList": "if (ret_val != NULL) xmlFreeNsList(ret_val);",
240 "xmlNewTextWriter": "if (ret_val != NULL) out = NULL;",
Daniel Veillarda521d282004-11-09 14:59:59 +0000241 "xmlNewTextWriterPushParser": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;} if (ret_val != NULL) ctxt = NULL;",
Daniel Veillard42595322004-11-08 10:52:06 +0000242 "xmlNewIOInputStream": "if (ret_val != NULL) input = NULL;",
Daniel Veillarda521d282004-11-09 14:59:59 +0000243 "htmlParseChunk": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}",
244 "htmlParseDocument": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}",
245 "xmlParseDocument": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}",
246 "xmlParseChunk": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}",
247 "xmlParseExtParsedEnt": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}",
Daniel Veillarda03e3652004-11-02 18:45:30 +0000248}
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000249
250modules = []
251
252def is_skipped_module(name):
253 for mod in skipped_modules:
254 if mod == name:
255 return 1
256 return 0
257
258def is_skipped_function(name):
259 for fun in skipped_functions:
260 if fun == name:
261 return 1
262 # Do not test destructors
263 if string.find(name, 'Free') != -1:
264 return 1
265 return 0
266
267def is_skipped_memcheck(name):
268 for fun in skipped_memcheck:
269 if fun == name:
270 return 1
271 return 0
272
273missing_types = {}
274def add_missing_type(name, func):
275 try:
276 list = missing_types[name]
277 list.append(func)
278 except:
279 missing_types[name] = [func]
280
Daniel Veillardce682bc2004-11-05 17:22:25 +0000281generated_param_types = []
282def add_generated_param_type(name):
283 generated_param_types.append(name)
284
285generated_return_types = []
286def add_generated_return_type(name):
287 generated_return_types.append(name)
288
Daniel Veillard34099b42004-11-04 17:34:35 +0000289missing_functions = {}
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000290missing_functions_nr = 0
Daniel Veillard34099b42004-11-04 17:34:35 +0000291def add_missing_functions(name, module):
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000292 global missing_functions_nr
293
294 missing_functions_nr = missing_functions_nr + 1
Daniel Veillard34099b42004-11-04 17:34:35 +0000295 try:
296 list = missing_functions[module]
297 list.append(name)
298 except:
299 missing_functions[module] = [name]
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000300
301#
302# Provide the type generators and destructors for the parameters
303#
304
Daniel Veillarda03e3652004-11-02 18:45:30 +0000305def type_convert(str, name, info, module, function, pos):
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000306# res = string.replace(str, " ", " ")
307# res = string.replace(str, " ", " ")
308# res = string.replace(str, " ", " ")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000309 res = string.replace(str, " *", "_ptr")
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000310# res = string.replace(str, "*", "_ptr")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000311 res = string.replace(res, " ", "_")
312 if res == 'const_char_ptr':
313 if string.find(name, "file") != -1 or \
314 string.find(name, "uri") != -1 or \
315 string.find(name, "URI") != -1 or \
316 string.find(info, "filename") != -1 or \
317 string.find(info, "URI") != -1 or \
318 string.find(info, "URL") != -1:
William M. Brack83d9c372004-11-08 02:26:08 +0000319 if string.find(function, "Save") != -1 or \
320 string.find(function, "Create") != -1 or \
321 string.find(function, "Write") != -1:
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000322 return('fileoutput')
323 return('filepath')
324 if res == 'void_ptr':
325 if module == 'nanoftp' and name == 'ctx':
326 return('xmlNanoFTPCtxtPtr')
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000327 if function == 'xmlNanoFTPNewCtxt':
328 return('xmlNanoFTPCtxtPtr')
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000329 if module == 'nanohttp' and name == 'ctx':
330 return('xmlNanoHTTPCtxtPtr')
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000331 if function == 'xmlIOHTTPOpenW':
332 return('xmlNanoHTTPCtxtPtr')
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000333 if string.find(name, "data") != -1:
334 return('userdata');
Daniel Veillardd005b9e2004-11-03 17:07:05 +0000335 if string.find(name, "user") != -1:
336 return('userdata');
Daniel Veillard3d97e662004-11-04 10:49:00 +0000337 if res == 'xmlDoc_ptr':
338 res = 'xmlDocPtr';
339 if res == 'xmlNode_ptr':
340 res = 'xmlNodePtr';
341 if res == 'xmlDict_ptr':
342 res = 'xmlDictPtr';
Daniel Veillarda03e3652004-11-02 18:45:30 +0000343 if res == 'xmlNodePtr' and pos != 0:
344 if (function == 'xmlAddChild' and pos == 2) or \
345 (function == 'xmlAddChildList' and pos == 2) or \
346 (function == 'xmlAddNextSibling' and pos == 2) or \
347 (function == 'xmlAddSibling' and pos == 2) or \
348 (function == 'xmlDocSetRootElement' and pos == 2) or \
349 (function == 'xmlReplaceNode' and pos == 2) or \
350 (function == 'xmlTextMerge') or \
351 (function == 'xmlAddPrevSibling' and pos == 2):
352 return('xmlNodePtr_in');
Daniel Veillard34099b42004-11-04 17:34:35 +0000353 if res == 'const xmlBufferPtr':
354 res = 'xmlBufferPtr';
Daniel Veillard27f20102004-11-05 11:50:11 +0000355 if res == 'xmlChar_ptr' and name == 'name' and \
356 string.find(function, "EatName") != -1:
357 return('eaten_name')
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000358 if res == 'void_ptr*':
359 res = 'void_ptr_ptr'
360 if res == 'char_ptr*':
361 res = 'char_ptr_ptr'
362 if res == 'xmlChar_ptr*':
363 res = 'xmlChar_ptr_ptr'
364 if res == 'const_xmlChar_ptr*':
365 res = 'const_xmlChar_ptr_ptr'
366 if res == 'const_char_ptr*':
367 res = 'const_char_ptr_ptr'
Daniel Veillarda82b1822004-11-08 16:24:57 +0000368 if res == 'FILE_ptr' and module == 'debugXML':
369 res = 'debug_FILE_ptr';
Daniel Veillard6128c012004-11-08 17:16:15 +0000370 if res == 'int' and name == 'options':
371 if module == 'parser' or module == 'xmlreader':
372 res = 'parseroptions'
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000373
374 return res
375
Daniel Veillard34099b42004-11-04 17:34:35 +0000376known_param_types = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000377
Daniel Veillardce682bc2004-11-05 17:22:25 +0000378def is_known_param_type(name, rtype):
379 global test
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000380 for type in known_param_types:
381 if type == name:
382 return 1
Daniel Veillardce682bc2004-11-05 17:22:25 +0000383 for type in generated_param_types:
384 if type == name:
385 return 1
386
387 if name[-3:] == 'Ptr' or name[-4:] == '_ptr':
388 if rtype[0:6] == 'const ':
389 crtype = rtype[6:]
390 else:
391 crtype = rtype
392
Daniel Veillarda521d282004-11-09 14:59:59 +0000393 define = 0
394 if modules_defines.has_key(module):
395 test.write("#ifdef %s\n" % (modules_defines[module]))
396 define = 1
Daniel Veillardce682bc2004-11-05 17:22:25 +0000397 test.write("""
398#define gen_nb_%s 1
399static %s gen_%s(int no ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
400 return(NULL);
401}
402static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
403}
404""" % (name, crtype, name, name, rtype))
Daniel Veillarda521d282004-11-09 14:59:59 +0000405 if define == 1:
406 test.write("#endif\n\n")
Daniel Veillardce682bc2004-11-05 17:22:25 +0000407 add_generated_param_type(name)
408 return 1
409
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000410 return 0
411
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000412#
413# Provide the type destructors for the return values
414#
415
Daniel Veillard34099b42004-11-04 17:34:35 +0000416known_return_types = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000417
418def is_known_return_type(name):
419 for type in known_return_types:
420 if type == name:
421 return 1
422 return 0
423
Daniel Veillard34099b42004-11-04 17:34:35 +0000424#
425# Copy the beginning of the C test program result
426#
427
428input = open("testapi.c", "r")
429test = open('testapi.c.new', 'w')
430
431def compare_and_save():
432 global test
433
434 test.close()
435 input = open("testapi.c", "r").read()
436 test = open('testapi.c.new', "r").read()
437 if input != test:
438 os.system("rm testapi.c ; mv testapi.c.new testapi.c")
439 print("Updated testapi.c")
440 else:
441 print("Generated testapi.c is identical")
442
443line = input.readline()
444while line != "":
445 if line == "/* CUT HERE: everything below that line is generated */\n":
446 break;
447 if line[0:15] == "#define gen_nb_":
448 type = string.split(line[15:])[0]
449 known_param_types.append(type)
450 if line[0:19] == "static void desret_":
451 type = string.split(line[19:], '(')[0]
452 known_return_types.append(type)
453 test.write(line)
454 line = input.readline()
455input.close()
456
457if line == "":
458 print "Could not find the CUT marker in testapi.c skipping generation"
459 test.close()
460 sys.exit(0)
461
462print("Scanned testapi.c: found %d parameters types and %d return types\n" % (
463 len(known_param_types), len(known_return_types)))
464test.write("/* CUT HERE: everything below that line is generated */\n")
465
466
467#
468# Open the input API description
469#
470doc = libxml2.readFile('doc/libxml2-api.xml', None, 0)
471if doc == None:
472 print "Failed to load doc/libxml2-api.xml"
473 sys.exit(1)
474ctxt = doc.xpathNewContext()
Daniel Veillard57b25162004-11-06 14:50:18 +0000475
476#
477# Generate constructors and return type handling for all enums
478#
479enums = ctxt.xpathEval("/api/symbols/typedef[@type='enum']")
480for enum in enums:
481 name = enum.xpathEval('string(@name)')
482 if name == None:
483 continue;
Daniel Veillarda521d282004-11-09 14:59:59 +0000484 module = enum.xpathEval('string(@file)')
485 define = 0
Daniel Veillard57b25162004-11-06 14:50:18 +0000486
487 if is_known_param_type(name, name) == 0:
488 values = ctxt.xpathEval("/api/symbols/enum[@type='%s']" % name)
489 i = 0
490 vals = []
491 for value in values:
492 vname = value.xpathEval('string(@name)')
493 if vname == None:
494 continue;
495 i = i + 1
496 if i >= 5:
497 break;
498 vals.append(vname)
499 if vals == []:
500 print "Didn't found any value for enum %s" % (name)
501 continue
Daniel Veillarda521d282004-11-09 14:59:59 +0000502 if modules_defines.has_key(module):
503 test.write("#ifdef %s\n" % (modules_defines[module]))
504 define = 1
Daniel Veillard57b25162004-11-06 14:50:18 +0000505 test.write("#define gen_nb_%s %d\n" % (name, len(vals)))
506 test.write("""static %s gen_%s(int no, int nr ATTRIBUTE_UNUSED) {\n""" %
507 (name, name))
508 i = 1
509 for value in vals:
510 test.write(" if (no == %d) return(%s);\n" % (i, value))
511 i = i + 1
512 test.write(""" return(0);
513}
514""");
515 known_param_types.append(name)
516
517 if is_known_return_type(name) == 0:
Daniel Veillarda521d282004-11-09 14:59:59 +0000518 if define == 0 and modules_defines.has_key(module):
519 test.write("#ifdef %s\n" % (modules_defines[module]))
520 define = 1
Daniel Veillard57b25162004-11-06 14:50:18 +0000521 test.write("""static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
522}
523static void desret_%s(%s val ATTRIBUTE_UNUSED) {
524}
525
526""" % (name, name, name, name))
527 known_return_types.append(name)
Daniel Veillarda521d282004-11-09 14:59:59 +0000528 if define == 1:
529 test.write("#endif\n\n")
Daniel Veillard34099b42004-11-04 17:34:35 +0000530
531#
532# Load the interfaces
533#
Daniel Veillard57b25162004-11-06 14:50:18 +0000534headers = ctxt.xpathEval("/api/files/file")
Daniel Veillard34099b42004-11-04 17:34:35 +0000535for file in headers:
536 name = file.xpathEval('string(@name)')
537 if (name == None) or (name == ''):
538 continue
539
540 #
541 # Some module may be skipped because they don't really consists
542 # of user callable APIs
543 #
544 if is_skipped_module(name):
545 continue
546
547 #
548 # do not test deprecated APIs
549 #
550 desc = file.xpathEval('string(description)')
551 if string.find(desc, 'DEPRECATED') != -1:
552 print "Skipping deprecated interface %s" % name
553 continue;
554
555 test.write("#include <libxml/%s.h>\n" % name)
556 modules.append(name)
557
558#
559# Generate the callers signatures
560#
561for module in modules:
562 test.write("static int test_%s(void);\n" % module);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000563
564#
565# Generate the top caller
566#
567
568test.write("""
569/**
570 * testlibxml2:
571 *
572 * Main entry point of the tester for the full libxml2 module,
573 * it calls all the tester entry point for each module.
574 *
575 * Returns the number of error found
576 */
577static int
578testlibxml2(void)
579{
Daniel Veillard42595322004-11-08 10:52:06 +0000580 int test_ret = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000581
582""")
583
584for module in modules:
Daniel Veillard42595322004-11-08 10:52:06 +0000585 test.write(" test_ret += test_%s();\n" % module)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000586
587test.write("""
Daniel Veillard3d97e662004-11-04 10:49:00 +0000588 printf("Total: %d functions, %d tests, %d errors\\n",
Daniel Veillard42595322004-11-08 10:52:06 +0000589 function_tests, call_tests, test_ret);
590 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000591}
592
593""")
594
595#
596# How to handle a function
597#
598nb_tests = 0
599
600def generate_test(module, node):
601 global test
602 global nb_tests
603 nb_cond = 0
604 no_gen = 0
605
606 name = node.xpathEval('string(@name)')
607 if is_skipped_function(name):
608 return
609
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000610 #
611 # check we know how to handle the args and return values
612 # and store the informations for the generation
613 #
614 try:
615 args = node.xpathEval("arg")
616 except:
617 args = []
618 t_args = []
Daniel Veillarda03e3652004-11-02 18:45:30 +0000619 n = 0
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000620 for arg in args:
Daniel Veillarda03e3652004-11-02 18:45:30 +0000621 n = n + 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000622 rtype = arg.xpathEval("string(@type)")
623 if rtype == 'void':
624 break;
625 info = arg.xpathEval("string(@info)")
626 nam = arg.xpathEval("string(@name)")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000627 type = type_convert(rtype, nam, info, module, name, n)
Daniel Veillardce682bc2004-11-05 17:22:25 +0000628 if is_known_param_type(type, rtype) == 0:
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000629 add_missing_type(type, name);
630 no_gen = 1
631 t_args.append((nam, type, rtype, info))
632
633 try:
634 rets = node.xpathEval("return")
635 except:
636 rets = []
637 t_ret = None
638 for ret in rets:
639 rtype = ret.xpathEval("string(@type)")
640 info = ret.xpathEval("string(@info)")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000641 type = type_convert(rtype, 'return', info, module, name, 0)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000642 if rtype == 'void':
643 break
644 if is_known_return_type(type) == 0:
645 add_missing_type(type, name);
646 no_gen = 1
647 t_ret = (type, rtype, info)
648 break
649
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000650 test.write("""
651static int
652test_%s(void) {
Daniel Veillard42595322004-11-08 10:52:06 +0000653 int test_ret = 0;
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000654
655""" % (name))
656
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000657 if no_gen == 1:
Daniel Veillard34099b42004-11-04 17:34:35 +0000658 add_missing_functions(name, module)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000659 test.write("""
660 /* missing type support */
Daniel Veillard42595322004-11-08 10:52:06 +0000661 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000662}
663
664""")
665 return
666
667 try:
668 conds = node.xpathEval("cond")
669 for cond in conds:
670 test.write("#ifdef %s\n" % (cond.get_content()))
671 nb_cond = nb_cond + 1
672 except:
673 pass
Daniel Veillarda521d282004-11-09 14:59:59 +0000674
675 define = 0
676 if function_defines.has_key(name):
677 test.write("#ifdef %s\n" % (function_defines[name]))
678 define = 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000679
680 # Declare the memory usage counter
681 no_mem = is_skipped_memcheck(name)
682 if no_mem == 0:
683 test.write(" int mem_base;\n");
684
685 # Declare the return value
686 if t_ret != None:
687 test.write(" %s ret_val;\n" % (t_ret[1]))
688
689 # Declare the arguments
690 for arg in t_args:
691 (nam, type, rtype, info) = arg;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000692 if (type[-3:] == 'Ptr' or type[-4:] == '_ptr') and \
693 rtype[0:6] == 'const ':
694 crtype = rtype[6:]
695 else:
696 crtype = rtype
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000697 # add declaration
Daniel Veillardce682bc2004-11-05 17:22:25 +0000698 test.write(" %s %s; /* %s */\n" % (crtype, nam, info))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000699 test.write(" int n_%s;\n" % (nam))
700 test.write("\n")
701
702 # Cascade loop on of each argument list of values
703 for arg in t_args:
704 (nam, type, rtype, info) = arg;
705 #
706 test.write(" for (n_%s = 0;n_%s < gen_nb_%s;n_%s++) {\n" % (
707 nam, nam, type, nam))
708
709 # log the memory usage
710 if no_mem == 0:
711 test.write(" mem_base = xmlMemBlocks();\n");
712
713 # prepare the call
Daniel Veillard3d97e662004-11-04 10:49:00 +0000714 i = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000715 for arg in t_args:
716 (nam, type, rtype, info) = arg;
717 #
Daniel Veillard3d97e662004-11-04 10:49:00 +0000718 test.write(" %s = gen_%s(n_%s, %d);\n" % (nam, type, nam, i))
719 i = i + 1;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000720
721 # do the call, and clanup the result
Daniel Veillard34099b42004-11-04 17:34:35 +0000722 if extra_pre_call.has_key(name):
723 test.write(" %s\n"% (extra_pre_call[name]))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000724 if t_ret != None:
725 test.write("\n ret_val = %s(" % (name))
726 need = 0
727 for arg in t_args:
728 (nam, type, rtype, info) = arg
729 if need:
730 test.write(", ")
731 else:
732 need = 1
733 test.write("%s" % nam);
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000734 test.write(");\n")
735 if extra_post_call.has_key(name):
736 test.write(" %s\n"% (extra_post_call[name]))
737 test.write(" desret_%s(ret_val);\n" % t_ret[0])
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000738 else:
739 test.write("\n %s(" % (name));
740 need = 0;
741 for arg in t_args:
742 (nam, type, rtype, info) = arg;
743 if need:
744 test.write(", ")
745 else:
746 need = 1
747 test.write("%s" % nam)
748 test.write(");\n")
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000749 if extra_post_call.has_key(name):
750 test.write(" %s\n"% (extra_post_call[name]))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000751
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000752 test.write(" call_tests++;\n");
Daniel Veillarda03e3652004-11-02 18:45:30 +0000753
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000754 # Free the arguments
Daniel Veillard3d97e662004-11-04 10:49:00 +0000755 i = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000756 for arg in t_args:
757 (nam, type, rtype, info) = arg;
758 #
Daniel Veillard3d97e662004-11-04 10:49:00 +0000759 test.write(" des_%s(n_%s, %s, %d);\n" % (type, nam, nam, i))
760 i = i + 1;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000761
762 test.write(" xmlResetLastError();\n");
763 # Check the memory usage
764 if no_mem == 0:
765 test.write(""" if (mem_base != xmlMemBlocks()) {
Daniel Veillarda03e3652004-11-02 18:45:30 +0000766 printf("Leak of %%d blocks found in %s",
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000767 xmlMemBlocks() - mem_base);
Daniel Veillard42595322004-11-08 10:52:06 +0000768 test_ret++;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000769""" % (name));
Daniel Veillarda03e3652004-11-02 18:45:30 +0000770 for arg in t_args:
771 (nam, type, rtype, info) = arg;
772 test.write(""" printf(" %%d", n_%s);\n""" % (nam))
773 test.write(""" printf("\\n");\n""")
774 test.write(" }\n")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000775
776 for arg in t_args:
777 test.write(" }\n")
778
Daniel Veillardd0cf7f62004-11-09 16:17:02 +0000779 test.write(" function_tests++;\n")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000780 #
781 # end of conditional
782 #
783 while nb_cond > 0:
784 test.write("#endif\n")
785 nb_cond = nb_cond -1
Daniel Veillarda521d282004-11-09 14:59:59 +0000786 if define == 1:
787 test.write("#endif\n")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000788
789 nb_tests = nb_tests + 1;
790
791 test.write("""
Daniel Veillard42595322004-11-08 10:52:06 +0000792 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000793}
794
795""")
796
797#
798# Generate all module callers
799#
800for module in modules:
801 # gather all the functions exported by that module
802 try:
803 functions = ctxt.xpathEval("/api/symbols/function[@file='%s']" % (module))
804 except:
805 print "Failed to gather functions from module %s" % (module)
806 continue;
807
808 # iterate over all functions in the module generating the test
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000809 i = 0
810 nb_tests_old = nb_tests
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000811 for function in functions:
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000812 i = i + 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000813 generate_test(module, function);
814
815 # header
816 test.write("""static int
817test_%s(void) {
Daniel Veillard42595322004-11-08 10:52:06 +0000818 int test_ret = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000819
Daniel Veillardd0cf7f62004-11-09 16:17:02 +0000820 if (quiet == 0) printf("Testing %s : %d of %d functions ...\\n");
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000821""" % (module, module, nb_tests - nb_tests_old, i))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000822
823 # iterate over all functions in the module generating the call
824 for function in functions:
825 name = function.xpathEval('string(@name)')
826 if is_skipped_function(name):
827 continue
Daniel Veillard42595322004-11-08 10:52:06 +0000828 test.write(" test_ret += test_%s();\n" % (name))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000829
830 # footer
831 test.write("""
Daniel Veillard42595322004-11-08 10:52:06 +0000832 if (test_ret != 0)
833 printf("Module %s: %%d errors\\n", test_ret);
834 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000835}
836""" % (module))
837
Daniel Veillardce244ad2004-11-05 10:03:46 +0000838#
839# Generate direct module caller
840#
841test.write("""static int
842test_module(const char *module) {
843""");
844for module in modules:
845 test.write(""" if (!strcmp(module, "%s")) return(test_%s());\n""" % (
846 module, module))
847test.write(""" return(0);
848}
849""");
850
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000851print "Generated test for %d modules and %d functions" %(len(modules), nb_tests)
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000852
Daniel Veillard34099b42004-11-04 17:34:35 +0000853compare_and_save()
854
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000855missing_list = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000856for missing in missing_types.keys():
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000857 if missing == 'va_list' or missing == '...':
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000858 continue;
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000859
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000860 n = len(missing_types[missing])
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000861 missing_list.append((n, missing))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000862
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000863def compare_missing(a, b):
864 return b[0] - a[0]
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000865
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000866missing_list.sort(compare_missing)
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000867print "Missing support for %d functions and %d types see missing.lst" % (missing_functions_nr, len(missing_list))
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000868lst = open("missing.lst", "w")
Daniel Veillard34099b42004-11-04 17:34:35 +0000869lst.write("Missing support for %d types" % (len(missing_list)))
870lst.write("\n")
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000871for miss in missing_list:
872 lst.write("%s: %d :" % (miss[1], miss[0]))
873 i = 0
874 for n in missing_types[miss[1]]:
875 i = i + 1
876 if i > 5:
877 lst.write(" ...")
878 break
879 lst.write(" %s" % (n))
880 lst.write("\n")
Daniel Veillard34099b42004-11-04 17:34:35 +0000881lst.write("\n")
882lst.write("\n")
883lst.write("Missing support per module");
884for module in missing_functions.keys():
885 lst.write("module %s:\n %s\n" % (module, missing_functions[module]))
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000886
887lst.close()
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000888
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000889