blob: 927ecd8a540d0fabf4ef334c950585404aed8e6d [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#
17skipped_modules = [ "SAX", "SAX2", "xlink", "threads", "globals",
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +000018 "xpathInternals", "parserInternals", "xmlmemory",
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +000019 "xmlversion", "debugXML", "xmlexports", "DOCBparser",
Daniel Veillardd005b9e2004-11-03 17:07:05 +000020
21 # temporary
Daniel Veillard3d97e662004-11-04 10:49:00 +000022 "xmlautomata", "xmlregexp", "c14n",
Daniel Veillardd005b9e2004-11-03 17:07:05 +000023
24]
Daniel Veillard36e5cd52004-11-02 14:52:23 +000025
26#
27# Some function really need to be skipped for the tests.
28#
Daniel Veillarddd6d3002004-11-03 14:20:29 +000029skipped_functions = [
30# block on I/O
31"xmlFdRead", "xmlReadFd", "xmlCtxtReadFd",
32"htmlFdRead", "htmlReadFd", "htmlCtxtReadFd",
Daniel Veillard1ba06bb2004-11-04 12:32:18 +000033"xmlReaderNewFd", "xmlReaderForFd",
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +000034"xmlIORead", "xmlReadIO", "xmlCtxtReadIO",
35"htmlIORead", "htmlReadIO", "htmlCtxtReadIO",
Daniel Veillard27f20102004-11-05 11:50:11 +000036"xmlReaderNewIO", "xmlBufferDump", "xmlNanoFTPConnect",
37"xmlNanoFTPConnectTo",
Daniel Veillard42595322004-11-08 10:52:06 +000038# Complex I/O APIs
39"xmlCreateIOParserCtxt", "xmlParserInputBufferCreateIO",
40"xmlRegisterInputCallbacks", "xmlReaderForIO",
41"xmlOutputBufferCreateIO", "xmlRegisterOutputCallbacks",
42"xmlSaveToIO",
Daniel Veillarddd6d3002004-11-03 14:20:29 +000043# library state cleanup, generate false leak informations and other
44# troubles, heavillyb tested otherwise.
Daniel Veillardce244ad2004-11-05 10:03:46 +000045"xmlCleanupParser", "xmlRelaxNGCleanupTypes", "xmlSetListDoc",
46"xmlSetTreeDoc", "xmlUnlinkNode",
Daniel Veillarddd6d3002004-11-03 14:20:29 +000047# hard to avoid leaks in the tests
Daniel Veillardd5cc0f72004-11-06 19:24:28 +000048"xmlStrcat", "xmlStrncat", "xmlCatalogAddLocal", "xmlNewTextWriterDoc",
Daniel Veillarddd6d3002004-11-03 14:20:29 +000049# unimplemented
50"xmlTextReaderReadInnerXml", "xmlTextReaderReadOuterXml",
Daniel Veillardd005b9e2004-11-03 17:07:05 +000051"xmlTextReaderReadString",
52# destructor
Daniel Veillard27f20102004-11-05 11:50:11 +000053"xmlListDelete", "xmlOutputBufferClose", "xmlNanoFTPClose",
Daniel Veillardd005b9e2004-11-03 17:07:05 +000054# deprecated
55"xmlCatalogGetPublic", "xmlCatalogGetSystem", "xmlEncodeEntities",
Daniel Veillardd5cc0f72004-11-06 19:24:28 +000056"xmlNewGlobalNs",
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +000057# allocators
58"xmlMemFree",
Daniel Veillardc2c894f2004-11-07 12:17:35 +000059# verbosity
60"xmlCatalogSetDebug",
Daniel Veillarddd6d3002004-11-03 14:20:29 +000061]
Daniel Veillard36e5cd52004-11-02 14:52:23 +000062
63#
64# Those functions have side effect on the global state
65# and hence generate errors on memory allocation tests
66#
67skipped_memcheck = [ "xmlLoadCatalog", "xmlAddEncodingAlias",
68 "xmlSchemaInitTypes", "xmlNanoFTPProxy", "xmlNanoFTPScanProxy",
69 "xmlNanoHTTPScanProxy", "xmlResetLastError", "xmlCatalogConvert",
70 "xmlCatalogRemove", "xmlLoadCatalogs", "xmlCleanupCharEncodingHandlers",
Daniel Veillarda03e3652004-11-02 18:45:30 +000071 "xmlInitCharEncodingHandlers", "xmlCatalogCleanup",
Daniel Veillard42595322004-11-08 10:52:06 +000072 "xmlSchemaGetBuiltInType",
73 "htmlParseFile", # loads the catalogs
Daniel Veillarda03e3652004-11-02 18:45:30 +000074]
75
76#
77# Extra code needed for some test cases
78#
Daniel Veillard34099b42004-11-04 17:34:35 +000079extra_pre_call = {
80 "xmlSAXUserParseFile":
Daniel Veillardce244ad2004-11-05 10:03:46 +000081 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
Daniel Veillard34099b42004-11-04 17:34:35 +000082 "xmlSAXUserParseMemory":
Daniel Veillardce244ad2004-11-05 10:03:46 +000083 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
Daniel Veillardce682bc2004-11-05 17:22:25 +000084 "xmlParseBalancedChunkMemory":
85 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
86 "xmlParseBalancedChunkMemoryRecover":
87 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
Daniel Veillardd5cc0f72004-11-06 19:24:28 +000088 "xmlParserInputBufferCreateFd":
89 "if (fd >= 0) fd = -1;",
Daniel Veillard34099b42004-11-04 17:34:35 +000090}
Daniel Veillarda03e3652004-11-02 18:45:30 +000091extra_post_call = {
92 "xmlAddChild":
93 "if (ret_val == NULL) { xmlFreeNode(cur) ; cur = NULL ; }",
94 "xmlAddChildList":
95 "if (ret_val == NULL) { xmlFreeNodeList(cur) ; cur = NULL ; }",
96 "xmlAddSibling":
97 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
98 "xmlAddNextSibling":
99 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
100 "xmlAddPrevSibling":
101 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
102 "xmlDocSetRootElement":
103 "if (doc == NULL) { xmlFreeNode(root) ; root = NULL ; }",
104 "xmlReplaceNode":
Daniel Veillardce244ad2004-11-05 10:03:46 +0000105 """if (cur != NULL) {
106 xmlUnlinkNode(cur);
107 xmlFreeNode(cur) ; cur = NULL ; }
108 if (old != NULL) {
109 xmlUnlinkNode(old);
110 xmlFreeNode(old) ; old = NULL ; }
111 ret_val = NULL;""",
Daniel Veillarda03e3652004-11-02 18:45:30 +0000112 "xmlTextMerge":
113 """if ((first != NULL) && (first->type != XML_TEXT_NODE)) {
Daniel Veillardce244ad2004-11-05 10:03:46 +0000114 xmlUnlinkNode(second);
Daniel Veillarda03e3652004-11-02 18:45:30 +0000115 xmlFreeNode(second) ; second = NULL ; }""",
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000116 "xmlBuildQName":
117 """if ((ret_val != NULL) && (ret_val != ncname) &&
118 (ret_val != prefix) && (ret_val != memory))
119 xmlFree(ret_val);
120 ret_val = NULL;""",
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000121 "xmlDictReference": "xmlDictFree(dict);",
Daniel Veillard3d97e662004-11-04 10:49:00 +0000122 # Functions which deallocates one of their parameters
123 "xmlXPathConvertBoolean": """val = NULL;""",
124 "xmlXPathConvertNumber": """val = NULL;""",
125 "xmlXPathConvertString": """val = NULL;""",
126 "xmlSaveFileTo": """buf = NULL;""",
Daniel Veillard34099b42004-11-04 17:34:35 +0000127 "xmlSaveFormatFileTo": """buf = NULL;""",
128 "xmlIOParseDTD": "input = NULL;",
Daniel Veillardce244ad2004-11-05 10:03:46 +0000129 "xmlRemoveProp": "cur = NULL;",
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000130 "xmlNewNs": "if ((node == NULL) && (ret_val != NULL)) xmlFreeNs(ret_val);",
131 "xmlCopyNamespace": "if (ret_val != NULL) xmlFreeNs(ret_val);",
132 "xmlCopyNamespaceList": "if (ret_val != NULL) xmlFreeNsList(ret_val);",
133 "xmlNewTextWriter": "if (ret_val != NULL) out = NULL;",
134 "xmlNewTextWriterPushParser": "if (ret_val != NULL) ctxt = NULL;",
Daniel Veillard42595322004-11-08 10:52:06 +0000135 "xmlNewIOInputStream": "if (ret_val != NULL) input = NULL;",
Daniel Veillarda03e3652004-11-02 18:45:30 +0000136}
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000137
138modules = []
139
140def is_skipped_module(name):
141 for mod in skipped_modules:
142 if mod == name:
143 return 1
144 return 0
145
146def is_skipped_function(name):
147 for fun in skipped_functions:
148 if fun == name:
149 return 1
150 # Do not test destructors
151 if string.find(name, 'Free') != -1:
152 return 1
153 return 0
154
155def is_skipped_memcheck(name):
156 for fun in skipped_memcheck:
157 if fun == name:
158 return 1
159 return 0
160
161missing_types = {}
162def add_missing_type(name, func):
163 try:
164 list = missing_types[name]
165 list.append(func)
166 except:
167 missing_types[name] = [func]
168
Daniel Veillardce682bc2004-11-05 17:22:25 +0000169generated_param_types = []
170def add_generated_param_type(name):
171 generated_param_types.append(name)
172
173generated_return_types = []
174def add_generated_return_type(name):
175 generated_return_types.append(name)
176
Daniel Veillard34099b42004-11-04 17:34:35 +0000177missing_functions = {}
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000178missing_functions_nr = 0
Daniel Veillard34099b42004-11-04 17:34:35 +0000179def add_missing_functions(name, module):
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000180 global missing_functions_nr
181
182 missing_functions_nr = missing_functions_nr + 1
Daniel Veillard34099b42004-11-04 17:34:35 +0000183 try:
184 list = missing_functions[module]
185 list.append(name)
186 except:
187 missing_functions[module] = [name]
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000188
189#
190# Provide the type generators and destructors for the parameters
191#
192
Daniel Veillarda03e3652004-11-02 18:45:30 +0000193def type_convert(str, name, info, module, function, pos):
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000194# res = string.replace(str, " ", " ")
195# res = string.replace(str, " ", " ")
196# res = string.replace(str, " ", " ")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000197 res = string.replace(str, " *", "_ptr")
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000198# res = string.replace(str, "*", "_ptr")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000199 res = string.replace(res, " ", "_")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000200 res = string.replace(res, "htmlNode", "xmlNode")
201 res = string.replace(res, "htmlDoc", "xmlDoc")
202 res = string.replace(res, "htmlParser", "xmlParser")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000203 if res == 'const_char_ptr':
204 if string.find(name, "file") != -1 or \
205 string.find(name, "uri") != -1 or \
206 string.find(name, "URI") != -1 or \
207 string.find(info, "filename") != -1 or \
208 string.find(info, "URI") != -1 or \
209 string.find(info, "URL") != -1:
William M. Brack83d9c372004-11-08 02:26:08 +0000210 if string.find(function, "Save") != -1 or \
211 string.find(function, "Create") != -1 or \
212 string.find(function, "Write") != -1:
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000213 return('fileoutput')
214 return('filepath')
215 if res == 'void_ptr':
216 if module == 'nanoftp' and name == 'ctx':
217 return('xmlNanoFTPCtxtPtr')
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000218 if function == 'xmlNanoFTPNewCtxt':
219 return('xmlNanoFTPCtxtPtr')
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000220 if module == 'nanohttp' and name == 'ctx':
221 return('xmlNanoHTTPCtxtPtr')
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000222 if function == 'xmlIOHTTPOpenW':
223 return('xmlNanoHTTPCtxtPtr')
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000224 if string.find(name, "data") != -1:
225 return('userdata');
Daniel Veillardd005b9e2004-11-03 17:07:05 +0000226 if string.find(name, "user") != -1:
227 return('userdata');
Daniel Veillard3d97e662004-11-04 10:49:00 +0000228 if res == 'xmlDoc_ptr':
229 res = 'xmlDocPtr';
230 if res == 'xmlNode_ptr':
231 res = 'xmlNodePtr';
232 if res == 'xmlDict_ptr':
233 res = 'xmlDictPtr';
Daniel Veillarda03e3652004-11-02 18:45:30 +0000234 if res == 'xmlNodePtr' and pos != 0:
235 if (function == 'xmlAddChild' and pos == 2) or \
236 (function == 'xmlAddChildList' and pos == 2) or \
237 (function == 'xmlAddNextSibling' and pos == 2) or \
238 (function == 'xmlAddSibling' and pos == 2) or \
239 (function == 'xmlDocSetRootElement' and pos == 2) or \
240 (function == 'xmlReplaceNode' and pos == 2) or \
241 (function == 'xmlTextMerge') or \
242 (function == 'xmlAddPrevSibling' and pos == 2):
243 return('xmlNodePtr_in');
Daniel Veillard34099b42004-11-04 17:34:35 +0000244 if res == 'const xmlBufferPtr':
245 res = 'xmlBufferPtr';
Daniel Veillard27f20102004-11-05 11:50:11 +0000246 if res == 'xmlChar_ptr' and name == 'name' and \
247 string.find(function, "EatName") != -1:
248 return('eaten_name')
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000249 if res == 'void_ptr*':
250 res = 'void_ptr_ptr'
251 if res == 'char_ptr*':
252 res = 'char_ptr_ptr'
253 if res == 'xmlChar_ptr*':
254 res = 'xmlChar_ptr_ptr'
255 if res == 'const_xmlChar_ptr*':
256 res = 'const_xmlChar_ptr_ptr'
257 if res == 'const_char_ptr*':
258 res = 'const_char_ptr_ptr'
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000259
260 return res
261
Daniel Veillard34099b42004-11-04 17:34:35 +0000262known_param_types = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000263
Daniel Veillardce682bc2004-11-05 17:22:25 +0000264def is_known_param_type(name, rtype):
265 global test
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000266 for type in known_param_types:
267 if type == name:
268 return 1
Daniel Veillardce682bc2004-11-05 17:22:25 +0000269 for type in generated_param_types:
270 if type == name:
271 return 1
272
273 if name[-3:] == 'Ptr' or name[-4:] == '_ptr':
274 if rtype[0:6] == 'const ':
275 crtype = rtype[6:]
276 else:
277 crtype = rtype
278
279 test.write("""
280#define gen_nb_%s 1
281static %s gen_%s(int no ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
282 return(NULL);
283}
284static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
285}
286""" % (name, crtype, name, name, rtype))
287 add_generated_param_type(name)
288 return 1
289
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000290 return 0
291
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000292#
293# Provide the type destructors for the return values
294#
295
Daniel Veillard34099b42004-11-04 17:34:35 +0000296known_return_types = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000297
298def is_known_return_type(name):
299 for type in known_return_types:
300 if type == name:
301 return 1
302 return 0
303
Daniel Veillard34099b42004-11-04 17:34:35 +0000304#
305# Copy the beginning of the C test program result
306#
307
308input = open("testapi.c", "r")
309test = open('testapi.c.new', 'w')
310
311def compare_and_save():
312 global test
313
314 test.close()
315 input = open("testapi.c", "r").read()
316 test = open('testapi.c.new', "r").read()
317 if input != test:
318 os.system("rm testapi.c ; mv testapi.c.new testapi.c")
319 print("Updated testapi.c")
320 else:
321 print("Generated testapi.c is identical")
322
323line = input.readline()
324while line != "":
325 if line == "/* CUT HERE: everything below that line is generated */\n":
326 break;
327 if line[0:15] == "#define gen_nb_":
328 type = string.split(line[15:])[0]
329 known_param_types.append(type)
330 if line[0:19] == "static void desret_":
331 type = string.split(line[19:], '(')[0]
332 known_return_types.append(type)
333 test.write(line)
334 line = input.readline()
335input.close()
336
337if line == "":
338 print "Could not find the CUT marker in testapi.c skipping generation"
339 test.close()
340 sys.exit(0)
341
342print("Scanned testapi.c: found %d parameters types and %d return types\n" % (
343 len(known_param_types), len(known_return_types)))
344test.write("/* CUT HERE: everything below that line is generated */\n")
345
346
347#
348# Open the input API description
349#
350doc = libxml2.readFile('doc/libxml2-api.xml', None, 0)
351if doc == None:
352 print "Failed to load doc/libxml2-api.xml"
353 sys.exit(1)
354ctxt = doc.xpathNewContext()
Daniel Veillard57b25162004-11-06 14:50:18 +0000355
356#
357# Generate constructors and return type handling for all enums
358#
359enums = ctxt.xpathEval("/api/symbols/typedef[@type='enum']")
360for enum in enums:
361 name = enum.xpathEval('string(@name)')
362 if name == None:
363 continue;
364
365 if is_known_param_type(name, name) == 0:
366 values = ctxt.xpathEval("/api/symbols/enum[@type='%s']" % name)
367 i = 0
368 vals = []
369 for value in values:
370 vname = value.xpathEval('string(@name)')
371 if vname == None:
372 continue;
373 i = i + 1
374 if i >= 5:
375 break;
376 vals.append(vname)
377 if vals == []:
378 print "Didn't found any value for enum %s" % (name)
379 continue
380 test.write("#define gen_nb_%s %d\n" % (name, len(vals)))
381 test.write("""static %s gen_%s(int no, int nr ATTRIBUTE_UNUSED) {\n""" %
382 (name, name))
383 i = 1
384 for value in vals:
385 test.write(" if (no == %d) return(%s);\n" % (i, value))
386 i = i + 1
387 test.write(""" return(0);
388}
389""");
390 known_param_types.append(name)
391
392 if is_known_return_type(name) == 0:
393 test.write("""static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
394}
395static void desret_%s(%s val ATTRIBUTE_UNUSED) {
396}
397
398""" % (name, name, name, name))
399 known_return_types.append(name)
Daniel Veillard34099b42004-11-04 17:34:35 +0000400
401#
402# Load the interfaces
403#
Daniel Veillard57b25162004-11-06 14:50:18 +0000404headers = ctxt.xpathEval("/api/files/file")
Daniel Veillard34099b42004-11-04 17:34:35 +0000405for file in headers:
406 name = file.xpathEval('string(@name)')
407 if (name == None) or (name == ''):
408 continue
409
410 #
411 # Some module may be skipped because they don't really consists
412 # of user callable APIs
413 #
414 if is_skipped_module(name):
415 continue
416
417 #
418 # do not test deprecated APIs
419 #
420 desc = file.xpathEval('string(description)')
421 if string.find(desc, 'DEPRECATED') != -1:
422 print "Skipping deprecated interface %s" % name
423 continue;
424
425 test.write("#include <libxml/%s.h>\n" % name)
426 modules.append(name)
427
428#
429# Generate the callers signatures
430#
431for module in modules:
432 test.write("static int test_%s(void);\n" % module);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000433
434#
435# Generate the top caller
436#
437
438test.write("""
439/**
440 * testlibxml2:
441 *
442 * Main entry point of the tester for the full libxml2 module,
443 * it calls all the tester entry point for each module.
444 *
445 * Returns the number of error found
446 */
447static int
448testlibxml2(void)
449{
Daniel Veillard42595322004-11-08 10:52:06 +0000450 int test_ret = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000451
452""")
453
454for module in modules:
Daniel Veillard42595322004-11-08 10:52:06 +0000455 test.write(" test_ret += test_%s();\n" % module)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000456
457test.write("""
Daniel Veillard3d97e662004-11-04 10:49:00 +0000458 printf("Total: %d functions, %d tests, %d errors\\n",
Daniel Veillard42595322004-11-08 10:52:06 +0000459 function_tests, call_tests, test_ret);
460 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000461}
462
463""")
464
465#
466# How to handle a function
467#
468nb_tests = 0
469
470def generate_test(module, node):
471 global test
472 global nb_tests
473 nb_cond = 0
474 no_gen = 0
475
476 name = node.xpathEval('string(@name)')
477 if is_skipped_function(name):
478 return
479
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000480 #
481 # check we know how to handle the args and return values
482 # and store the informations for the generation
483 #
484 try:
485 args = node.xpathEval("arg")
486 except:
487 args = []
488 t_args = []
Daniel Veillarda03e3652004-11-02 18:45:30 +0000489 n = 0
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000490 for arg in args:
Daniel Veillarda03e3652004-11-02 18:45:30 +0000491 n = n + 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000492 rtype = arg.xpathEval("string(@type)")
493 if rtype == 'void':
494 break;
495 info = arg.xpathEval("string(@info)")
496 nam = arg.xpathEval("string(@name)")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000497 type = type_convert(rtype, nam, info, module, name, n)
Daniel Veillardce682bc2004-11-05 17:22:25 +0000498 if is_known_param_type(type, rtype) == 0:
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000499 add_missing_type(type, name);
500 no_gen = 1
501 t_args.append((nam, type, rtype, info))
502
503 try:
504 rets = node.xpathEval("return")
505 except:
506 rets = []
507 t_ret = None
508 for ret in rets:
509 rtype = ret.xpathEval("string(@type)")
510 info = ret.xpathEval("string(@info)")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000511 type = type_convert(rtype, 'return', info, module, name, 0)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000512 if rtype == 'void':
513 break
514 if is_known_return_type(type) == 0:
515 add_missing_type(type, name);
516 no_gen = 1
517 t_ret = (type, rtype, info)
518 break
519
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000520 test.write("""
521static int
522test_%s(void) {
Daniel Veillard42595322004-11-08 10:52:06 +0000523 int test_ret = 0;
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000524
525""" % (name))
526
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000527 if no_gen == 1:
Daniel Veillard34099b42004-11-04 17:34:35 +0000528 add_missing_functions(name, module)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000529 test.write("""
530 /* missing type support */
Daniel Veillard42595322004-11-08 10:52:06 +0000531 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000532}
533
534""")
535 return
536
537 try:
538 conds = node.xpathEval("cond")
539 for cond in conds:
540 test.write("#ifdef %s\n" % (cond.get_content()))
541 nb_cond = nb_cond + 1
542 except:
543 pass
544
545 # Declare the memory usage counter
546 no_mem = is_skipped_memcheck(name)
547 if no_mem == 0:
548 test.write(" int mem_base;\n");
549
550 # Declare the return value
551 if t_ret != None:
552 test.write(" %s ret_val;\n" % (t_ret[1]))
553
554 # Declare the arguments
555 for arg in t_args:
556 (nam, type, rtype, info) = arg;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000557 if (type[-3:] == 'Ptr' or type[-4:] == '_ptr') and \
558 rtype[0:6] == 'const ':
559 crtype = rtype[6:]
560 else:
561 crtype = rtype
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000562 # add declaration
Daniel Veillardce682bc2004-11-05 17:22:25 +0000563 test.write(" %s %s; /* %s */\n" % (crtype, nam, info))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000564 test.write(" int n_%s;\n" % (nam))
565 test.write("\n")
566
567 # Cascade loop on of each argument list of values
568 for arg in t_args:
569 (nam, type, rtype, info) = arg;
570 #
571 test.write(" for (n_%s = 0;n_%s < gen_nb_%s;n_%s++) {\n" % (
572 nam, nam, type, nam))
573
574 # log the memory usage
575 if no_mem == 0:
576 test.write(" mem_base = xmlMemBlocks();\n");
577
578 # prepare the call
Daniel Veillard3d97e662004-11-04 10:49:00 +0000579 i = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000580 for arg in t_args:
581 (nam, type, rtype, info) = arg;
582 #
Daniel Veillard3d97e662004-11-04 10:49:00 +0000583 test.write(" %s = gen_%s(n_%s, %d);\n" % (nam, type, nam, i))
584 i = i + 1;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000585
586 # do the call, and clanup the result
Daniel Veillard34099b42004-11-04 17:34:35 +0000587 if extra_pre_call.has_key(name):
588 test.write(" %s\n"% (extra_pre_call[name]))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000589 if t_ret != None:
590 test.write("\n ret_val = %s(" % (name))
591 need = 0
592 for arg in t_args:
593 (nam, type, rtype, info) = arg
594 if need:
595 test.write(", ")
596 else:
597 need = 1
598 test.write("%s" % nam);
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000599 test.write(");\n")
600 if extra_post_call.has_key(name):
601 test.write(" %s\n"% (extra_post_call[name]))
602 test.write(" desret_%s(ret_val);\n" % t_ret[0])
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000603 else:
604 test.write("\n %s(" % (name));
605 need = 0;
606 for arg in t_args:
607 (nam, type, rtype, info) = arg;
608 if need:
609 test.write(", ")
610 else:
611 need = 1
612 test.write("%s" % nam)
613 test.write(");\n")
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000614 if extra_post_call.has_key(name):
615 test.write(" %s\n"% (extra_post_call[name]))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000616
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000617 test.write(" call_tests++;\n");
Daniel Veillarda03e3652004-11-02 18:45:30 +0000618
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000619 # Free the arguments
Daniel Veillard3d97e662004-11-04 10:49:00 +0000620 i = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000621 for arg in t_args:
622 (nam, type, rtype, info) = arg;
623 #
Daniel Veillard3d97e662004-11-04 10:49:00 +0000624 test.write(" des_%s(n_%s, %s, %d);\n" % (type, nam, nam, i))
625 i = i + 1;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000626
627 test.write(" xmlResetLastError();\n");
628 # Check the memory usage
629 if no_mem == 0:
630 test.write(""" if (mem_base != xmlMemBlocks()) {
Daniel Veillarda03e3652004-11-02 18:45:30 +0000631 printf("Leak of %%d blocks found in %s",
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000632 xmlMemBlocks() - mem_base);
Daniel Veillard42595322004-11-08 10:52:06 +0000633 test_ret++;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000634""" % (name));
Daniel Veillarda03e3652004-11-02 18:45:30 +0000635 for arg in t_args:
636 (nam, type, rtype, info) = arg;
637 test.write(""" printf(" %%d", n_%s);\n""" % (nam))
638 test.write(""" printf("\\n");\n""")
639 test.write(" }\n")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000640
641 for arg in t_args:
642 test.write(" }\n")
643
644 #
645 # end of conditional
646 #
647 while nb_cond > 0:
648 test.write("#endif\n")
649 nb_cond = nb_cond -1
650
651 nb_tests = nb_tests + 1;
652
653 test.write("""
Daniel Veillard3d97e662004-11-04 10:49:00 +0000654 function_tests++;
Daniel Veillard42595322004-11-08 10:52:06 +0000655 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000656}
657
658""")
659
660#
661# Generate all module callers
662#
663for module in modules:
664 # gather all the functions exported by that module
665 try:
666 functions = ctxt.xpathEval("/api/symbols/function[@file='%s']" % (module))
667 except:
668 print "Failed to gather functions from module %s" % (module)
669 continue;
670
671 # iterate over all functions in the module generating the test
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000672 i = 0
673 nb_tests_old = nb_tests
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000674 for function in functions:
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000675 i = i + 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000676 generate_test(module, function);
677
678 # header
679 test.write("""static int
680test_%s(void) {
Daniel Veillard42595322004-11-08 10:52:06 +0000681 int test_ret = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000682
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000683 printf("Testing %s : %d of %d functions ...\\n");
684""" % (module, module, nb_tests - nb_tests_old, i))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000685
686 # iterate over all functions in the module generating the call
687 for function in functions:
688 name = function.xpathEval('string(@name)')
689 if is_skipped_function(name):
690 continue
Daniel Veillard42595322004-11-08 10:52:06 +0000691 test.write(" test_ret += test_%s();\n" % (name))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000692
693 # footer
694 test.write("""
Daniel Veillard42595322004-11-08 10:52:06 +0000695 if (test_ret != 0)
696 printf("Module %s: %%d errors\\n", test_ret);
697 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000698}
699""" % (module))
700
Daniel Veillardce244ad2004-11-05 10:03:46 +0000701#
702# Generate direct module caller
703#
704test.write("""static int
705test_module(const char *module) {
706""");
707for module in modules:
708 test.write(""" if (!strcmp(module, "%s")) return(test_%s());\n""" % (
709 module, module))
710test.write(""" return(0);
711}
712""");
713
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000714print "Generated test for %d modules and %d functions" %(len(modules), nb_tests)
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000715
Daniel Veillard34099b42004-11-04 17:34:35 +0000716compare_and_save()
717
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000718missing_list = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000719for missing in missing_types.keys():
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000720 if missing == 'va_list' or missing == '...':
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000721 continue;
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000722
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000723 n = len(missing_types[missing])
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000724 missing_list.append((n, missing))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000725
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000726def compare_missing(a, b):
727 return b[0] - a[0]
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000728
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000729missing_list.sort(compare_missing)
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000730print "Missing support for %d functions and %d types see missing.lst" % (missing_functions_nr, len(missing_list))
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000731lst = open("missing.lst", "w")
Daniel Veillard34099b42004-11-04 17:34:35 +0000732lst.write("Missing support for %d types" % (len(missing_list)))
733lst.write("\n")
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000734for miss in missing_list:
735 lst.write("%s: %d :" % (miss[1], miss[0]))
736 i = 0
737 for n in missing_types[miss[1]]:
738 i = i + 1
739 if i > 5:
740 lst.write(" ...")
741 break
742 lst.write(" %s" % (n))
743 lst.write("\n")
Daniel Veillard34099b42004-11-04 17:34:35 +0000744lst.write("\n")
745lst.write("\n")
746lst.write("Missing support per module");
747for module in missing_functions.keys():
748 lst.write("module %s:\n %s\n" % (module, missing_functions[module]))
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000749
750lst.close()
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000751
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000752