blob: d66b50a3bb94096c6b7437ab0075d5778f21a13f [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",
95}
96
97#
Daniel Veillard36e5cd52004-11-02 14:52:23 +000098# Some function really need to be skipped for the tests.
99#
Daniel Veillarddd6d3002004-11-03 14:20:29 +0000100skipped_functions = [
101# block on I/O
102"xmlFdRead", "xmlReadFd", "xmlCtxtReadFd",
103"htmlFdRead", "htmlReadFd", "htmlCtxtReadFd",
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000104"xmlReaderNewFd", "xmlReaderForFd",
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000105"xmlIORead", "xmlReadIO", "xmlCtxtReadIO",
106"htmlIORead", "htmlReadIO", "htmlCtxtReadIO",
Daniel Veillard27f20102004-11-05 11:50:11 +0000107"xmlReaderNewIO", "xmlBufferDump", "xmlNanoFTPConnect",
108"xmlNanoFTPConnectTo",
Daniel Veillard42595322004-11-08 10:52:06 +0000109# Complex I/O APIs
110"xmlCreateIOParserCtxt", "xmlParserInputBufferCreateIO",
111"xmlRegisterInputCallbacks", "xmlReaderForIO",
112"xmlOutputBufferCreateIO", "xmlRegisterOutputCallbacks",
113"xmlSaveToIO",
Daniel Veillarddd6d3002004-11-03 14:20:29 +0000114# library state cleanup, generate false leak informations and other
115# troubles, heavillyb tested otherwise.
Daniel Veillardce244ad2004-11-05 10:03:46 +0000116"xmlCleanupParser", "xmlRelaxNGCleanupTypes", "xmlSetListDoc",
117"xmlSetTreeDoc", "xmlUnlinkNode",
Daniel Veillarddd6d3002004-11-03 14:20:29 +0000118# hard to avoid leaks in the tests
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000119"xmlStrcat", "xmlStrncat", "xmlCatalogAddLocal", "xmlNewTextWriterDoc",
Daniel Veillarda82b1822004-11-08 16:24:57 +0000120"xmlXPathNewValueTree", "xmlXPathWrapString",
Daniel Veillarddd6d3002004-11-03 14:20:29 +0000121# unimplemented
122"xmlTextReaderReadInnerXml", "xmlTextReaderReadOuterXml",
Daniel Veillardd005b9e2004-11-03 17:07:05 +0000123"xmlTextReaderReadString",
124# destructor
Daniel Veillard27f20102004-11-05 11:50:11 +0000125"xmlListDelete", "xmlOutputBufferClose", "xmlNanoFTPClose",
Daniel Veillardd005b9e2004-11-03 17:07:05 +0000126# deprecated
127"xmlCatalogGetPublic", "xmlCatalogGetSystem", "xmlEncodeEntities",
Daniel Veillard2a4fb5a2004-11-08 14:02:18 +0000128"xmlNewGlobalNs", "xmlHandleEntity", "xmlNamespaceParseNCName",
129"xmlNamespaceParseNSDef", "xmlNamespaceParseQName",
130"xmlParseNamespace", "xmlParseQuotedString", "xmlParserHandleReference",
131"xmlScanName",
Daniel Veillarda82b1822004-11-08 16:24:57 +0000132"xmlDecodeEntities",
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000133# allocators
134"xmlMemFree",
Daniel Veillardc2c894f2004-11-07 12:17:35 +0000135# verbosity
Daniel Veillarda82b1822004-11-08 16:24:57 +0000136"xmlCatalogSetDebug", "xmlShellPrintXPathError", "xmlShellPrintNode",
Daniel Veillard2a4fb5a2004-11-08 14:02:18 +0000137# Internal functions, no user space should really call them
138"xmlParseAttribute", "xmlParseAttributeListDecl", "xmlParseName",
139"xmlParseNmtoken", "xmlParseEntityValue", "xmlParseAttValue",
140"xmlParseSystemLiteral", "xmlParsePubidLiteral", "xmlParseCharData",
141"xmlParseExternalID", "xmlParseComment", "xmlParsePITarget", "xmlParsePI",
142"xmlParseNotationDecl", "xmlParseEntityDecl", "xmlParseDefaultDecl",
143"xmlParseNotationType", "xmlParseEnumerationType", "xmlParseEnumeratedType",
144"xmlParseAttributeType", "xmlParseAttributeListDecl",
145"xmlParseElementMixedContentDecl", "xmlParseElementChildrenContentDecl",
146"xmlParseElementContentDecl", "xmlParseElementDecl", "xmlParseMarkupDecl",
147"xmlParseCharRef", "xmlParseEntityRef", "xmlParseReference",
148"xmlParsePEReference", "xmlParseDocTypeDecl", "xmlParseAttribute",
149"xmlParseStartTag", "xmlParseEndTag", "xmlParseCDSect", "xmlParseContent",
150"xmlParseElement", "xmlParseVersionNum", "xmlParseVersionInfo",
151"xmlParseEncName", "xmlParseEncodingDecl", "xmlParseSDDecl",
152"xmlParseXMLDecl", "xmlParseTextDecl", "xmlParseMisc",
153"xmlParseExternalSubset", "xmlParserHandlePEReference",
154"xmlSkipBlankChars",
Daniel Veillarddd6d3002004-11-03 14:20:29 +0000155]
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000156
157#
158# Those functions have side effect on the global state
159# and hence generate errors on memory allocation tests
160#
161skipped_memcheck = [ "xmlLoadCatalog", "xmlAddEncodingAlias",
162 "xmlSchemaInitTypes", "xmlNanoFTPProxy", "xmlNanoFTPScanProxy",
163 "xmlNanoHTTPScanProxy", "xmlResetLastError", "xmlCatalogConvert",
164 "xmlCatalogRemove", "xmlLoadCatalogs", "xmlCleanupCharEncodingHandlers",
Daniel Veillarda03e3652004-11-02 18:45:30 +0000165 "xmlInitCharEncodingHandlers", "xmlCatalogCleanup",
Daniel Veillard42595322004-11-08 10:52:06 +0000166 "xmlSchemaGetBuiltInType",
167 "htmlParseFile", # loads the catalogs
Daniel Veillarda03e3652004-11-02 18:45:30 +0000168]
169
170#
171# Extra code needed for some test cases
172#
Daniel Veillard34099b42004-11-04 17:34:35 +0000173extra_pre_call = {
Daniel Veillarda521d282004-11-09 14:59:59 +0000174 "xmlSAXUserParseFile": """
175#ifdef LIBXML_SAX1_ENABLED
176 if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;
177#endif
178""",
179 "xmlSAXUserParseMemory": """
180#ifdef LIBXML_SAX1_ENABLED
181 if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;
182#endif
183""",
184 "xmlParseBalancedChunkMemory": """
185#ifdef LIBXML_SAX1_ENABLED
186 if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;
187#endif
188""",
189 "xmlParseBalancedChunkMemoryRecover": """
190#ifdef LIBXML_SAX1_ENABLED
191 if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;
192#endif
193""",
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000194 "xmlParserInputBufferCreateFd":
195 "if (fd >= 0) fd = -1;",
Daniel Veillard34099b42004-11-04 17:34:35 +0000196}
Daniel Veillarda03e3652004-11-02 18:45:30 +0000197extra_post_call = {
198 "xmlAddChild":
199 "if (ret_val == NULL) { xmlFreeNode(cur) ; cur = NULL ; }",
200 "xmlAddChildList":
201 "if (ret_val == NULL) { xmlFreeNodeList(cur) ; cur = NULL ; }",
202 "xmlAddSibling":
203 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
204 "xmlAddNextSibling":
205 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
206 "xmlAddPrevSibling":
207 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
208 "xmlDocSetRootElement":
209 "if (doc == NULL) { xmlFreeNode(root) ; root = NULL ; }",
210 "xmlReplaceNode":
Daniel Veillardce244ad2004-11-05 10:03:46 +0000211 """if (cur != NULL) {
212 xmlUnlinkNode(cur);
213 xmlFreeNode(cur) ; cur = NULL ; }
214 if (old != NULL) {
215 xmlUnlinkNode(old);
216 xmlFreeNode(old) ; old = NULL ; }
217 ret_val = NULL;""",
Daniel Veillarda03e3652004-11-02 18:45:30 +0000218 "xmlTextMerge":
219 """if ((first != NULL) && (first->type != XML_TEXT_NODE)) {
Daniel Veillardce244ad2004-11-05 10:03:46 +0000220 xmlUnlinkNode(second);
Daniel Veillarda03e3652004-11-02 18:45:30 +0000221 xmlFreeNode(second) ; second = NULL ; }""",
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000222 "xmlBuildQName":
223 """if ((ret_val != NULL) && (ret_val != ncname) &&
224 (ret_val != prefix) && (ret_val != memory))
225 xmlFree(ret_val);
226 ret_val = NULL;""",
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000227 "xmlDictReference": "xmlDictFree(dict);",
Daniel Veillard3d97e662004-11-04 10:49:00 +0000228 # Functions which deallocates one of their parameters
229 "xmlXPathConvertBoolean": """val = NULL;""",
230 "xmlXPathConvertNumber": """val = NULL;""",
231 "xmlXPathConvertString": """val = NULL;""",
232 "xmlSaveFileTo": """buf = NULL;""",
Daniel Veillard34099b42004-11-04 17:34:35 +0000233 "xmlSaveFormatFileTo": """buf = NULL;""",
234 "xmlIOParseDTD": "input = NULL;",
Daniel Veillardce244ad2004-11-05 10:03:46 +0000235 "xmlRemoveProp": "cur = NULL;",
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000236 "xmlNewNs": "if ((node == NULL) && (ret_val != NULL)) xmlFreeNs(ret_val);",
237 "xmlCopyNamespace": "if (ret_val != NULL) xmlFreeNs(ret_val);",
238 "xmlCopyNamespaceList": "if (ret_val != NULL) xmlFreeNsList(ret_val);",
239 "xmlNewTextWriter": "if (ret_val != NULL) out = NULL;",
Daniel Veillarda521d282004-11-09 14:59:59 +0000240 "xmlNewTextWriterPushParser": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;} if (ret_val != NULL) ctxt = NULL;",
Daniel Veillard42595322004-11-08 10:52:06 +0000241 "xmlNewIOInputStream": "if (ret_val != NULL) input = NULL;",
Daniel Veillarda521d282004-11-09 14:59:59 +0000242 "htmlParseChunk": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}",
243 "htmlParseDocument": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}",
244 "xmlParseDocument": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}",
245 "xmlParseChunk": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}",
246 "xmlParseExtParsedEnt": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}",
Daniel Veillarda03e3652004-11-02 18:45:30 +0000247}
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000248
249modules = []
250
251def is_skipped_module(name):
252 for mod in skipped_modules:
253 if mod == name:
254 return 1
255 return 0
256
257def is_skipped_function(name):
258 for fun in skipped_functions:
259 if fun == name:
260 return 1
261 # Do not test destructors
262 if string.find(name, 'Free') != -1:
263 return 1
264 return 0
265
266def is_skipped_memcheck(name):
267 for fun in skipped_memcheck:
268 if fun == name:
269 return 1
270 return 0
271
272missing_types = {}
273def add_missing_type(name, func):
274 try:
275 list = missing_types[name]
276 list.append(func)
277 except:
278 missing_types[name] = [func]
279
Daniel Veillardce682bc2004-11-05 17:22:25 +0000280generated_param_types = []
281def add_generated_param_type(name):
282 generated_param_types.append(name)
283
284generated_return_types = []
285def add_generated_return_type(name):
286 generated_return_types.append(name)
287
Daniel Veillard34099b42004-11-04 17:34:35 +0000288missing_functions = {}
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000289missing_functions_nr = 0
Daniel Veillard34099b42004-11-04 17:34:35 +0000290def add_missing_functions(name, module):
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000291 global missing_functions_nr
292
293 missing_functions_nr = missing_functions_nr + 1
Daniel Veillard34099b42004-11-04 17:34:35 +0000294 try:
295 list = missing_functions[module]
296 list.append(name)
297 except:
298 missing_functions[module] = [name]
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000299
300#
301# Provide the type generators and destructors for the parameters
302#
303
Daniel Veillarda03e3652004-11-02 18:45:30 +0000304def type_convert(str, name, info, module, function, pos):
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000305# res = string.replace(str, " ", " ")
306# res = string.replace(str, " ", " ")
307# res = string.replace(str, " ", " ")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000308 res = string.replace(str, " *", "_ptr")
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000309# res = string.replace(str, "*", "_ptr")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000310 res = string.replace(res, " ", "_")
311 if res == 'const_char_ptr':
312 if string.find(name, "file") != -1 or \
313 string.find(name, "uri") != -1 or \
314 string.find(name, "URI") != -1 or \
315 string.find(info, "filename") != -1 or \
316 string.find(info, "URI") != -1 or \
317 string.find(info, "URL") != -1:
William M. Brack83d9c372004-11-08 02:26:08 +0000318 if string.find(function, "Save") != -1 or \
319 string.find(function, "Create") != -1 or \
320 string.find(function, "Write") != -1:
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000321 return('fileoutput')
322 return('filepath')
323 if res == 'void_ptr':
324 if module == 'nanoftp' and name == 'ctx':
325 return('xmlNanoFTPCtxtPtr')
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000326 if function == 'xmlNanoFTPNewCtxt':
327 return('xmlNanoFTPCtxtPtr')
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000328 if module == 'nanohttp' and name == 'ctx':
329 return('xmlNanoHTTPCtxtPtr')
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000330 if function == 'xmlIOHTTPOpenW':
331 return('xmlNanoHTTPCtxtPtr')
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000332 if string.find(name, "data") != -1:
333 return('userdata');
Daniel Veillardd005b9e2004-11-03 17:07:05 +0000334 if string.find(name, "user") != -1:
335 return('userdata');
Daniel Veillard3d97e662004-11-04 10:49:00 +0000336 if res == 'xmlDoc_ptr':
337 res = 'xmlDocPtr';
338 if res == 'xmlNode_ptr':
339 res = 'xmlNodePtr';
340 if res == 'xmlDict_ptr':
341 res = 'xmlDictPtr';
Daniel Veillarda03e3652004-11-02 18:45:30 +0000342 if res == 'xmlNodePtr' and pos != 0:
343 if (function == 'xmlAddChild' and pos == 2) or \
344 (function == 'xmlAddChildList' and pos == 2) or \
345 (function == 'xmlAddNextSibling' and pos == 2) or \
346 (function == 'xmlAddSibling' and pos == 2) or \
347 (function == 'xmlDocSetRootElement' and pos == 2) or \
348 (function == 'xmlReplaceNode' and pos == 2) or \
349 (function == 'xmlTextMerge') or \
350 (function == 'xmlAddPrevSibling' and pos == 2):
351 return('xmlNodePtr_in');
Daniel Veillard34099b42004-11-04 17:34:35 +0000352 if res == 'const xmlBufferPtr':
353 res = 'xmlBufferPtr';
Daniel Veillard27f20102004-11-05 11:50:11 +0000354 if res == 'xmlChar_ptr' and name == 'name' and \
355 string.find(function, "EatName") != -1:
356 return('eaten_name')
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000357 if res == 'void_ptr*':
358 res = 'void_ptr_ptr'
359 if res == 'char_ptr*':
360 res = 'char_ptr_ptr'
361 if res == 'xmlChar_ptr*':
362 res = 'xmlChar_ptr_ptr'
363 if res == 'const_xmlChar_ptr*':
364 res = 'const_xmlChar_ptr_ptr'
365 if res == 'const_char_ptr*':
366 res = 'const_char_ptr_ptr'
Daniel Veillarda82b1822004-11-08 16:24:57 +0000367 if res == 'FILE_ptr' and module == 'debugXML':
368 res = 'debug_FILE_ptr';
Daniel Veillard6128c012004-11-08 17:16:15 +0000369 if res == 'int' and name == 'options':
370 if module == 'parser' or module == 'xmlreader':
371 res = 'parseroptions'
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000372
373 return res
374
Daniel Veillard34099b42004-11-04 17:34:35 +0000375known_param_types = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000376
Daniel Veillardce682bc2004-11-05 17:22:25 +0000377def is_known_param_type(name, rtype):
378 global test
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000379 for type in known_param_types:
380 if type == name:
381 return 1
Daniel Veillardce682bc2004-11-05 17:22:25 +0000382 for type in generated_param_types:
383 if type == name:
384 return 1
385
386 if name[-3:] == 'Ptr' or name[-4:] == '_ptr':
387 if rtype[0:6] == 'const ':
388 crtype = rtype[6:]
389 else:
390 crtype = rtype
391
Daniel Veillarda521d282004-11-09 14:59:59 +0000392 define = 0
393 if modules_defines.has_key(module):
394 test.write("#ifdef %s\n" % (modules_defines[module]))
395 define = 1
Daniel Veillardce682bc2004-11-05 17:22:25 +0000396 test.write("""
397#define gen_nb_%s 1
398static %s gen_%s(int no ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
399 return(NULL);
400}
401static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
402}
403""" % (name, crtype, name, name, rtype))
Daniel Veillarda521d282004-11-09 14:59:59 +0000404 if define == 1:
405 test.write("#endif\n\n")
Daniel Veillardce682bc2004-11-05 17:22:25 +0000406 add_generated_param_type(name)
407 return 1
408
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000409 return 0
410
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000411#
412# Provide the type destructors for the return values
413#
414
Daniel Veillard34099b42004-11-04 17:34:35 +0000415known_return_types = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000416
417def is_known_return_type(name):
418 for type in known_return_types:
419 if type == name:
420 return 1
421 return 0
422
Daniel Veillard34099b42004-11-04 17:34:35 +0000423#
424# Copy the beginning of the C test program result
425#
426
427input = open("testapi.c", "r")
428test = open('testapi.c.new', 'w')
429
430def compare_and_save():
431 global test
432
433 test.close()
434 input = open("testapi.c", "r").read()
435 test = open('testapi.c.new', "r").read()
436 if input != test:
437 os.system("rm testapi.c ; mv testapi.c.new testapi.c")
438 print("Updated testapi.c")
439 else:
440 print("Generated testapi.c is identical")
441
442line = input.readline()
443while line != "":
444 if line == "/* CUT HERE: everything below that line is generated */\n":
445 break;
446 if line[0:15] == "#define gen_nb_":
447 type = string.split(line[15:])[0]
448 known_param_types.append(type)
449 if line[0:19] == "static void desret_":
450 type = string.split(line[19:], '(')[0]
451 known_return_types.append(type)
452 test.write(line)
453 line = input.readline()
454input.close()
455
456if line == "":
457 print "Could not find the CUT marker in testapi.c skipping generation"
458 test.close()
459 sys.exit(0)
460
461print("Scanned testapi.c: found %d parameters types and %d return types\n" % (
462 len(known_param_types), len(known_return_types)))
463test.write("/* CUT HERE: everything below that line is generated */\n")
464
465
466#
467# Open the input API description
468#
469doc = libxml2.readFile('doc/libxml2-api.xml', None, 0)
470if doc == None:
471 print "Failed to load doc/libxml2-api.xml"
472 sys.exit(1)
473ctxt = doc.xpathNewContext()
Daniel Veillard57b25162004-11-06 14:50:18 +0000474
475#
476# Generate constructors and return type handling for all enums
477#
478enums = ctxt.xpathEval("/api/symbols/typedef[@type='enum']")
479for enum in enums:
480 name = enum.xpathEval('string(@name)')
481 if name == None:
482 continue;
Daniel Veillarda521d282004-11-09 14:59:59 +0000483 module = enum.xpathEval('string(@file)')
484 define = 0
Daniel Veillard57b25162004-11-06 14:50:18 +0000485
486 if is_known_param_type(name, name) == 0:
487 values = ctxt.xpathEval("/api/symbols/enum[@type='%s']" % name)
488 i = 0
489 vals = []
490 for value in values:
491 vname = value.xpathEval('string(@name)')
492 if vname == None:
493 continue;
494 i = i + 1
495 if i >= 5:
496 break;
497 vals.append(vname)
498 if vals == []:
499 print "Didn't found any value for enum %s" % (name)
500 continue
Daniel Veillarda521d282004-11-09 14:59:59 +0000501 if modules_defines.has_key(module):
502 test.write("#ifdef %s\n" % (modules_defines[module]))
503 define = 1
Daniel Veillard57b25162004-11-06 14:50:18 +0000504 test.write("#define gen_nb_%s %d\n" % (name, len(vals)))
505 test.write("""static %s gen_%s(int no, int nr ATTRIBUTE_UNUSED) {\n""" %
506 (name, name))
507 i = 1
508 for value in vals:
509 test.write(" if (no == %d) return(%s);\n" % (i, value))
510 i = i + 1
511 test.write(""" return(0);
512}
513""");
514 known_param_types.append(name)
515
516 if is_known_return_type(name) == 0:
Daniel Veillarda521d282004-11-09 14:59:59 +0000517 if define == 0 and modules_defines.has_key(module):
518 test.write("#ifdef %s\n" % (modules_defines[module]))
519 define = 1
Daniel Veillard57b25162004-11-06 14:50:18 +0000520 test.write("""static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
521}
522static void desret_%s(%s val ATTRIBUTE_UNUSED) {
523}
524
525""" % (name, name, name, name))
526 known_return_types.append(name)
Daniel Veillarda521d282004-11-09 14:59:59 +0000527 if define == 1:
528 test.write("#endif\n\n")
Daniel Veillard34099b42004-11-04 17:34:35 +0000529
530#
531# Load the interfaces
532#
Daniel Veillard57b25162004-11-06 14:50:18 +0000533headers = ctxt.xpathEval("/api/files/file")
Daniel Veillard34099b42004-11-04 17:34:35 +0000534for file in headers:
535 name = file.xpathEval('string(@name)')
536 if (name == None) or (name == ''):
537 continue
538
539 #
540 # Some module may be skipped because they don't really consists
541 # of user callable APIs
542 #
543 if is_skipped_module(name):
544 continue
545
546 #
547 # do not test deprecated APIs
548 #
549 desc = file.xpathEval('string(description)')
550 if string.find(desc, 'DEPRECATED') != -1:
551 print "Skipping deprecated interface %s" % name
552 continue;
553
554 test.write("#include <libxml/%s.h>\n" % name)
555 modules.append(name)
556
557#
558# Generate the callers signatures
559#
560for module in modules:
561 test.write("static int test_%s(void);\n" % module);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000562
563#
564# Generate the top caller
565#
566
567test.write("""
568/**
569 * testlibxml2:
570 *
571 * Main entry point of the tester for the full libxml2 module,
572 * it calls all the tester entry point for each module.
573 *
574 * Returns the number of error found
575 */
576static int
577testlibxml2(void)
578{
Daniel Veillard42595322004-11-08 10:52:06 +0000579 int test_ret = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000580
581""")
582
583for module in modules:
Daniel Veillard42595322004-11-08 10:52:06 +0000584 test.write(" test_ret += test_%s();\n" % module)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000585
586test.write("""
Daniel Veillard3d97e662004-11-04 10:49:00 +0000587 printf("Total: %d functions, %d tests, %d errors\\n",
Daniel Veillard42595322004-11-08 10:52:06 +0000588 function_tests, call_tests, test_ret);
589 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000590}
591
592""")
593
594#
595# How to handle a function
596#
597nb_tests = 0
598
599def generate_test(module, node):
600 global test
601 global nb_tests
602 nb_cond = 0
603 no_gen = 0
604
605 name = node.xpathEval('string(@name)')
606 if is_skipped_function(name):
607 return
608
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000609 #
610 # check we know how to handle the args and return values
611 # and store the informations for the generation
612 #
613 try:
614 args = node.xpathEval("arg")
615 except:
616 args = []
617 t_args = []
Daniel Veillarda03e3652004-11-02 18:45:30 +0000618 n = 0
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000619 for arg in args:
Daniel Veillarda03e3652004-11-02 18:45:30 +0000620 n = n + 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000621 rtype = arg.xpathEval("string(@type)")
622 if rtype == 'void':
623 break;
624 info = arg.xpathEval("string(@info)")
625 nam = arg.xpathEval("string(@name)")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000626 type = type_convert(rtype, nam, info, module, name, n)
Daniel Veillardce682bc2004-11-05 17:22:25 +0000627 if is_known_param_type(type, rtype) == 0:
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000628 add_missing_type(type, name);
629 no_gen = 1
630 t_args.append((nam, type, rtype, info))
631
632 try:
633 rets = node.xpathEval("return")
634 except:
635 rets = []
636 t_ret = None
637 for ret in rets:
638 rtype = ret.xpathEval("string(@type)")
639 info = ret.xpathEval("string(@info)")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000640 type = type_convert(rtype, 'return', info, module, name, 0)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000641 if rtype == 'void':
642 break
643 if is_known_return_type(type) == 0:
644 add_missing_type(type, name);
645 no_gen = 1
646 t_ret = (type, rtype, info)
647 break
648
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000649 test.write("""
650static int
651test_%s(void) {
Daniel Veillard42595322004-11-08 10:52:06 +0000652 int test_ret = 0;
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000653
654""" % (name))
655
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000656 if no_gen == 1:
Daniel Veillard34099b42004-11-04 17:34:35 +0000657 add_missing_functions(name, module)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000658 test.write("""
659 /* missing type support */
Daniel Veillard42595322004-11-08 10:52:06 +0000660 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000661}
662
663""")
664 return
665
666 try:
667 conds = node.xpathEval("cond")
668 for cond in conds:
669 test.write("#ifdef %s\n" % (cond.get_content()))
670 nb_cond = nb_cond + 1
671 except:
672 pass
Daniel Veillarda521d282004-11-09 14:59:59 +0000673
674 define = 0
675 if function_defines.has_key(name):
676 test.write("#ifdef %s\n" % (function_defines[name]))
677 define = 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000678
679 # Declare the memory usage counter
680 no_mem = is_skipped_memcheck(name)
681 if no_mem == 0:
682 test.write(" int mem_base;\n");
683
684 # Declare the return value
685 if t_ret != None:
686 test.write(" %s ret_val;\n" % (t_ret[1]))
687
688 # Declare the arguments
689 for arg in t_args:
690 (nam, type, rtype, info) = arg;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000691 if (type[-3:] == 'Ptr' or type[-4:] == '_ptr') and \
692 rtype[0:6] == 'const ':
693 crtype = rtype[6:]
694 else:
695 crtype = rtype
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000696 # add declaration
Daniel Veillardce682bc2004-11-05 17:22:25 +0000697 test.write(" %s %s; /* %s */\n" % (crtype, nam, info))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000698 test.write(" int n_%s;\n" % (nam))
699 test.write("\n")
700
701 # Cascade loop on of each argument list of values
702 for arg in t_args:
703 (nam, type, rtype, info) = arg;
704 #
705 test.write(" for (n_%s = 0;n_%s < gen_nb_%s;n_%s++) {\n" % (
706 nam, nam, type, nam))
707
708 # log the memory usage
709 if no_mem == 0:
710 test.write(" mem_base = xmlMemBlocks();\n");
711
712 # prepare the call
Daniel Veillard3d97e662004-11-04 10:49:00 +0000713 i = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000714 for arg in t_args:
715 (nam, type, rtype, info) = arg;
716 #
Daniel Veillard3d97e662004-11-04 10:49:00 +0000717 test.write(" %s = gen_%s(n_%s, %d);\n" % (nam, type, nam, i))
718 i = i + 1;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000719
720 # do the call, and clanup the result
Daniel Veillard34099b42004-11-04 17:34:35 +0000721 if extra_pre_call.has_key(name):
722 test.write(" %s\n"% (extra_pre_call[name]))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000723 if t_ret != None:
724 test.write("\n ret_val = %s(" % (name))
725 need = 0
726 for arg in t_args:
727 (nam, type, rtype, info) = arg
728 if need:
729 test.write(", ")
730 else:
731 need = 1
732 test.write("%s" % nam);
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000733 test.write(");\n")
734 if extra_post_call.has_key(name):
735 test.write(" %s\n"% (extra_post_call[name]))
736 test.write(" desret_%s(ret_val);\n" % t_ret[0])
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000737 else:
738 test.write("\n %s(" % (name));
739 need = 0;
740 for arg in t_args:
741 (nam, type, rtype, info) = arg;
742 if need:
743 test.write(", ")
744 else:
745 need = 1
746 test.write("%s" % nam)
747 test.write(");\n")
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000748 if extra_post_call.has_key(name):
749 test.write(" %s\n"% (extra_post_call[name]))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000750
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000751 test.write(" call_tests++;\n");
Daniel Veillarda03e3652004-11-02 18:45:30 +0000752
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000753 # Free the arguments
Daniel Veillard3d97e662004-11-04 10:49:00 +0000754 i = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000755 for arg in t_args:
756 (nam, type, rtype, info) = arg;
757 #
Daniel Veillard3d97e662004-11-04 10:49:00 +0000758 test.write(" des_%s(n_%s, %s, %d);\n" % (type, nam, nam, i))
759 i = i + 1;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000760
761 test.write(" xmlResetLastError();\n");
762 # Check the memory usage
763 if no_mem == 0:
764 test.write(""" if (mem_base != xmlMemBlocks()) {
Daniel Veillarda03e3652004-11-02 18:45:30 +0000765 printf("Leak of %%d blocks found in %s",
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000766 xmlMemBlocks() - mem_base);
Daniel Veillard42595322004-11-08 10:52:06 +0000767 test_ret++;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000768""" % (name));
Daniel Veillarda03e3652004-11-02 18:45:30 +0000769 for arg in t_args:
770 (nam, type, rtype, info) = arg;
771 test.write(""" printf(" %%d", n_%s);\n""" % (nam))
772 test.write(""" printf("\\n");\n""")
773 test.write(" }\n")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000774
775 for arg in t_args:
776 test.write(" }\n")
777
778 #
779 # end of conditional
780 #
781 while nb_cond > 0:
782 test.write("#endif\n")
783 nb_cond = nb_cond -1
Daniel Veillarda521d282004-11-09 14:59:59 +0000784 if define == 1:
785 test.write("#endif\n")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000786
787 nb_tests = nb_tests + 1;
788
789 test.write("""
Daniel Veillard3d97e662004-11-04 10:49:00 +0000790 function_tests++;
Daniel Veillard42595322004-11-08 10:52:06 +0000791 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000792}
793
794""")
795
796#
797# Generate all module callers
798#
799for module in modules:
800 # gather all the functions exported by that module
801 try:
802 functions = ctxt.xpathEval("/api/symbols/function[@file='%s']" % (module))
803 except:
804 print "Failed to gather functions from module %s" % (module)
805 continue;
806
807 # iterate over all functions in the module generating the test
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000808 i = 0
809 nb_tests_old = nb_tests
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000810 for function in functions:
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000811 i = i + 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000812 generate_test(module, function);
813
814 # header
815 test.write("""static int
816test_%s(void) {
Daniel Veillard42595322004-11-08 10:52:06 +0000817 int test_ret = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000818
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000819 printf("Testing %s : %d of %d functions ...\\n");
820""" % (module, module, nb_tests - nb_tests_old, i))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000821
822 # iterate over all functions in the module generating the call
823 for function in functions:
824 name = function.xpathEval('string(@name)')
825 if is_skipped_function(name):
826 continue
Daniel Veillard42595322004-11-08 10:52:06 +0000827 test.write(" test_ret += test_%s();\n" % (name))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000828
829 # footer
830 test.write("""
Daniel Veillard42595322004-11-08 10:52:06 +0000831 if (test_ret != 0)
832 printf("Module %s: %%d errors\\n", test_ret);
833 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000834}
835""" % (module))
836
Daniel Veillardce244ad2004-11-05 10:03:46 +0000837#
838# Generate direct module caller
839#
840test.write("""static int
841test_module(const char *module) {
842""");
843for module in modules:
844 test.write(""" if (!strcmp(module, "%s")) return(test_%s());\n""" % (
845 module, module))
846test.write(""" return(0);
847}
848""");
849
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000850print "Generated test for %d modules and %d functions" %(len(modules), nb_tests)
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000851
Daniel Veillard34099b42004-11-04 17:34:35 +0000852compare_and_save()
853
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000854missing_list = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000855for missing in missing_types.keys():
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000856 if missing == 'va_list' or missing == '...':
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000857 continue;
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000858
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000859 n = len(missing_types[missing])
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000860 missing_list.append((n, missing))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000861
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000862def compare_missing(a, b):
863 return b[0] - a[0]
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000864
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000865missing_list.sort(compare_missing)
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000866print "Missing support for %d functions and %d types see missing.lst" % (missing_functions_nr, len(missing_list))
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000867lst = open("missing.lst", "w")
Daniel Veillard34099b42004-11-04 17:34:35 +0000868lst.write("Missing support for %d types" % (len(missing_list)))
869lst.write("\n")
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000870for miss in missing_list:
871 lst.write("%s: %d :" % (miss[1], miss[0]))
872 i = 0
873 for n in missing_types[miss[1]]:
874 i = i + 1
875 if i > 5:
876 lst.write(" ...")
877 break
878 lst.write(" %s" % (n))
879 lst.write("\n")
Daniel Veillard34099b42004-11-04 17:34:35 +0000880lst.write("\n")
881lst.write("\n")
882lst.write("Missing support per module");
883for module in missing_functions.keys():
884 lst.write("module %s:\n %s\n" % (module, missing_functions[module]))
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000885
886lst.close()
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000887
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000888