blob: 5473a8d26684355e9db4ace19dffb35f3b082f31 [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
William M. Brackf13f77f2004-11-12 16:03:48 +0000631 if (type[-3:] == 'Ptr' or type[-4:] == '_ptr') and \
632 rtype[0:6] == 'const ':
633 crtype = rtype[6:]
634 else:
635 crtype = rtype
636 t_args.append((nam, type, rtype, crtype, info))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000637
638 try:
639 rets = node.xpathEval("return")
640 except:
641 rets = []
642 t_ret = None
643 for ret in rets:
644 rtype = ret.xpathEval("string(@type)")
645 info = ret.xpathEval("string(@info)")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000646 type = type_convert(rtype, 'return', info, module, name, 0)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000647 if rtype == 'void':
648 break
649 if is_known_return_type(type) == 0:
650 add_missing_type(type, name);
651 no_gen = 1
652 t_ret = (type, rtype, info)
653 break
654
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000655 test.write("""
656static int
657test_%s(void) {
Daniel Veillard42595322004-11-08 10:52:06 +0000658 int test_ret = 0;
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000659
660""" % (name))
661
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000662 if no_gen == 1:
Daniel Veillard34099b42004-11-04 17:34:35 +0000663 add_missing_functions(name, module)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000664 test.write("""
665 /* missing type support */
Daniel Veillard42595322004-11-08 10:52:06 +0000666 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000667}
668
669""")
670 return
671
672 try:
673 conds = node.xpathEval("cond")
674 for cond in conds:
675 test.write("#ifdef %s\n" % (cond.get_content()))
676 nb_cond = nb_cond + 1
677 except:
678 pass
Daniel Veillarda521d282004-11-09 14:59:59 +0000679
680 define = 0
681 if function_defines.has_key(name):
682 test.write("#ifdef %s\n" % (function_defines[name]))
683 define = 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000684
685 # Declare the memory usage counter
686 no_mem = is_skipped_memcheck(name)
687 if no_mem == 0:
688 test.write(" int mem_base;\n");
689
690 # Declare the return value
691 if t_ret != None:
692 test.write(" %s ret_val;\n" % (t_ret[1]))
693
694 # Declare the arguments
695 for arg in t_args:
William M. Brackf13f77f2004-11-12 16:03:48 +0000696 (nam, type, rtype, crtype, info) = arg;
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:
William M. Brackf13f77f2004-11-12 16:03:48 +0000704 (nam, type, rtype, crtype, info) = arg;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000705 #
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:
William M. Brackf13f77f2004-11-12 16:03:48 +0000716 (nam, type, rtype, crtype, info) = arg;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000717 #
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:
William M. Brackf13f77f2004-11-12 16:03:48 +0000728 (nam, type, rtype, crtype, info) = arg
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000729 if need:
730 test.write(", ")
731 else:
732 need = 1
William M. Brackf13f77f2004-11-12 16:03:48 +0000733 if rtype != crtype:
734 test.write("(%s)" % rtype)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000735 test.write("%s" % nam);
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000736 test.write(");\n")
737 if extra_post_call.has_key(name):
738 test.write(" %s\n"% (extra_post_call[name]))
739 test.write(" desret_%s(ret_val);\n" % t_ret[0])
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000740 else:
741 test.write("\n %s(" % (name));
742 need = 0;
743 for arg in t_args:
William M. Brackf13f77f2004-11-12 16:03:48 +0000744 (nam, type, rtype, crtype, info) = arg;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000745 if need:
746 test.write(", ")
747 else:
748 need = 1
William M. Brackf13f77f2004-11-12 16:03:48 +0000749 if rtype != crtype:
750 test.write("(%s)" % rtype)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000751 test.write("%s" % nam)
752 test.write(");\n")
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000753 if extra_post_call.has_key(name):
754 test.write(" %s\n"% (extra_post_call[name]))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000755
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000756 test.write(" call_tests++;\n");
Daniel Veillarda03e3652004-11-02 18:45:30 +0000757
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000758 # Free the arguments
Daniel Veillard3d97e662004-11-04 10:49:00 +0000759 i = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000760 for arg in t_args:
William M. Brackf13f77f2004-11-12 16:03:48 +0000761 (nam, type, rtype, crtype, info) = arg;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000762 #
William M. Brackf13f77f2004-11-12 16:03:48 +0000763 test.write(" des_%s(n_%s, " % (type, nam))
764 if rtype != crtype:
765 test.write("(%s)" % rtype)
766 test.write("%s, %d);\n" % (nam, i))
Daniel Veillard3d97e662004-11-04 10:49:00 +0000767 i = i + 1;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000768
769 test.write(" xmlResetLastError();\n");
770 # Check the memory usage
771 if no_mem == 0:
772 test.write(""" if (mem_base != xmlMemBlocks()) {
Daniel Veillarda03e3652004-11-02 18:45:30 +0000773 printf("Leak of %%d blocks found in %s",
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000774 xmlMemBlocks() - mem_base);
Daniel Veillard42595322004-11-08 10:52:06 +0000775 test_ret++;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000776""" % (name));
Daniel Veillarda03e3652004-11-02 18:45:30 +0000777 for arg in t_args:
William M. Brackf13f77f2004-11-12 16:03:48 +0000778 (nam, type, rtype, crtype, info) = arg;
Daniel Veillarda03e3652004-11-02 18:45:30 +0000779 test.write(""" printf(" %%d", n_%s);\n""" % (nam))
780 test.write(""" printf("\\n");\n""")
781 test.write(" }\n")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000782
783 for arg in t_args:
784 test.write(" }\n")
785
Daniel Veillardd0cf7f62004-11-09 16:17:02 +0000786 test.write(" function_tests++;\n")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000787 #
788 # end of conditional
789 #
790 while nb_cond > 0:
791 test.write("#endif\n")
792 nb_cond = nb_cond -1
Daniel Veillarda521d282004-11-09 14:59:59 +0000793 if define == 1:
794 test.write("#endif\n")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000795
796 nb_tests = nb_tests + 1;
797
798 test.write("""
Daniel Veillard42595322004-11-08 10:52:06 +0000799 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000800}
801
802""")
803
804#
805# Generate all module callers
806#
807for module in modules:
808 # gather all the functions exported by that module
809 try:
810 functions = ctxt.xpathEval("/api/symbols/function[@file='%s']" % (module))
811 except:
812 print "Failed to gather functions from module %s" % (module)
813 continue;
814
815 # iterate over all functions in the module generating the test
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000816 i = 0
817 nb_tests_old = nb_tests
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000818 for function in functions:
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000819 i = i + 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000820 generate_test(module, function);
821
822 # header
823 test.write("""static int
824test_%s(void) {
Daniel Veillard42595322004-11-08 10:52:06 +0000825 int test_ret = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000826
Daniel Veillardd0cf7f62004-11-09 16:17:02 +0000827 if (quiet == 0) printf("Testing %s : %d of %d functions ...\\n");
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000828""" % (module, module, nb_tests - nb_tests_old, i))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000829
830 # iterate over all functions in the module generating the call
831 for function in functions:
832 name = function.xpathEval('string(@name)')
833 if is_skipped_function(name):
834 continue
Daniel Veillard42595322004-11-08 10:52:06 +0000835 test.write(" test_ret += test_%s();\n" % (name))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000836
837 # footer
838 test.write("""
Daniel Veillard42595322004-11-08 10:52:06 +0000839 if (test_ret != 0)
840 printf("Module %s: %%d errors\\n", test_ret);
841 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000842}
843""" % (module))
844
Daniel Veillardce244ad2004-11-05 10:03:46 +0000845#
846# Generate direct module caller
847#
848test.write("""static int
849test_module(const char *module) {
850""");
851for module in modules:
852 test.write(""" if (!strcmp(module, "%s")) return(test_%s());\n""" % (
853 module, module))
854test.write(""" return(0);
855}
856""");
857
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000858print "Generated test for %d modules and %d functions" %(len(modules), nb_tests)
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000859
Daniel Veillard34099b42004-11-04 17:34:35 +0000860compare_and_save()
861
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000862missing_list = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000863for missing in missing_types.keys():
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000864 if missing == 'va_list' or missing == '...':
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000865 continue;
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000866
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000867 n = len(missing_types[missing])
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000868 missing_list.append((n, missing))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000869
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000870def compare_missing(a, b):
871 return b[0] - a[0]
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000872
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000873missing_list.sort(compare_missing)
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000874print "Missing support for %d functions and %d types see missing.lst" % (missing_functions_nr, len(missing_list))
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000875lst = open("missing.lst", "w")
Daniel Veillard34099b42004-11-04 17:34:35 +0000876lst.write("Missing support for %d types" % (len(missing_list)))
877lst.write("\n")
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000878for miss in missing_list:
879 lst.write("%s: %d :" % (miss[1], miss[0]))
880 i = 0
881 for n in missing_types[miss[1]]:
882 i = i + 1
883 if i > 5:
884 lst.write(" ...")
885 break
886 lst.write(" %s" % (n))
887 lst.write("\n")
Daniel Veillard34099b42004-11-04 17:34:35 +0000888lst.write("\n")
889lst.write("\n")
890lst.write("Missing support per module");
891for module in missing_functions.keys():
892 lst.write("module %s:\n %s\n" % (module, missing_functions[module]))
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000893
894lst.close()
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000895
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000896