blob: c0bba90378d5f0a0d0d8b4bec1577f644dba120e [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#
24# Some function really need to be skipped for the tests.
25#
Daniel Veillarddd6d3002004-11-03 14:20:29 +000026skipped_functions = [
27# block on I/O
28"xmlFdRead", "xmlReadFd", "xmlCtxtReadFd",
29"htmlFdRead", "htmlReadFd", "htmlCtxtReadFd",
Daniel Veillard1ba06bb2004-11-04 12:32:18 +000030"xmlReaderNewFd", "xmlReaderForFd",
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +000031"xmlIORead", "xmlReadIO", "xmlCtxtReadIO",
32"htmlIORead", "htmlReadIO", "htmlCtxtReadIO",
Daniel Veillard27f20102004-11-05 11:50:11 +000033"xmlReaderNewIO", "xmlBufferDump", "xmlNanoFTPConnect",
34"xmlNanoFTPConnectTo",
Daniel Veillard42595322004-11-08 10:52:06 +000035# Complex I/O APIs
36"xmlCreateIOParserCtxt", "xmlParserInputBufferCreateIO",
37"xmlRegisterInputCallbacks", "xmlReaderForIO",
38"xmlOutputBufferCreateIO", "xmlRegisterOutputCallbacks",
39"xmlSaveToIO",
Daniel Veillarddd6d3002004-11-03 14:20:29 +000040# library state cleanup, generate false leak informations and other
41# troubles, heavillyb tested otherwise.
Daniel Veillardce244ad2004-11-05 10:03:46 +000042"xmlCleanupParser", "xmlRelaxNGCleanupTypes", "xmlSetListDoc",
43"xmlSetTreeDoc", "xmlUnlinkNode",
Daniel Veillarddd6d3002004-11-03 14:20:29 +000044# hard to avoid leaks in the tests
Daniel Veillardd5cc0f72004-11-06 19:24:28 +000045"xmlStrcat", "xmlStrncat", "xmlCatalogAddLocal", "xmlNewTextWriterDoc",
Daniel Veillarda82b1822004-11-08 16:24:57 +000046"xmlXPathNewValueTree", "xmlXPathWrapString",
Daniel Veillarddd6d3002004-11-03 14:20:29 +000047# unimplemented
48"xmlTextReaderReadInnerXml", "xmlTextReaderReadOuterXml",
Daniel Veillardd005b9e2004-11-03 17:07:05 +000049"xmlTextReaderReadString",
50# destructor
Daniel Veillard27f20102004-11-05 11:50:11 +000051"xmlListDelete", "xmlOutputBufferClose", "xmlNanoFTPClose",
Daniel Veillardd005b9e2004-11-03 17:07:05 +000052# deprecated
53"xmlCatalogGetPublic", "xmlCatalogGetSystem", "xmlEncodeEntities",
Daniel Veillard2a4fb5a2004-11-08 14:02:18 +000054"xmlNewGlobalNs", "xmlHandleEntity", "xmlNamespaceParseNCName",
55"xmlNamespaceParseNSDef", "xmlNamespaceParseQName",
56"xmlParseNamespace", "xmlParseQuotedString", "xmlParserHandleReference",
57"xmlScanName",
Daniel Veillarda82b1822004-11-08 16:24:57 +000058"xmlDecodeEntities",
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +000059# allocators
60"xmlMemFree",
Daniel Veillardc2c894f2004-11-07 12:17:35 +000061# verbosity
Daniel Veillarda82b1822004-11-08 16:24:57 +000062"xmlCatalogSetDebug", "xmlShellPrintXPathError", "xmlShellPrintNode",
Daniel Veillard2a4fb5a2004-11-08 14:02:18 +000063# Internal functions, no user space should really call them
64"xmlParseAttribute", "xmlParseAttributeListDecl", "xmlParseName",
65"xmlParseNmtoken", "xmlParseEntityValue", "xmlParseAttValue",
66"xmlParseSystemLiteral", "xmlParsePubidLiteral", "xmlParseCharData",
67"xmlParseExternalID", "xmlParseComment", "xmlParsePITarget", "xmlParsePI",
68"xmlParseNotationDecl", "xmlParseEntityDecl", "xmlParseDefaultDecl",
69"xmlParseNotationType", "xmlParseEnumerationType", "xmlParseEnumeratedType",
70"xmlParseAttributeType", "xmlParseAttributeListDecl",
71"xmlParseElementMixedContentDecl", "xmlParseElementChildrenContentDecl",
72"xmlParseElementContentDecl", "xmlParseElementDecl", "xmlParseMarkupDecl",
73"xmlParseCharRef", "xmlParseEntityRef", "xmlParseReference",
74"xmlParsePEReference", "xmlParseDocTypeDecl", "xmlParseAttribute",
75"xmlParseStartTag", "xmlParseEndTag", "xmlParseCDSect", "xmlParseContent",
76"xmlParseElement", "xmlParseVersionNum", "xmlParseVersionInfo",
77"xmlParseEncName", "xmlParseEncodingDecl", "xmlParseSDDecl",
78"xmlParseXMLDecl", "xmlParseTextDecl", "xmlParseMisc",
79"xmlParseExternalSubset", "xmlParserHandlePEReference",
80"xmlSkipBlankChars",
Daniel Veillarddd6d3002004-11-03 14:20:29 +000081]
Daniel Veillard36e5cd52004-11-02 14:52:23 +000082
83#
84# Those functions have side effect on the global state
85# and hence generate errors on memory allocation tests
86#
87skipped_memcheck = [ "xmlLoadCatalog", "xmlAddEncodingAlias",
88 "xmlSchemaInitTypes", "xmlNanoFTPProxy", "xmlNanoFTPScanProxy",
89 "xmlNanoHTTPScanProxy", "xmlResetLastError", "xmlCatalogConvert",
90 "xmlCatalogRemove", "xmlLoadCatalogs", "xmlCleanupCharEncodingHandlers",
Daniel Veillarda03e3652004-11-02 18:45:30 +000091 "xmlInitCharEncodingHandlers", "xmlCatalogCleanup",
Daniel Veillard42595322004-11-08 10:52:06 +000092 "xmlSchemaGetBuiltInType",
93 "htmlParseFile", # loads the catalogs
Daniel Veillarda03e3652004-11-02 18:45:30 +000094]
95
96#
97# Extra code needed for some test cases
98#
Daniel Veillard34099b42004-11-04 17:34:35 +000099extra_pre_call = {
100 "xmlSAXUserParseFile":
Daniel Veillardce244ad2004-11-05 10:03:46 +0000101 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
Daniel Veillard34099b42004-11-04 17:34:35 +0000102 "xmlSAXUserParseMemory":
Daniel Veillardce244ad2004-11-05 10:03:46 +0000103 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
Daniel Veillardce682bc2004-11-05 17:22:25 +0000104 "xmlParseBalancedChunkMemory":
105 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
106 "xmlParseBalancedChunkMemoryRecover":
107 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000108 "xmlParserInputBufferCreateFd":
109 "if (fd >= 0) fd = -1;",
Daniel Veillard34099b42004-11-04 17:34:35 +0000110}
Daniel Veillarda03e3652004-11-02 18:45:30 +0000111extra_post_call = {
112 "xmlAddChild":
113 "if (ret_val == NULL) { xmlFreeNode(cur) ; cur = NULL ; }",
114 "xmlAddChildList":
115 "if (ret_val == NULL) { xmlFreeNodeList(cur) ; cur = NULL ; }",
116 "xmlAddSibling":
117 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
118 "xmlAddNextSibling":
119 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
120 "xmlAddPrevSibling":
121 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
122 "xmlDocSetRootElement":
123 "if (doc == NULL) { xmlFreeNode(root) ; root = NULL ; }",
124 "xmlReplaceNode":
Daniel Veillardce244ad2004-11-05 10:03:46 +0000125 """if (cur != NULL) {
126 xmlUnlinkNode(cur);
127 xmlFreeNode(cur) ; cur = NULL ; }
128 if (old != NULL) {
129 xmlUnlinkNode(old);
130 xmlFreeNode(old) ; old = NULL ; }
131 ret_val = NULL;""",
Daniel Veillarda03e3652004-11-02 18:45:30 +0000132 "xmlTextMerge":
133 """if ((first != NULL) && (first->type != XML_TEXT_NODE)) {
Daniel Veillardce244ad2004-11-05 10:03:46 +0000134 xmlUnlinkNode(second);
Daniel Veillarda03e3652004-11-02 18:45:30 +0000135 xmlFreeNode(second) ; second = NULL ; }""",
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000136 "xmlBuildQName":
137 """if ((ret_val != NULL) && (ret_val != ncname) &&
138 (ret_val != prefix) && (ret_val != memory))
139 xmlFree(ret_val);
140 ret_val = NULL;""",
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000141 "xmlDictReference": "xmlDictFree(dict);",
Daniel Veillard3d97e662004-11-04 10:49:00 +0000142 # Functions which deallocates one of their parameters
143 "xmlXPathConvertBoolean": """val = NULL;""",
144 "xmlXPathConvertNumber": """val = NULL;""",
145 "xmlXPathConvertString": """val = NULL;""",
146 "xmlSaveFileTo": """buf = NULL;""",
Daniel Veillard34099b42004-11-04 17:34:35 +0000147 "xmlSaveFormatFileTo": """buf = NULL;""",
148 "xmlIOParseDTD": "input = NULL;",
Daniel Veillardce244ad2004-11-05 10:03:46 +0000149 "xmlRemoveProp": "cur = NULL;",
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000150 "xmlNewNs": "if ((node == NULL) && (ret_val != NULL)) xmlFreeNs(ret_val);",
151 "xmlCopyNamespace": "if (ret_val != NULL) xmlFreeNs(ret_val);",
152 "xmlCopyNamespaceList": "if (ret_val != NULL) xmlFreeNsList(ret_val);",
153 "xmlNewTextWriter": "if (ret_val != NULL) out = NULL;",
154 "xmlNewTextWriterPushParser": "if (ret_val != NULL) ctxt = NULL;",
Daniel Veillard42595322004-11-08 10:52:06 +0000155 "xmlNewIOInputStream": "if (ret_val != NULL) input = NULL;",
Daniel Veillarda03e3652004-11-02 18:45:30 +0000156}
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000157
158modules = []
159
160def is_skipped_module(name):
161 for mod in skipped_modules:
162 if mod == name:
163 return 1
164 return 0
165
166def is_skipped_function(name):
167 for fun in skipped_functions:
168 if fun == name:
169 return 1
170 # Do not test destructors
171 if string.find(name, 'Free') != -1:
172 return 1
173 return 0
174
175def is_skipped_memcheck(name):
176 for fun in skipped_memcheck:
177 if fun == name:
178 return 1
179 return 0
180
181missing_types = {}
182def add_missing_type(name, func):
183 try:
184 list = missing_types[name]
185 list.append(func)
186 except:
187 missing_types[name] = [func]
188
Daniel Veillardce682bc2004-11-05 17:22:25 +0000189generated_param_types = []
190def add_generated_param_type(name):
191 generated_param_types.append(name)
192
193generated_return_types = []
194def add_generated_return_type(name):
195 generated_return_types.append(name)
196
Daniel Veillard34099b42004-11-04 17:34:35 +0000197missing_functions = {}
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000198missing_functions_nr = 0
Daniel Veillard34099b42004-11-04 17:34:35 +0000199def add_missing_functions(name, module):
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000200 global missing_functions_nr
201
202 missing_functions_nr = missing_functions_nr + 1
Daniel Veillard34099b42004-11-04 17:34:35 +0000203 try:
204 list = missing_functions[module]
205 list.append(name)
206 except:
207 missing_functions[module] = [name]
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000208
209#
210# Provide the type generators and destructors for the parameters
211#
212
Daniel Veillarda03e3652004-11-02 18:45:30 +0000213def type_convert(str, name, info, module, function, pos):
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000214# res = string.replace(str, " ", " ")
215# res = string.replace(str, " ", " ")
216# res = string.replace(str, " ", " ")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000217 res = string.replace(str, " *", "_ptr")
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000218# res = string.replace(str, "*", "_ptr")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000219 res = string.replace(res, " ", "_")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000220 res = string.replace(res, "htmlNode", "xmlNode")
221 res = string.replace(res, "htmlDoc", "xmlDoc")
222 res = string.replace(res, "htmlParser", "xmlParser")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000223 if res == 'const_char_ptr':
224 if string.find(name, "file") != -1 or \
225 string.find(name, "uri") != -1 or \
226 string.find(name, "URI") != -1 or \
227 string.find(info, "filename") != -1 or \
228 string.find(info, "URI") != -1 or \
229 string.find(info, "URL") != -1:
William M. Brack83d9c372004-11-08 02:26:08 +0000230 if string.find(function, "Save") != -1 or \
231 string.find(function, "Create") != -1 or \
232 string.find(function, "Write") != -1:
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000233 return('fileoutput')
234 return('filepath')
235 if res == 'void_ptr':
236 if module == 'nanoftp' and name == 'ctx':
237 return('xmlNanoFTPCtxtPtr')
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000238 if function == 'xmlNanoFTPNewCtxt':
239 return('xmlNanoFTPCtxtPtr')
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000240 if module == 'nanohttp' and name == 'ctx':
241 return('xmlNanoHTTPCtxtPtr')
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000242 if function == 'xmlIOHTTPOpenW':
243 return('xmlNanoHTTPCtxtPtr')
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000244 if string.find(name, "data") != -1:
245 return('userdata');
Daniel Veillardd005b9e2004-11-03 17:07:05 +0000246 if string.find(name, "user") != -1:
247 return('userdata');
Daniel Veillard3d97e662004-11-04 10:49:00 +0000248 if res == 'xmlDoc_ptr':
249 res = 'xmlDocPtr';
250 if res == 'xmlNode_ptr':
251 res = 'xmlNodePtr';
252 if res == 'xmlDict_ptr':
253 res = 'xmlDictPtr';
Daniel Veillarda03e3652004-11-02 18:45:30 +0000254 if res == 'xmlNodePtr' and pos != 0:
255 if (function == 'xmlAddChild' and pos == 2) or \
256 (function == 'xmlAddChildList' and pos == 2) or \
257 (function == 'xmlAddNextSibling' and pos == 2) or \
258 (function == 'xmlAddSibling' and pos == 2) or \
259 (function == 'xmlDocSetRootElement' and pos == 2) or \
260 (function == 'xmlReplaceNode' and pos == 2) or \
261 (function == 'xmlTextMerge') or \
262 (function == 'xmlAddPrevSibling' and pos == 2):
263 return('xmlNodePtr_in');
Daniel Veillard34099b42004-11-04 17:34:35 +0000264 if res == 'const xmlBufferPtr':
265 res = 'xmlBufferPtr';
Daniel Veillard27f20102004-11-05 11:50:11 +0000266 if res == 'xmlChar_ptr' and name == 'name' and \
267 string.find(function, "EatName") != -1:
268 return('eaten_name')
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000269 if res == 'void_ptr*':
270 res = 'void_ptr_ptr'
271 if res == 'char_ptr*':
272 res = 'char_ptr_ptr'
273 if res == 'xmlChar_ptr*':
274 res = 'xmlChar_ptr_ptr'
275 if res == 'const_xmlChar_ptr*':
276 res = 'const_xmlChar_ptr_ptr'
277 if res == 'const_char_ptr*':
278 res = 'const_char_ptr_ptr'
Daniel Veillarda82b1822004-11-08 16:24:57 +0000279 if res == 'FILE_ptr' and module == 'debugXML':
280 res = 'debug_FILE_ptr';
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000281
282 return res
283
Daniel Veillard34099b42004-11-04 17:34:35 +0000284known_param_types = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000285
Daniel Veillardce682bc2004-11-05 17:22:25 +0000286def is_known_param_type(name, rtype):
287 global test
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000288 for type in known_param_types:
289 if type == name:
290 return 1
Daniel Veillardce682bc2004-11-05 17:22:25 +0000291 for type in generated_param_types:
292 if type == name:
293 return 1
294
295 if name[-3:] == 'Ptr' or name[-4:] == '_ptr':
296 if rtype[0:6] == 'const ':
297 crtype = rtype[6:]
298 else:
299 crtype = rtype
300
301 test.write("""
302#define gen_nb_%s 1
303static %s gen_%s(int no ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
304 return(NULL);
305}
306static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
307}
308""" % (name, crtype, name, name, rtype))
309 add_generated_param_type(name)
310 return 1
311
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000312 return 0
313
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000314#
315# Provide the type destructors for the return values
316#
317
Daniel Veillard34099b42004-11-04 17:34:35 +0000318known_return_types = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000319
320def is_known_return_type(name):
321 for type in known_return_types:
322 if type == name:
323 return 1
324 return 0
325
Daniel Veillard34099b42004-11-04 17:34:35 +0000326#
327# Copy the beginning of the C test program result
328#
329
330input = open("testapi.c", "r")
331test = open('testapi.c.new', 'w')
332
333def compare_and_save():
334 global test
335
336 test.close()
337 input = open("testapi.c", "r").read()
338 test = open('testapi.c.new', "r").read()
339 if input != test:
340 os.system("rm testapi.c ; mv testapi.c.new testapi.c")
341 print("Updated testapi.c")
342 else:
343 print("Generated testapi.c is identical")
344
345line = input.readline()
346while line != "":
347 if line == "/* CUT HERE: everything below that line is generated */\n":
348 break;
349 if line[0:15] == "#define gen_nb_":
350 type = string.split(line[15:])[0]
351 known_param_types.append(type)
352 if line[0:19] == "static void desret_":
353 type = string.split(line[19:], '(')[0]
354 known_return_types.append(type)
355 test.write(line)
356 line = input.readline()
357input.close()
358
359if line == "":
360 print "Could not find the CUT marker in testapi.c skipping generation"
361 test.close()
362 sys.exit(0)
363
364print("Scanned testapi.c: found %d parameters types and %d return types\n" % (
365 len(known_param_types), len(known_return_types)))
366test.write("/* CUT HERE: everything below that line is generated */\n")
367
368
369#
370# Open the input API description
371#
372doc = libxml2.readFile('doc/libxml2-api.xml', None, 0)
373if doc == None:
374 print "Failed to load doc/libxml2-api.xml"
375 sys.exit(1)
376ctxt = doc.xpathNewContext()
Daniel Veillard57b25162004-11-06 14:50:18 +0000377
378#
379# Generate constructors and return type handling for all enums
380#
381enums = ctxt.xpathEval("/api/symbols/typedef[@type='enum']")
382for enum in enums:
383 name = enum.xpathEval('string(@name)')
384 if name == None:
385 continue;
386
387 if is_known_param_type(name, name) == 0:
388 values = ctxt.xpathEval("/api/symbols/enum[@type='%s']" % name)
389 i = 0
390 vals = []
391 for value in values:
392 vname = value.xpathEval('string(@name)')
393 if vname == None:
394 continue;
395 i = i + 1
396 if i >= 5:
397 break;
398 vals.append(vname)
399 if vals == []:
400 print "Didn't found any value for enum %s" % (name)
401 continue
402 test.write("#define gen_nb_%s %d\n" % (name, len(vals)))
403 test.write("""static %s gen_%s(int no, int nr ATTRIBUTE_UNUSED) {\n""" %
404 (name, name))
405 i = 1
406 for value in vals:
407 test.write(" if (no == %d) return(%s);\n" % (i, value))
408 i = i + 1
409 test.write(""" return(0);
410}
411""");
412 known_param_types.append(name)
413
414 if is_known_return_type(name) == 0:
415 test.write("""static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
416}
417static void desret_%s(%s val ATTRIBUTE_UNUSED) {
418}
419
420""" % (name, name, name, name))
421 known_return_types.append(name)
Daniel Veillard34099b42004-11-04 17:34:35 +0000422
423#
424# Load the interfaces
425#
Daniel Veillard57b25162004-11-06 14:50:18 +0000426headers = ctxt.xpathEval("/api/files/file")
Daniel Veillard34099b42004-11-04 17:34:35 +0000427for file in headers:
428 name = file.xpathEval('string(@name)')
429 if (name == None) or (name == ''):
430 continue
431
432 #
433 # Some module may be skipped because they don't really consists
434 # of user callable APIs
435 #
436 if is_skipped_module(name):
437 continue
438
439 #
440 # do not test deprecated APIs
441 #
442 desc = file.xpathEval('string(description)')
443 if string.find(desc, 'DEPRECATED') != -1:
444 print "Skipping deprecated interface %s" % name
445 continue;
446
447 test.write("#include <libxml/%s.h>\n" % name)
448 modules.append(name)
449
450#
451# Generate the callers signatures
452#
453for module in modules:
454 test.write("static int test_%s(void);\n" % module);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000455
456#
457# Generate the top caller
458#
459
460test.write("""
461/**
462 * testlibxml2:
463 *
464 * Main entry point of the tester for the full libxml2 module,
465 * it calls all the tester entry point for each module.
466 *
467 * Returns the number of error found
468 */
469static int
470testlibxml2(void)
471{
Daniel Veillard42595322004-11-08 10:52:06 +0000472 int test_ret = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000473
474""")
475
476for module in modules:
Daniel Veillard42595322004-11-08 10:52:06 +0000477 test.write(" test_ret += test_%s();\n" % module)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000478
479test.write("""
Daniel Veillard3d97e662004-11-04 10:49:00 +0000480 printf("Total: %d functions, %d tests, %d errors\\n",
Daniel Veillard42595322004-11-08 10:52:06 +0000481 function_tests, call_tests, test_ret);
482 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000483}
484
485""")
486
487#
488# How to handle a function
489#
490nb_tests = 0
491
492def generate_test(module, node):
493 global test
494 global nb_tests
495 nb_cond = 0
496 no_gen = 0
497
498 name = node.xpathEval('string(@name)')
499 if is_skipped_function(name):
500 return
501
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000502 #
503 # check we know how to handle the args and return values
504 # and store the informations for the generation
505 #
506 try:
507 args = node.xpathEval("arg")
508 except:
509 args = []
510 t_args = []
Daniel Veillarda03e3652004-11-02 18:45:30 +0000511 n = 0
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000512 for arg in args:
Daniel Veillarda03e3652004-11-02 18:45:30 +0000513 n = n + 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000514 rtype = arg.xpathEval("string(@type)")
515 if rtype == 'void':
516 break;
517 info = arg.xpathEval("string(@info)")
518 nam = arg.xpathEval("string(@name)")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000519 type = type_convert(rtype, nam, info, module, name, n)
Daniel Veillardce682bc2004-11-05 17:22:25 +0000520 if is_known_param_type(type, rtype) == 0:
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000521 add_missing_type(type, name);
522 no_gen = 1
523 t_args.append((nam, type, rtype, info))
524
525 try:
526 rets = node.xpathEval("return")
527 except:
528 rets = []
529 t_ret = None
530 for ret in rets:
531 rtype = ret.xpathEval("string(@type)")
532 info = ret.xpathEval("string(@info)")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000533 type = type_convert(rtype, 'return', info, module, name, 0)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000534 if rtype == 'void':
535 break
536 if is_known_return_type(type) == 0:
537 add_missing_type(type, name);
538 no_gen = 1
539 t_ret = (type, rtype, info)
540 break
541
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000542 test.write("""
543static int
544test_%s(void) {
Daniel Veillard42595322004-11-08 10:52:06 +0000545 int test_ret = 0;
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000546
547""" % (name))
548
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000549 if no_gen == 1:
Daniel Veillard34099b42004-11-04 17:34:35 +0000550 add_missing_functions(name, module)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000551 test.write("""
552 /* missing type support */
Daniel Veillard42595322004-11-08 10:52:06 +0000553 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000554}
555
556""")
557 return
558
559 try:
560 conds = node.xpathEval("cond")
561 for cond in conds:
562 test.write("#ifdef %s\n" % (cond.get_content()))
563 nb_cond = nb_cond + 1
564 except:
565 pass
566
567 # Declare the memory usage counter
568 no_mem = is_skipped_memcheck(name)
569 if no_mem == 0:
570 test.write(" int mem_base;\n");
571
572 # Declare the return value
573 if t_ret != None:
574 test.write(" %s ret_val;\n" % (t_ret[1]))
575
576 # Declare the arguments
577 for arg in t_args:
578 (nam, type, rtype, info) = arg;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000579 if (type[-3:] == 'Ptr' or type[-4:] == '_ptr') and \
580 rtype[0:6] == 'const ':
581 crtype = rtype[6:]
582 else:
583 crtype = rtype
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000584 # add declaration
Daniel Veillardce682bc2004-11-05 17:22:25 +0000585 test.write(" %s %s; /* %s */\n" % (crtype, nam, info))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000586 test.write(" int n_%s;\n" % (nam))
587 test.write("\n")
588
589 # Cascade loop on of each argument list of values
590 for arg in t_args:
591 (nam, type, rtype, info) = arg;
592 #
593 test.write(" for (n_%s = 0;n_%s < gen_nb_%s;n_%s++) {\n" % (
594 nam, nam, type, nam))
595
596 # log the memory usage
597 if no_mem == 0:
598 test.write(" mem_base = xmlMemBlocks();\n");
599
600 # prepare the call
Daniel Veillard3d97e662004-11-04 10:49:00 +0000601 i = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000602 for arg in t_args:
603 (nam, type, rtype, info) = arg;
604 #
Daniel Veillard3d97e662004-11-04 10:49:00 +0000605 test.write(" %s = gen_%s(n_%s, %d);\n" % (nam, type, nam, i))
606 i = i + 1;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000607
608 # do the call, and clanup the result
Daniel Veillard34099b42004-11-04 17:34:35 +0000609 if extra_pre_call.has_key(name):
610 test.write(" %s\n"% (extra_pre_call[name]))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000611 if t_ret != None:
612 test.write("\n ret_val = %s(" % (name))
613 need = 0
614 for arg in t_args:
615 (nam, type, rtype, info) = arg
616 if need:
617 test.write(", ")
618 else:
619 need = 1
620 test.write("%s" % nam);
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000621 test.write(");\n")
622 if extra_post_call.has_key(name):
623 test.write(" %s\n"% (extra_post_call[name]))
624 test.write(" desret_%s(ret_val);\n" % t_ret[0])
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000625 else:
626 test.write("\n %s(" % (name));
627 need = 0;
628 for arg in t_args:
629 (nam, type, rtype, info) = arg;
630 if need:
631 test.write(", ")
632 else:
633 need = 1
634 test.write("%s" % nam)
635 test.write(");\n")
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000636 if extra_post_call.has_key(name):
637 test.write(" %s\n"% (extra_post_call[name]))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000638
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000639 test.write(" call_tests++;\n");
Daniel Veillarda03e3652004-11-02 18:45:30 +0000640
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000641 # Free the arguments
Daniel Veillard3d97e662004-11-04 10:49:00 +0000642 i = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000643 for arg in t_args:
644 (nam, type, rtype, info) = arg;
645 #
Daniel Veillard3d97e662004-11-04 10:49:00 +0000646 test.write(" des_%s(n_%s, %s, %d);\n" % (type, nam, nam, i))
647 i = i + 1;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000648
649 test.write(" xmlResetLastError();\n");
650 # Check the memory usage
651 if no_mem == 0:
652 test.write(""" if (mem_base != xmlMemBlocks()) {
Daniel Veillarda03e3652004-11-02 18:45:30 +0000653 printf("Leak of %%d blocks found in %s",
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000654 xmlMemBlocks() - mem_base);
Daniel Veillard42595322004-11-08 10:52:06 +0000655 test_ret++;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000656""" % (name));
Daniel Veillarda03e3652004-11-02 18:45:30 +0000657 for arg in t_args:
658 (nam, type, rtype, info) = arg;
659 test.write(""" printf(" %%d", n_%s);\n""" % (nam))
660 test.write(""" printf("\\n");\n""")
661 test.write(" }\n")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000662
663 for arg in t_args:
664 test.write(" }\n")
665
666 #
667 # end of conditional
668 #
669 while nb_cond > 0:
670 test.write("#endif\n")
671 nb_cond = nb_cond -1
672
673 nb_tests = nb_tests + 1;
674
675 test.write("""
Daniel Veillard3d97e662004-11-04 10:49:00 +0000676 function_tests++;
Daniel Veillard42595322004-11-08 10:52:06 +0000677 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000678}
679
680""")
681
682#
683# Generate all module callers
684#
685for module in modules:
686 # gather all the functions exported by that module
687 try:
688 functions = ctxt.xpathEval("/api/symbols/function[@file='%s']" % (module))
689 except:
690 print "Failed to gather functions from module %s" % (module)
691 continue;
692
693 # iterate over all functions in the module generating the test
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000694 i = 0
695 nb_tests_old = nb_tests
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000696 for function in functions:
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000697 i = i + 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000698 generate_test(module, function);
699
700 # header
701 test.write("""static int
702test_%s(void) {
Daniel Veillard42595322004-11-08 10:52:06 +0000703 int test_ret = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000704
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000705 printf("Testing %s : %d of %d functions ...\\n");
706""" % (module, module, nb_tests - nb_tests_old, i))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000707
708 # iterate over all functions in the module generating the call
709 for function in functions:
710 name = function.xpathEval('string(@name)')
711 if is_skipped_function(name):
712 continue
Daniel Veillard42595322004-11-08 10:52:06 +0000713 test.write(" test_ret += test_%s();\n" % (name))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000714
715 # footer
716 test.write("""
Daniel Veillard42595322004-11-08 10:52:06 +0000717 if (test_ret != 0)
718 printf("Module %s: %%d errors\\n", test_ret);
719 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000720}
721""" % (module))
722
Daniel Veillardce244ad2004-11-05 10:03:46 +0000723#
724# Generate direct module caller
725#
726test.write("""static int
727test_module(const char *module) {
728""");
729for module in modules:
730 test.write(""" if (!strcmp(module, "%s")) return(test_%s());\n""" % (
731 module, module))
732test.write(""" return(0);
733}
734""");
735
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000736print "Generated test for %d modules and %d functions" %(len(modules), nb_tests)
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000737
Daniel Veillard34099b42004-11-04 17:34:35 +0000738compare_and_save()
739
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000740missing_list = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000741for missing in missing_types.keys():
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000742 if missing == 'va_list' or missing == '...':
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000743 continue;
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000744
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000745 n = len(missing_types[missing])
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000746 missing_list.append((n, missing))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000747
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000748def compare_missing(a, b):
749 return b[0] - a[0]
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000750
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000751missing_list.sort(compare_missing)
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000752print "Missing support for %d functions and %d types see missing.lst" % (missing_functions_nr, len(missing_list))
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000753lst = open("missing.lst", "w")
Daniel Veillard34099b42004-11-04 17:34:35 +0000754lst.write("Missing support for %d types" % (len(missing_list)))
755lst.write("\n")
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000756for miss in missing_list:
757 lst.write("%s: %d :" % (miss[1], miss[0]))
758 i = 0
759 for n in missing_types[miss[1]]:
760 i = i + 1
761 if i > 5:
762 lst.write(" ...")
763 break
764 lst.write(" %s" % (n))
765 lst.write("\n")
Daniel Veillard34099b42004-11-04 17:34:35 +0000766lst.write("\n")
767lst.write("\n")
768lst.write("Missing support per module");
769for module in missing_functions.keys():
770 lst.write("module %s:\n %s\n" % (module, missing_functions[module]))
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000771
772lst.close()
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000773
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000774