blob: 77e81a00fe69d3cf9eb5034fc4eaf94264e1b384 [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 Veillarddd6d3002004-11-03 14:20:29 +000038# library state cleanup, generate false leak informations and other
39# troubles, heavillyb tested otherwise.
Daniel Veillardce244ad2004-11-05 10:03:46 +000040"xmlCleanupParser", "xmlRelaxNGCleanupTypes", "xmlSetListDoc",
41"xmlSetTreeDoc", "xmlUnlinkNode",
Daniel Veillarddd6d3002004-11-03 14:20:29 +000042# hard to avoid leaks in the tests
Daniel Veillardd5cc0f72004-11-06 19:24:28 +000043"xmlStrcat", "xmlStrncat", "xmlCatalogAddLocal", "xmlNewTextWriterDoc",
Daniel Veillarddd6d3002004-11-03 14:20:29 +000044# unimplemented
45"xmlTextReaderReadInnerXml", "xmlTextReaderReadOuterXml",
Daniel Veillardd005b9e2004-11-03 17:07:05 +000046"xmlTextReaderReadString",
47# destructor
Daniel Veillard27f20102004-11-05 11:50:11 +000048"xmlListDelete", "xmlOutputBufferClose", "xmlNanoFTPClose",
Daniel Veillardd005b9e2004-11-03 17:07:05 +000049# deprecated
50"xmlCatalogGetPublic", "xmlCatalogGetSystem", "xmlEncodeEntities",
Daniel Veillardd5cc0f72004-11-06 19:24:28 +000051"xmlNewGlobalNs",
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +000052# allocators
53"xmlMemFree",
Daniel Veillardc2c894f2004-11-07 12:17:35 +000054# verbosity
55"xmlCatalogSetDebug",
Daniel Veillarddd6d3002004-11-03 14:20:29 +000056]
Daniel Veillard36e5cd52004-11-02 14:52:23 +000057
58#
59# Those functions have side effect on the global state
60# and hence generate errors on memory allocation tests
61#
62skipped_memcheck = [ "xmlLoadCatalog", "xmlAddEncodingAlias",
63 "xmlSchemaInitTypes", "xmlNanoFTPProxy", "xmlNanoFTPScanProxy",
64 "xmlNanoHTTPScanProxy", "xmlResetLastError", "xmlCatalogConvert",
65 "xmlCatalogRemove", "xmlLoadCatalogs", "xmlCleanupCharEncodingHandlers",
Daniel Veillarda03e3652004-11-02 18:45:30 +000066 "xmlInitCharEncodingHandlers", "xmlCatalogCleanup",
67 "htmlParseFile" # loads the catalogs
68]
69
70#
71# Extra code needed for some test cases
72#
Daniel Veillard34099b42004-11-04 17:34:35 +000073extra_pre_call = {
74 "xmlSAXUserParseFile":
Daniel Veillardce244ad2004-11-05 10:03:46 +000075 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
Daniel Veillard34099b42004-11-04 17:34:35 +000076 "xmlSAXUserParseMemory":
Daniel Veillardce244ad2004-11-05 10:03:46 +000077 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
Daniel Veillardce682bc2004-11-05 17:22:25 +000078 "xmlParseBalancedChunkMemory":
79 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
80 "xmlParseBalancedChunkMemoryRecover":
81 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
Daniel Veillardd5cc0f72004-11-06 19:24:28 +000082 "xmlParserInputBufferCreateFd":
83 "if (fd >= 0) fd = -1;",
Daniel Veillard34099b42004-11-04 17:34:35 +000084}
Daniel Veillarda03e3652004-11-02 18:45:30 +000085extra_post_call = {
86 "xmlAddChild":
87 "if (ret_val == NULL) { xmlFreeNode(cur) ; cur = NULL ; }",
88 "xmlAddChildList":
89 "if (ret_val == NULL) { xmlFreeNodeList(cur) ; cur = NULL ; }",
90 "xmlAddSibling":
91 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
92 "xmlAddNextSibling":
93 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
94 "xmlAddPrevSibling":
95 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
96 "xmlDocSetRootElement":
97 "if (doc == NULL) { xmlFreeNode(root) ; root = NULL ; }",
98 "xmlReplaceNode":
Daniel Veillardce244ad2004-11-05 10:03:46 +000099 """if (cur != NULL) {
100 xmlUnlinkNode(cur);
101 xmlFreeNode(cur) ; cur = NULL ; }
102 if (old != NULL) {
103 xmlUnlinkNode(old);
104 xmlFreeNode(old) ; old = NULL ; }
105 ret_val = NULL;""",
Daniel Veillarda03e3652004-11-02 18:45:30 +0000106 "xmlTextMerge":
107 """if ((first != NULL) && (first->type != XML_TEXT_NODE)) {
Daniel Veillardce244ad2004-11-05 10:03:46 +0000108 xmlUnlinkNode(second);
Daniel Veillarda03e3652004-11-02 18:45:30 +0000109 xmlFreeNode(second) ; second = NULL ; }""",
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000110 "xmlBuildQName":
111 """if ((ret_val != NULL) && (ret_val != ncname) &&
112 (ret_val != prefix) && (ret_val != memory))
113 xmlFree(ret_val);
114 ret_val = NULL;""",
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000115 "xmlDictReference": "xmlDictFree(dict);",
Daniel Veillard3d97e662004-11-04 10:49:00 +0000116 # Functions which deallocates one of their parameters
117 "xmlXPathConvertBoolean": """val = NULL;""",
118 "xmlXPathConvertNumber": """val = NULL;""",
119 "xmlXPathConvertString": """val = NULL;""",
120 "xmlSaveFileTo": """buf = NULL;""",
Daniel Veillard34099b42004-11-04 17:34:35 +0000121 "xmlSaveFormatFileTo": """buf = NULL;""",
122 "xmlIOParseDTD": "input = NULL;",
Daniel Veillardce244ad2004-11-05 10:03:46 +0000123 "xmlRemoveProp": "cur = NULL;",
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000124 "xmlNewNs": "if ((node == NULL) && (ret_val != NULL)) xmlFreeNs(ret_val);",
125 "xmlCopyNamespace": "if (ret_val != NULL) xmlFreeNs(ret_val);",
126 "xmlCopyNamespaceList": "if (ret_val != NULL) xmlFreeNsList(ret_val);",
127 "xmlNewTextWriter": "if (ret_val != NULL) out = NULL;",
128 "xmlNewTextWriterPushParser": "if (ret_val != NULL) ctxt = NULL;",
Daniel Veillarda03e3652004-11-02 18:45:30 +0000129}
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000130
131modules = []
132
133def is_skipped_module(name):
134 for mod in skipped_modules:
135 if mod == name:
136 return 1
137 return 0
138
139def is_skipped_function(name):
140 for fun in skipped_functions:
141 if fun == name:
142 return 1
143 # Do not test destructors
144 if string.find(name, 'Free') != -1:
145 return 1
146 return 0
147
148def is_skipped_memcheck(name):
149 for fun in skipped_memcheck:
150 if fun == name:
151 return 1
152 return 0
153
154missing_types = {}
155def add_missing_type(name, func):
156 try:
157 list = missing_types[name]
158 list.append(func)
159 except:
160 missing_types[name] = [func]
161
Daniel Veillardce682bc2004-11-05 17:22:25 +0000162generated_param_types = []
163def add_generated_param_type(name):
164 generated_param_types.append(name)
165
166generated_return_types = []
167def add_generated_return_type(name):
168 generated_return_types.append(name)
169
Daniel Veillard34099b42004-11-04 17:34:35 +0000170missing_functions = {}
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000171missing_functions_nr = 0
Daniel Veillard34099b42004-11-04 17:34:35 +0000172def add_missing_functions(name, module):
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000173 global missing_functions_nr
174
175 missing_functions_nr = missing_functions_nr + 1
Daniel Veillard34099b42004-11-04 17:34:35 +0000176 try:
177 list = missing_functions[module]
178 list.append(name)
179 except:
180 missing_functions[module] = [name]
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000181
182#
183# Provide the type generators and destructors for the parameters
184#
185
Daniel Veillarda03e3652004-11-02 18:45:30 +0000186def type_convert(str, name, info, module, function, pos):
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000187# res = string.replace(str, " ", " ")
188# res = string.replace(str, " ", " ")
189# res = string.replace(str, " ", " ")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000190 res = string.replace(str, " *", "_ptr")
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000191# res = string.replace(str, "*", "_ptr")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000192 res = string.replace(res, " ", "_")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000193 res = string.replace(res, "htmlNode", "xmlNode")
194 res = string.replace(res, "htmlDoc", "xmlDoc")
195 res = string.replace(res, "htmlParser", "xmlParser")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000196 if res == 'const_char_ptr':
197 if string.find(name, "file") != -1 or \
198 string.find(name, "uri") != -1 or \
199 string.find(name, "URI") != -1 or \
200 string.find(info, "filename") != -1 or \
201 string.find(info, "URI") != -1 or \
202 string.find(info, "URL") != -1:
William M. Brack83d9c372004-11-08 02:26:08 +0000203 if string.find(function, "Save") != -1 or \
204 string.find(function, "Create") != -1 or \
205 string.find(function, "Write") != -1:
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000206 return('fileoutput')
207 return('filepath')
208 if res == 'void_ptr':
209 if module == 'nanoftp' and name == 'ctx':
210 return('xmlNanoFTPCtxtPtr')
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000211 if function == 'xmlNanoFTPNewCtxt':
212 return('xmlNanoFTPCtxtPtr')
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000213 if module == 'nanohttp' and name == 'ctx':
214 return('xmlNanoHTTPCtxtPtr')
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000215 if function == 'xmlIOHTTPOpenW':
216 return('xmlNanoHTTPCtxtPtr')
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000217 if string.find(name, "data") != -1:
218 return('userdata');
Daniel Veillardd005b9e2004-11-03 17:07:05 +0000219 if string.find(name, "user") != -1:
220 return('userdata');
Daniel Veillard3d97e662004-11-04 10:49:00 +0000221 if res == 'xmlDoc_ptr':
222 res = 'xmlDocPtr';
223 if res == 'xmlNode_ptr':
224 res = 'xmlNodePtr';
225 if res == 'xmlDict_ptr':
226 res = 'xmlDictPtr';
Daniel Veillarda03e3652004-11-02 18:45:30 +0000227 if res == 'xmlNodePtr' and pos != 0:
228 if (function == 'xmlAddChild' and pos == 2) or \
229 (function == 'xmlAddChildList' and pos == 2) or \
230 (function == 'xmlAddNextSibling' and pos == 2) or \
231 (function == 'xmlAddSibling' and pos == 2) or \
232 (function == 'xmlDocSetRootElement' and pos == 2) or \
233 (function == 'xmlReplaceNode' and pos == 2) or \
234 (function == 'xmlTextMerge') or \
235 (function == 'xmlAddPrevSibling' and pos == 2):
236 return('xmlNodePtr_in');
Daniel Veillard34099b42004-11-04 17:34:35 +0000237 if res == 'const xmlBufferPtr':
238 res = 'xmlBufferPtr';
Daniel Veillard27f20102004-11-05 11:50:11 +0000239 if res == 'xmlChar_ptr' and name == 'name' and \
240 string.find(function, "EatName") != -1:
241 return('eaten_name')
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000242 if res == 'void_ptr*':
243 res = 'void_ptr_ptr'
244 if res == 'char_ptr*':
245 res = 'char_ptr_ptr'
246 if res == 'xmlChar_ptr*':
247 res = 'xmlChar_ptr_ptr'
248 if res == 'const_xmlChar_ptr*':
249 res = 'const_xmlChar_ptr_ptr'
250 if res == 'const_char_ptr*':
251 res = 'const_char_ptr_ptr'
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000252
253 return res
254
Daniel Veillard34099b42004-11-04 17:34:35 +0000255known_param_types = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000256
Daniel Veillardce682bc2004-11-05 17:22:25 +0000257def is_known_param_type(name, rtype):
258 global test
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000259 for type in known_param_types:
260 if type == name:
261 return 1
Daniel Veillardce682bc2004-11-05 17:22:25 +0000262 for type in generated_param_types:
263 if type == name:
264 return 1
265
266 if name[-3:] == 'Ptr' or name[-4:] == '_ptr':
267 if rtype[0:6] == 'const ':
268 crtype = rtype[6:]
269 else:
270 crtype = rtype
271
272 test.write("""
273#define gen_nb_%s 1
274static %s gen_%s(int no ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
275 return(NULL);
276}
277static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
278}
279""" % (name, crtype, name, name, rtype))
280 add_generated_param_type(name)
281 return 1
282
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000283 return 0
284
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000285#
286# Provide the type destructors for the return values
287#
288
Daniel Veillard34099b42004-11-04 17:34:35 +0000289known_return_types = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000290
291def is_known_return_type(name):
292 for type in known_return_types:
293 if type == name:
294 return 1
295 return 0
296
Daniel Veillard34099b42004-11-04 17:34:35 +0000297#
298# Copy the beginning of the C test program result
299#
300
301input = open("testapi.c", "r")
302test = open('testapi.c.new', 'w')
303
304def compare_and_save():
305 global test
306
307 test.close()
308 input = open("testapi.c", "r").read()
309 test = open('testapi.c.new', "r").read()
310 if input != test:
311 os.system("rm testapi.c ; mv testapi.c.new testapi.c")
312 print("Updated testapi.c")
313 else:
314 print("Generated testapi.c is identical")
315
316line = input.readline()
317while line != "":
318 if line == "/* CUT HERE: everything below that line is generated */\n":
319 break;
320 if line[0:15] == "#define gen_nb_":
321 type = string.split(line[15:])[0]
322 known_param_types.append(type)
323 if line[0:19] == "static void desret_":
324 type = string.split(line[19:], '(')[0]
325 known_return_types.append(type)
326 test.write(line)
327 line = input.readline()
328input.close()
329
330if line == "":
331 print "Could not find the CUT marker in testapi.c skipping generation"
332 test.close()
333 sys.exit(0)
334
335print("Scanned testapi.c: found %d parameters types and %d return types\n" % (
336 len(known_param_types), len(known_return_types)))
337test.write("/* CUT HERE: everything below that line is generated */\n")
338
339
340#
341# Open the input API description
342#
343doc = libxml2.readFile('doc/libxml2-api.xml', None, 0)
344if doc == None:
345 print "Failed to load doc/libxml2-api.xml"
346 sys.exit(1)
347ctxt = doc.xpathNewContext()
Daniel Veillard57b25162004-11-06 14:50:18 +0000348
349#
350# Generate constructors and return type handling for all enums
351#
352enums = ctxt.xpathEval("/api/symbols/typedef[@type='enum']")
353for enum in enums:
354 name = enum.xpathEval('string(@name)')
355 if name == None:
356 continue;
357
358 if is_known_param_type(name, name) == 0:
359 values = ctxt.xpathEval("/api/symbols/enum[@type='%s']" % name)
360 i = 0
361 vals = []
362 for value in values:
363 vname = value.xpathEval('string(@name)')
364 if vname == None:
365 continue;
366 i = i + 1
367 if i >= 5:
368 break;
369 vals.append(vname)
370 if vals == []:
371 print "Didn't found any value for enum %s" % (name)
372 continue
373 test.write("#define gen_nb_%s %d\n" % (name, len(vals)))
374 test.write("""static %s gen_%s(int no, int nr ATTRIBUTE_UNUSED) {\n""" %
375 (name, name))
376 i = 1
377 for value in vals:
378 test.write(" if (no == %d) return(%s);\n" % (i, value))
379 i = i + 1
380 test.write(""" return(0);
381}
382""");
383 known_param_types.append(name)
384
385 if is_known_return_type(name) == 0:
386 test.write("""static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
387}
388static void desret_%s(%s val ATTRIBUTE_UNUSED) {
389}
390
391""" % (name, name, name, name))
392 known_return_types.append(name)
Daniel Veillard34099b42004-11-04 17:34:35 +0000393
394#
395# Load the interfaces
396#
Daniel Veillard57b25162004-11-06 14:50:18 +0000397headers = ctxt.xpathEval("/api/files/file")
Daniel Veillard34099b42004-11-04 17:34:35 +0000398for file in headers:
399 name = file.xpathEval('string(@name)')
400 if (name == None) or (name == ''):
401 continue
402
403 #
404 # Some module may be skipped because they don't really consists
405 # of user callable APIs
406 #
407 if is_skipped_module(name):
408 continue
409
410 #
411 # do not test deprecated APIs
412 #
413 desc = file.xpathEval('string(description)')
414 if string.find(desc, 'DEPRECATED') != -1:
415 print "Skipping deprecated interface %s" % name
416 continue;
417
418 test.write("#include <libxml/%s.h>\n" % name)
419 modules.append(name)
420
421#
422# Generate the callers signatures
423#
424for module in modules:
425 test.write("static int test_%s(void);\n" % module);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000426
427#
428# Generate the top caller
429#
430
431test.write("""
432/**
433 * testlibxml2:
434 *
435 * Main entry point of the tester for the full libxml2 module,
436 * it calls all the tester entry point for each module.
437 *
438 * Returns the number of error found
439 */
440static int
441testlibxml2(void)
442{
443 int ret = 0;
444
445""")
446
447for module in modules:
448 test.write(" ret += test_%s();\n" % module)
449
450test.write("""
Daniel Veillard3d97e662004-11-04 10:49:00 +0000451 printf("Total: %d functions, %d tests, %d errors\\n",
452 function_tests, call_tests, ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000453 return(ret);
454}
455
456""")
457
458#
459# How to handle a function
460#
461nb_tests = 0
462
463def generate_test(module, node):
464 global test
465 global nb_tests
466 nb_cond = 0
467 no_gen = 0
468
469 name = node.xpathEval('string(@name)')
470 if is_skipped_function(name):
471 return
472
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000473 #
474 # check we know how to handle the args and return values
475 # and store the informations for the generation
476 #
477 try:
478 args = node.xpathEval("arg")
479 except:
480 args = []
481 t_args = []
Daniel Veillarda03e3652004-11-02 18:45:30 +0000482 n = 0
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000483 for arg in args:
Daniel Veillarda03e3652004-11-02 18:45:30 +0000484 n = n + 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000485 rtype = arg.xpathEval("string(@type)")
486 if rtype == 'void':
487 break;
488 info = arg.xpathEval("string(@info)")
489 nam = arg.xpathEval("string(@name)")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000490 type = type_convert(rtype, nam, info, module, name, n)
Daniel Veillardce682bc2004-11-05 17:22:25 +0000491 if is_known_param_type(type, rtype) == 0:
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000492 add_missing_type(type, name);
493 no_gen = 1
494 t_args.append((nam, type, rtype, info))
495
496 try:
497 rets = node.xpathEval("return")
498 except:
499 rets = []
500 t_ret = None
501 for ret in rets:
502 rtype = ret.xpathEval("string(@type)")
503 info = ret.xpathEval("string(@info)")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000504 type = type_convert(rtype, 'return', info, module, name, 0)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000505 if rtype == 'void':
506 break
507 if is_known_return_type(type) == 0:
508 add_missing_type(type, name);
509 no_gen = 1
510 t_ret = (type, rtype, info)
511 break
512
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000513 test.write("""
514static int
515test_%s(void) {
516 int ret = 0;
517
518""" % (name))
519
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000520 if no_gen == 1:
Daniel Veillard34099b42004-11-04 17:34:35 +0000521 add_missing_functions(name, module)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000522 test.write("""
523 /* missing type support */
524 return(ret);
525}
526
527""")
528 return
529
530 try:
531 conds = node.xpathEval("cond")
532 for cond in conds:
533 test.write("#ifdef %s\n" % (cond.get_content()))
534 nb_cond = nb_cond + 1
535 except:
536 pass
537
538 # Declare the memory usage counter
539 no_mem = is_skipped_memcheck(name)
540 if no_mem == 0:
541 test.write(" int mem_base;\n");
542
543 # Declare the return value
544 if t_ret != None:
545 test.write(" %s ret_val;\n" % (t_ret[1]))
546
547 # Declare the arguments
548 for arg in t_args:
549 (nam, type, rtype, info) = arg;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000550 if (type[-3:] == 'Ptr' or type[-4:] == '_ptr') and \
551 rtype[0:6] == 'const ':
552 crtype = rtype[6:]
553 else:
554 crtype = rtype
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000555 # add declaration
Daniel Veillardce682bc2004-11-05 17:22:25 +0000556 test.write(" %s %s; /* %s */\n" % (crtype, nam, info))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000557 test.write(" int n_%s;\n" % (nam))
558 test.write("\n")
559
560 # Cascade loop on of each argument list of values
561 for arg in t_args:
562 (nam, type, rtype, info) = arg;
563 #
564 test.write(" for (n_%s = 0;n_%s < gen_nb_%s;n_%s++) {\n" % (
565 nam, nam, type, nam))
566
567 # log the memory usage
568 if no_mem == 0:
569 test.write(" mem_base = xmlMemBlocks();\n");
570
571 # prepare the call
Daniel Veillard3d97e662004-11-04 10:49:00 +0000572 i = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000573 for arg in t_args:
574 (nam, type, rtype, info) = arg;
575 #
Daniel Veillard3d97e662004-11-04 10:49:00 +0000576 test.write(" %s = gen_%s(n_%s, %d);\n" % (nam, type, nam, i))
577 i = i + 1;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000578
579 # do the call, and clanup the result
Daniel Veillard34099b42004-11-04 17:34:35 +0000580 if extra_pre_call.has_key(name):
581 test.write(" %s\n"% (extra_pre_call[name]))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000582 if t_ret != None:
583 test.write("\n ret_val = %s(" % (name))
584 need = 0
585 for arg in t_args:
586 (nam, type, rtype, info) = arg
587 if need:
588 test.write(", ")
589 else:
590 need = 1
591 test.write("%s" % nam);
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000592 test.write(");\n")
593 if extra_post_call.has_key(name):
594 test.write(" %s\n"% (extra_post_call[name]))
595 test.write(" desret_%s(ret_val);\n" % t_ret[0])
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000596 else:
597 test.write("\n %s(" % (name));
598 need = 0;
599 for arg in t_args:
600 (nam, type, rtype, info) = arg;
601 if need:
602 test.write(", ")
603 else:
604 need = 1
605 test.write("%s" % nam)
606 test.write(");\n")
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000607 if extra_post_call.has_key(name):
608 test.write(" %s\n"% (extra_post_call[name]))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000609
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000610 test.write(" call_tests++;\n");
Daniel Veillarda03e3652004-11-02 18:45:30 +0000611
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000612 # Free the arguments
Daniel Veillard3d97e662004-11-04 10:49:00 +0000613 i = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000614 for arg in t_args:
615 (nam, type, rtype, info) = arg;
616 #
Daniel Veillard3d97e662004-11-04 10:49:00 +0000617 test.write(" des_%s(n_%s, %s, %d);\n" % (type, nam, nam, i))
618 i = i + 1;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000619
620 test.write(" xmlResetLastError();\n");
621 # Check the memory usage
622 if no_mem == 0:
623 test.write(""" if (mem_base != xmlMemBlocks()) {
Daniel Veillarda03e3652004-11-02 18:45:30 +0000624 printf("Leak of %%d blocks found in %s",
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000625 xmlMemBlocks() - mem_base);
626 ret++;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000627""" % (name));
Daniel Veillarda03e3652004-11-02 18:45:30 +0000628 for arg in t_args:
629 (nam, type, rtype, info) = arg;
630 test.write(""" printf(" %%d", n_%s);\n""" % (nam))
631 test.write(""" printf("\\n");\n""")
632 test.write(" }\n")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000633
634 for arg in t_args:
635 test.write(" }\n")
636
637 #
638 # end of conditional
639 #
640 while nb_cond > 0:
641 test.write("#endif\n")
642 nb_cond = nb_cond -1
643
644 nb_tests = nb_tests + 1;
645
646 test.write("""
Daniel Veillard3d97e662004-11-04 10:49:00 +0000647 function_tests++;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000648 return(ret);
649}
650
651""")
652
653#
654# Generate all module callers
655#
656for module in modules:
657 # gather all the functions exported by that module
658 try:
659 functions = ctxt.xpathEval("/api/symbols/function[@file='%s']" % (module))
660 except:
661 print "Failed to gather functions from module %s" % (module)
662 continue;
663
664 # iterate over all functions in the module generating the test
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000665 i = 0
666 nb_tests_old = nb_tests
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000667 for function in functions:
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000668 i = i + 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000669 generate_test(module, function);
670
671 # header
672 test.write("""static int
673test_%s(void) {
674 int ret = 0;
675
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000676 printf("Testing %s : %d of %d functions ...\\n");
677""" % (module, module, nb_tests - nb_tests_old, i))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000678
679 # iterate over all functions in the module generating the call
680 for function in functions:
681 name = function.xpathEval('string(@name)')
682 if is_skipped_function(name):
683 continue
684 test.write(" ret += test_%s();\n" % (name))
685
686 # footer
687 test.write("""
688 if (ret != 0)
689 printf("Module %s: %%d errors\\n", ret);
690 return(ret);
691}
692""" % (module))
693
Daniel Veillardce244ad2004-11-05 10:03:46 +0000694#
695# Generate direct module caller
696#
697test.write("""static int
698test_module(const char *module) {
699""");
700for module in modules:
701 test.write(""" if (!strcmp(module, "%s")) return(test_%s());\n""" % (
702 module, module))
703test.write(""" return(0);
704}
705""");
706
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000707print "Generated test for %d modules and %d functions" %(len(modules), nb_tests)
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000708
Daniel Veillard34099b42004-11-04 17:34:35 +0000709compare_and_save()
710
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000711missing_list = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000712for missing in missing_types.keys():
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000713 if missing == 'va_list' or missing == '...':
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000714 continue;
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000715
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000716 n = len(missing_types[missing])
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000717 missing_list.append((n, missing))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000718
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000719def compare_missing(a, b):
720 return b[0] - a[0]
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000721
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000722missing_list.sort(compare_missing)
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000723print "Missing support for %d functions and %d types see missing.lst" % (missing_functions_nr, len(missing_list))
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000724lst = open("missing.lst", "w")
Daniel Veillard34099b42004-11-04 17:34:35 +0000725lst.write("Missing support for %d types" % (len(missing_list)))
726lst.write("\n")
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000727for miss in missing_list:
728 lst.write("%s: %d :" % (miss[1], miss[0]))
729 i = 0
730 for n in missing_types[miss[1]]:
731 i = i + 1
732 if i > 5:
733 lst.write(" ...")
734 break
735 lst.write(" %s" % (n))
736 lst.write("\n")
Daniel Veillard34099b42004-11-04 17:34:35 +0000737lst.write("\n")
738lst.write("\n")
739lst.write("Missing support per module");
740for module in missing_functions.keys():
741 lst.write("module %s:\n %s\n" % (module, missing_functions[module]))
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000742
743lst.close()
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000744
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000745