blob: b8603c24963b1db1efff0c520c6c3c6977f1b6c5 [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:
203 if string.find(function, "Save") != -1:
204 return('fileoutput')
205 return('filepath')
206 if res == 'void_ptr':
207 if module == 'nanoftp' and name == 'ctx':
208 return('xmlNanoFTPCtxtPtr')
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000209 if function == 'xmlNanoFTPNewCtxt':
210 return('xmlNanoFTPCtxtPtr')
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000211 if module == 'nanohttp' and name == 'ctx':
212 return('xmlNanoHTTPCtxtPtr')
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000213 if function == 'xmlIOHTTPOpenW':
214 return('xmlNanoHTTPCtxtPtr')
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000215 if string.find(name, "data") != -1:
216 return('userdata');
Daniel Veillardd005b9e2004-11-03 17:07:05 +0000217 if string.find(name, "user") != -1:
218 return('userdata');
Daniel Veillard3d97e662004-11-04 10:49:00 +0000219 if res == 'xmlDoc_ptr':
220 res = 'xmlDocPtr';
221 if res == 'xmlNode_ptr':
222 res = 'xmlNodePtr';
223 if res == 'xmlDict_ptr':
224 res = 'xmlDictPtr';
Daniel Veillarda03e3652004-11-02 18:45:30 +0000225 if res == 'xmlNodePtr' and pos != 0:
226 if (function == 'xmlAddChild' and pos == 2) or \
227 (function == 'xmlAddChildList' and pos == 2) or \
228 (function == 'xmlAddNextSibling' and pos == 2) or \
229 (function == 'xmlAddSibling' and pos == 2) or \
230 (function == 'xmlDocSetRootElement' and pos == 2) or \
231 (function == 'xmlReplaceNode' and pos == 2) or \
232 (function == 'xmlTextMerge') or \
233 (function == 'xmlAddPrevSibling' and pos == 2):
234 return('xmlNodePtr_in');
Daniel Veillard34099b42004-11-04 17:34:35 +0000235 if res == 'const xmlBufferPtr':
236 res = 'xmlBufferPtr';
Daniel Veillard27f20102004-11-05 11:50:11 +0000237 if res == 'xmlChar_ptr' and name == 'name' and \
238 string.find(function, "EatName") != -1:
239 return('eaten_name')
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000240 if res == 'void_ptr*':
241 res = 'void_ptr_ptr'
242 if res == 'char_ptr*':
243 res = 'char_ptr_ptr'
244 if res == 'xmlChar_ptr*':
245 res = 'xmlChar_ptr_ptr'
246 if res == 'const_xmlChar_ptr*':
247 res = 'const_xmlChar_ptr_ptr'
248 if res == 'const_char_ptr*':
249 res = 'const_char_ptr_ptr'
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000250
251 return res
252
Daniel Veillard34099b42004-11-04 17:34:35 +0000253known_param_types = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000254
Daniel Veillardce682bc2004-11-05 17:22:25 +0000255def is_known_param_type(name, rtype):
256 global test
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000257 for type in known_param_types:
258 if type == name:
259 return 1
Daniel Veillardce682bc2004-11-05 17:22:25 +0000260 for type in generated_param_types:
261 if type == name:
262 return 1
263
264 if name[-3:] == 'Ptr' or name[-4:] == '_ptr':
265 if rtype[0:6] == 'const ':
266 crtype = rtype[6:]
267 else:
268 crtype = rtype
269
270 test.write("""
271#define gen_nb_%s 1
272static %s gen_%s(int no ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
273 return(NULL);
274}
275static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
276}
277""" % (name, crtype, name, name, rtype))
278 add_generated_param_type(name)
279 return 1
280
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000281 return 0
282
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000283#
284# Provide the type destructors for the return values
285#
286
Daniel Veillard34099b42004-11-04 17:34:35 +0000287known_return_types = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000288
289def is_known_return_type(name):
290 for type in known_return_types:
291 if type == name:
292 return 1
293 return 0
294
Daniel Veillard34099b42004-11-04 17:34:35 +0000295#
296# Copy the beginning of the C test program result
297#
298
299input = open("testapi.c", "r")
300test = open('testapi.c.new', 'w')
301
302def compare_and_save():
303 global test
304
305 test.close()
306 input = open("testapi.c", "r").read()
307 test = open('testapi.c.new', "r").read()
308 if input != test:
309 os.system("rm testapi.c ; mv testapi.c.new testapi.c")
310 print("Updated testapi.c")
311 else:
312 print("Generated testapi.c is identical")
313
314line = input.readline()
315while line != "":
316 if line == "/* CUT HERE: everything below that line is generated */\n":
317 break;
318 if line[0:15] == "#define gen_nb_":
319 type = string.split(line[15:])[0]
320 known_param_types.append(type)
321 if line[0:19] == "static void desret_":
322 type = string.split(line[19:], '(')[0]
323 known_return_types.append(type)
324 test.write(line)
325 line = input.readline()
326input.close()
327
328if line == "":
329 print "Could not find the CUT marker in testapi.c skipping generation"
330 test.close()
331 sys.exit(0)
332
333print("Scanned testapi.c: found %d parameters types and %d return types\n" % (
334 len(known_param_types), len(known_return_types)))
335test.write("/* CUT HERE: everything below that line is generated */\n")
336
337
338#
339# Open the input API description
340#
341doc = libxml2.readFile('doc/libxml2-api.xml', None, 0)
342if doc == None:
343 print "Failed to load doc/libxml2-api.xml"
344 sys.exit(1)
345ctxt = doc.xpathNewContext()
Daniel Veillard57b25162004-11-06 14:50:18 +0000346
347#
348# Generate constructors and return type handling for all enums
349#
350enums = ctxt.xpathEval("/api/symbols/typedef[@type='enum']")
351for enum in enums:
352 name = enum.xpathEval('string(@name)')
353 if name == None:
354 continue;
355
356 if is_known_param_type(name, name) == 0:
357 values = ctxt.xpathEval("/api/symbols/enum[@type='%s']" % name)
358 i = 0
359 vals = []
360 for value in values:
361 vname = value.xpathEval('string(@name)')
362 if vname == None:
363 continue;
364 i = i + 1
365 if i >= 5:
366 break;
367 vals.append(vname)
368 if vals == []:
369 print "Didn't found any value for enum %s" % (name)
370 continue
371 test.write("#define gen_nb_%s %d\n" % (name, len(vals)))
372 test.write("""static %s gen_%s(int no, int nr ATTRIBUTE_UNUSED) {\n""" %
373 (name, name))
374 i = 1
375 for value in vals:
376 test.write(" if (no == %d) return(%s);\n" % (i, value))
377 i = i + 1
378 test.write(""" return(0);
379}
380""");
381 known_param_types.append(name)
382
383 if is_known_return_type(name) == 0:
384 test.write("""static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
385}
386static void desret_%s(%s val ATTRIBUTE_UNUSED) {
387}
388
389""" % (name, name, name, name))
390 known_return_types.append(name)
Daniel Veillard34099b42004-11-04 17:34:35 +0000391
392#
393# Load the interfaces
394#
Daniel Veillard57b25162004-11-06 14:50:18 +0000395headers = ctxt.xpathEval("/api/files/file")
Daniel Veillard34099b42004-11-04 17:34:35 +0000396for file in headers:
397 name = file.xpathEval('string(@name)')
398 if (name == None) or (name == ''):
399 continue
400
401 #
402 # Some module may be skipped because they don't really consists
403 # of user callable APIs
404 #
405 if is_skipped_module(name):
406 continue
407
408 #
409 # do not test deprecated APIs
410 #
411 desc = file.xpathEval('string(description)')
412 if string.find(desc, 'DEPRECATED') != -1:
413 print "Skipping deprecated interface %s" % name
414 continue;
415
416 test.write("#include <libxml/%s.h>\n" % name)
417 modules.append(name)
418
419#
420# Generate the callers signatures
421#
422for module in modules:
423 test.write("static int test_%s(void);\n" % module);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000424
425#
426# Generate the top caller
427#
428
429test.write("""
430/**
431 * testlibxml2:
432 *
433 * Main entry point of the tester for the full libxml2 module,
434 * it calls all the tester entry point for each module.
435 *
436 * Returns the number of error found
437 */
438static int
439testlibxml2(void)
440{
441 int ret = 0;
442
443""")
444
445for module in modules:
446 test.write(" ret += test_%s();\n" % module)
447
448test.write("""
Daniel Veillard3d97e662004-11-04 10:49:00 +0000449 printf("Total: %d functions, %d tests, %d errors\\n",
450 function_tests, call_tests, ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000451 return(ret);
452}
453
454""")
455
456#
457# How to handle a function
458#
459nb_tests = 0
460
461def generate_test(module, node):
462 global test
463 global nb_tests
464 nb_cond = 0
465 no_gen = 0
466
467 name = node.xpathEval('string(@name)')
468 if is_skipped_function(name):
469 return
470
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000471 #
472 # check we know how to handle the args and return values
473 # and store the informations for the generation
474 #
475 try:
476 args = node.xpathEval("arg")
477 except:
478 args = []
479 t_args = []
Daniel Veillarda03e3652004-11-02 18:45:30 +0000480 n = 0
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000481 for arg in args:
Daniel Veillarda03e3652004-11-02 18:45:30 +0000482 n = n + 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000483 rtype = arg.xpathEval("string(@type)")
484 if rtype == 'void':
485 break;
486 info = arg.xpathEval("string(@info)")
487 nam = arg.xpathEval("string(@name)")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000488 type = type_convert(rtype, nam, info, module, name, n)
Daniel Veillardce682bc2004-11-05 17:22:25 +0000489 if is_known_param_type(type, rtype) == 0:
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000490 add_missing_type(type, name);
491 no_gen = 1
492 t_args.append((nam, type, rtype, info))
493
494 try:
495 rets = node.xpathEval("return")
496 except:
497 rets = []
498 t_ret = None
499 for ret in rets:
500 rtype = ret.xpathEval("string(@type)")
501 info = ret.xpathEval("string(@info)")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000502 type = type_convert(rtype, 'return', info, module, name, 0)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000503 if rtype == 'void':
504 break
505 if is_known_return_type(type) == 0:
506 add_missing_type(type, name);
507 no_gen = 1
508 t_ret = (type, rtype, info)
509 break
510
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000511 test.write("""
512static int
513test_%s(void) {
514 int ret = 0;
515
516""" % (name))
517
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000518 if no_gen == 1:
Daniel Veillard34099b42004-11-04 17:34:35 +0000519 add_missing_functions(name, module)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000520 test.write("""
521 /* missing type support */
522 return(ret);
523}
524
525""")
526 return
527
528 try:
529 conds = node.xpathEval("cond")
530 for cond in conds:
531 test.write("#ifdef %s\n" % (cond.get_content()))
532 nb_cond = nb_cond + 1
533 except:
534 pass
535
536 # Declare the memory usage counter
537 no_mem = is_skipped_memcheck(name)
538 if no_mem == 0:
539 test.write(" int mem_base;\n");
540
541 # Declare the return value
542 if t_ret != None:
543 test.write(" %s ret_val;\n" % (t_ret[1]))
544
545 # Declare the arguments
546 for arg in t_args:
547 (nam, type, rtype, info) = arg;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000548 if (type[-3:] == 'Ptr' or type[-4:] == '_ptr') and \
549 rtype[0:6] == 'const ':
550 crtype = rtype[6:]
551 else:
552 crtype = rtype
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000553 # add declaration
Daniel Veillardce682bc2004-11-05 17:22:25 +0000554 test.write(" %s %s; /* %s */\n" % (crtype, nam, info))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000555 test.write(" int n_%s;\n" % (nam))
556 test.write("\n")
557
558 # Cascade loop on of each argument list of values
559 for arg in t_args:
560 (nam, type, rtype, info) = arg;
561 #
562 test.write(" for (n_%s = 0;n_%s < gen_nb_%s;n_%s++) {\n" % (
563 nam, nam, type, nam))
564
565 # log the memory usage
566 if no_mem == 0:
567 test.write(" mem_base = xmlMemBlocks();\n");
568
569 # prepare the call
Daniel Veillard3d97e662004-11-04 10:49:00 +0000570 i = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000571 for arg in t_args:
572 (nam, type, rtype, info) = arg;
573 #
Daniel Veillard3d97e662004-11-04 10:49:00 +0000574 test.write(" %s = gen_%s(n_%s, %d);\n" % (nam, type, nam, i))
575 i = i + 1;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000576
577 # do the call, and clanup the result
Daniel Veillard34099b42004-11-04 17:34:35 +0000578 if extra_pre_call.has_key(name):
579 test.write(" %s\n"% (extra_pre_call[name]))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000580 if t_ret != None:
581 test.write("\n ret_val = %s(" % (name))
582 need = 0
583 for arg in t_args:
584 (nam, type, rtype, info) = arg
585 if need:
586 test.write(", ")
587 else:
588 need = 1
589 test.write("%s" % nam);
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000590 test.write(");\n")
591 if extra_post_call.has_key(name):
592 test.write(" %s\n"% (extra_post_call[name]))
593 test.write(" desret_%s(ret_val);\n" % t_ret[0])
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000594 else:
595 test.write("\n %s(" % (name));
596 need = 0;
597 for arg in t_args:
598 (nam, type, rtype, info) = arg;
599 if need:
600 test.write(", ")
601 else:
602 need = 1
603 test.write("%s" % nam)
604 test.write(");\n")
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000605 if extra_post_call.has_key(name):
606 test.write(" %s\n"% (extra_post_call[name]))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000607
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000608 test.write(" call_tests++;\n");
Daniel Veillarda03e3652004-11-02 18:45:30 +0000609
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000610 # Free the arguments
Daniel Veillard3d97e662004-11-04 10:49:00 +0000611 i = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000612 for arg in t_args:
613 (nam, type, rtype, info) = arg;
614 #
Daniel Veillard3d97e662004-11-04 10:49:00 +0000615 test.write(" des_%s(n_%s, %s, %d);\n" % (type, nam, nam, i))
616 i = i + 1;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000617
618 test.write(" xmlResetLastError();\n");
619 # Check the memory usage
620 if no_mem == 0:
621 test.write(""" if (mem_base != xmlMemBlocks()) {
Daniel Veillarda03e3652004-11-02 18:45:30 +0000622 printf("Leak of %%d blocks found in %s",
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000623 xmlMemBlocks() - mem_base);
624 ret++;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000625""" % (name));
Daniel Veillarda03e3652004-11-02 18:45:30 +0000626 for arg in t_args:
627 (nam, type, rtype, info) = arg;
628 test.write(""" printf(" %%d", n_%s);\n""" % (nam))
629 test.write(""" printf("\\n");\n""")
630 test.write(" }\n")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000631
632 for arg in t_args:
633 test.write(" }\n")
634
635 #
636 # end of conditional
637 #
638 while nb_cond > 0:
639 test.write("#endif\n")
640 nb_cond = nb_cond -1
641
642 nb_tests = nb_tests + 1;
643
644 test.write("""
Daniel Veillard3d97e662004-11-04 10:49:00 +0000645 function_tests++;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000646 return(ret);
647}
648
649""")
650
651#
652# Generate all module callers
653#
654for module in modules:
655 # gather all the functions exported by that module
656 try:
657 functions = ctxt.xpathEval("/api/symbols/function[@file='%s']" % (module))
658 except:
659 print "Failed to gather functions from module %s" % (module)
660 continue;
661
662 # iterate over all functions in the module generating the test
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000663 i = 0
664 nb_tests_old = nb_tests
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000665 for function in functions:
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000666 i = i + 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000667 generate_test(module, function);
668
669 # header
670 test.write("""static int
671test_%s(void) {
672 int ret = 0;
673
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000674 printf("Testing %s : %d of %d functions ...\\n");
675""" % (module, module, nb_tests - nb_tests_old, i))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000676
677 # iterate over all functions in the module generating the call
678 for function in functions:
679 name = function.xpathEval('string(@name)')
680 if is_skipped_function(name):
681 continue
682 test.write(" ret += test_%s();\n" % (name))
683
684 # footer
685 test.write("""
686 if (ret != 0)
687 printf("Module %s: %%d errors\\n", ret);
688 return(ret);
689}
690""" % (module))
691
Daniel Veillardce244ad2004-11-05 10:03:46 +0000692#
693# Generate direct module caller
694#
695test.write("""static int
696test_module(const char *module) {
697""");
698for module in modules:
699 test.write(""" if (!strcmp(module, "%s")) return(test_%s());\n""" % (
700 module, module))
701test.write(""" return(0);
702}
703""");
704
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000705print "Generated test for %d modules and %d functions" %(len(modules), nb_tests)
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000706
Daniel Veillard34099b42004-11-04 17:34:35 +0000707compare_and_save()
708
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000709missing_list = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000710for missing in missing_types.keys():
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000711 if missing == 'va_list' or missing == '...':
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000712 continue;
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000713
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000714 n = len(missing_types[missing])
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000715 missing_list.append((n, missing))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000716
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000717def compare_missing(a, b):
718 return b[0] - a[0]
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000719
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000720missing_list.sort(compare_missing)
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000721print "Missing support for %d functions and %d types see missing.lst" % (missing_functions_nr, len(missing_list))
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000722lst = open("missing.lst", "w")
Daniel Veillard34099b42004-11-04 17:34:35 +0000723lst.write("Missing support for %d types" % (len(missing_list)))
724lst.write("\n")
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000725for miss in missing_list:
726 lst.write("%s: %d :" % (miss[1], miss[0]))
727 i = 0
728 for n in missing_types[miss[1]]:
729 i = i + 1
730 if i > 5:
731 lst.write(" ...")
732 break
733 lst.write(" %s" % (n))
734 lst.write("\n")
Daniel Veillard34099b42004-11-04 17:34:35 +0000735lst.write("\n")
736lst.write("\n")
737lst.write("Missing support per module");
738for module in missing_functions.keys():
739 lst.write("module %s:\n %s\n" % (module, missing_functions[module]))
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000740
741lst.close()
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000742
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000743