blob: d57e56dcecf3aab5c5d18318a2fc22eb03faed57 [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 Veillarddd6d3002004-11-03 14:20:29 +000054]
Daniel Veillard36e5cd52004-11-02 14:52:23 +000055
56#
57# Those functions have side effect on the global state
58# and hence generate errors on memory allocation tests
59#
60skipped_memcheck = [ "xmlLoadCatalog", "xmlAddEncodingAlias",
61 "xmlSchemaInitTypes", "xmlNanoFTPProxy", "xmlNanoFTPScanProxy",
62 "xmlNanoHTTPScanProxy", "xmlResetLastError", "xmlCatalogConvert",
63 "xmlCatalogRemove", "xmlLoadCatalogs", "xmlCleanupCharEncodingHandlers",
Daniel Veillarda03e3652004-11-02 18:45:30 +000064 "xmlInitCharEncodingHandlers", "xmlCatalogCleanup",
65 "htmlParseFile" # loads the catalogs
66]
67
68#
69# Extra code needed for some test cases
70#
Daniel Veillard34099b42004-11-04 17:34:35 +000071extra_pre_call = {
72 "xmlSAXUserParseFile":
Daniel Veillardce244ad2004-11-05 10:03:46 +000073 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
Daniel Veillard34099b42004-11-04 17:34:35 +000074 "xmlSAXUserParseMemory":
Daniel Veillardce244ad2004-11-05 10:03:46 +000075 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
Daniel Veillardce682bc2004-11-05 17:22:25 +000076 "xmlParseBalancedChunkMemory":
77 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
78 "xmlParseBalancedChunkMemoryRecover":
79 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
Daniel Veillardd5cc0f72004-11-06 19:24:28 +000080 "xmlParserInputBufferCreateFd":
81 "if (fd >= 0) fd = -1;",
Daniel Veillard34099b42004-11-04 17:34:35 +000082}
Daniel Veillarda03e3652004-11-02 18:45:30 +000083extra_post_call = {
84 "xmlAddChild":
85 "if (ret_val == NULL) { xmlFreeNode(cur) ; cur = NULL ; }",
86 "xmlAddChildList":
87 "if (ret_val == NULL) { xmlFreeNodeList(cur) ; cur = NULL ; }",
88 "xmlAddSibling":
89 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
90 "xmlAddNextSibling":
91 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
92 "xmlAddPrevSibling":
93 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
94 "xmlDocSetRootElement":
95 "if (doc == NULL) { xmlFreeNode(root) ; root = NULL ; }",
96 "xmlReplaceNode":
Daniel Veillardce244ad2004-11-05 10:03:46 +000097 """if (cur != NULL) {
98 xmlUnlinkNode(cur);
99 xmlFreeNode(cur) ; cur = NULL ; }
100 if (old != NULL) {
101 xmlUnlinkNode(old);
102 xmlFreeNode(old) ; old = NULL ; }
103 ret_val = NULL;""",
Daniel Veillarda03e3652004-11-02 18:45:30 +0000104 "xmlTextMerge":
105 """if ((first != NULL) && (first->type != XML_TEXT_NODE)) {
Daniel Veillardce244ad2004-11-05 10:03:46 +0000106 xmlUnlinkNode(second);
Daniel Veillarda03e3652004-11-02 18:45:30 +0000107 xmlFreeNode(second) ; second = NULL ; }""",
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000108 "xmlBuildQName":
109 """if ((ret_val != NULL) && (ret_val != ncname) &&
110 (ret_val != prefix) && (ret_val != memory))
111 xmlFree(ret_val);
112 ret_val = NULL;""",
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000113 "xmlDictReference": "xmlDictFree(dict);",
Daniel Veillard3d97e662004-11-04 10:49:00 +0000114 # Functions which deallocates one of their parameters
115 "xmlXPathConvertBoolean": """val = NULL;""",
116 "xmlXPathConvertNumber": """val = NULL;""",
117 "xmlXPathConvertString": """val = NULL;""",
118 "xmlSaveFileTo": """buf = NULL;""",
Daniel Veillard34099b42004-11-04 17:34:35 +0000119 "xmlSaveFormatFileTo": """buf = NULL;""",
120 "xmlIOParseDTD": "input = NULL;",
Daniel Veillardce244ad2004-11-05 10:03:46 +0000121 "xmlRemoveProp": "cur = NULL;",
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000122 "xmlNewNs": "if ((node == NULL) && (ret_val != NULL)) xmlFreeNs(ret_val);",
123 "xmlCopyNamespace": "if (ret_val != NULL) xmlFreeNs(ret_val);",
124 "xmlCopyNamespaceList": "if (ret_val != NULL) xmlFreeNsList(ret_val);",
125 "xmlNewTextWriter": "if (ret_val != NULL) out = NULL;",
126 "xmlNewTextWriterPushParser": "if (ret_val != NULL) ctxt = NULL;",
Daniel Veillarda03e3652004-11-02 18:45:30 +0000127}
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000128
129modules = []
130
131def is_skipped_module(name):
132 for mod in skipped_modules:
133 if mod == name:
134 return 1
135 return 0
136
137def is_skipped_function(name):
138 for fun in skipped_functions:
139 if fun == name:
140 return 1
141 # Do not test destructors
142 if string.find(name, 'Free') != -1:
143 return 1
144 return 0
145
146def is_skipped_memcheck(name):
147 for fun in skipped_memcheck:
148 if fun == name:
149 return 1
150 return 0
151
152missing_types = {}
153def add_missing_type(name, func):
154 try:
155 list = missing_types[name]
156 list.append(func)
157 except:
158 missing_types[name] = [func]
159
Daniel Veillardce682bc2004-11-05 17:22:25 +0000160generated_param_types = []
161def add_generated_param_type(name):
162 generated_param_types.append(name)
163
164generated_return_types = []
165def add_generated_return_type(name):
166 generated_return_types.append(name)
167
Daniel Veillard34099b42004-11-04 17:34:35 +0000168missing_functions = {}
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000169missing_functions_nr = 0
Daniel Veillard34099b42004-11-04 17:34:35 +0000170def add_missing_functions(name, module):
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000171 global missing_functions_nr
172
173 missing_functions_nr = missing_functions_nr + 1
Daniel Veillard34099b42004-11-04 17:34:35 +0000174 try:
175 list = missing_functions[module]
176 list.append(name)
177 except:
178 missing_functions[module] = [name]
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000179
180#
181# Provide the type generators and destructors for the parameters
182#
183
Daniel Veillarda03e3652004-11-02 18:45:30 +0000184def type_convert(str, name, info, module, function, pos):
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000185# res = string.replace(str, " ", " ")
186# res = string.replace(str, " ", " ")
187# res = string.replace(str, " ", " ")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000188 res = string.replace(str, " *", "_ptr")
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000189# res = string.replace(str, "*", "_ptr")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000190 res = string.replace(res, " ", "_")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000191 res = string.replace(res, "htmlNode", "xmlNode")
192 res = string.replace(res, "htmlDoc", "xmlDoc")
193 res = string.replace(res, "htmlParser", "xmlParser")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000194 if res == 'const_char_ptr':
195 if string.find(name, "file") != -1 or \
196 string.find(name, "uri") != -1 or \
197 string.find(name, "URI") != -1 or \
198 string.find(info, "filename") != -1 or \
199 string.find(info, "URI") != -1 or \
200 string.find(info, "URL") != -1:
201 if string.find(function, "Save") != -1:
202 return('fileoutput')
203 return('filepath')
204 if res == 'void_ptr':
205 if module == 'nanoftp' and name == 'ctx':
206 return('xmlNanoFTPCtxtPtr')
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000207 if function == 'xmlNanoFTPNewCtxt':
208 return('xmlNanoFTPCtxtPtr')
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000209 if module == 'nanohttp' and name == 'ctx':
210 return('xmlNanoHTTPCtxtPtr')
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000211 if function == 'xmlIOHTTPOpenW':
212 return('xmlNanoHTTPCtxtPtr')
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000213 if string.find(name, "data") != -1:
214 return('userdata');
Daniel Veillardd005b9e2004-11-03 17:07:05 +0000215 if string.find(name, "user") != -1:
216 return('userdata');
Daniel Veillard3d97e662004-11-04 10:49:00 +0000217 if res == 'xmlDoc_ptr':
218 res = 'xmlDocPtr';
219 if res == 'xmlNode_ptr':
220 res = 'xmlNodePtr';
221 if res == 'xmlDict_ptr':
222 res = 'xmlDictPtr';
Daniel Veillarda03e3652004-11-02 18:45:30 +0000223 if res == 'xmlNodePtr' and pos != 0:
224 if (function == 'xmlAddChild' and pos == 2) or \
225 (function == 'xmlAddChildList' and pos == 2) or \
226 (function == 'xmlAddNextSibling' and pos == 2) or \
227 (function == 'xmlAddSibling' and pos == 2) or \
228 (function == 'xmlDocSetRootElement' and pos == 2) or \
229 (function == 'xmlReplaceNode' and pos == 2) or \
230 (function == 'xmlTextMerge') or \
231 (function == 'xmlAddPrevSibling' and pos == 2):
232 return('xmlNodePtr_in');
Daniel Veillard34099b42004-11-04 17:34:35 +0000233 if res == 'const xmlBufferPtr':
234 res = 'xmlBufferPtr';
Daniel Veillard27f20102004-11-05 11:50:11 +0000235 if res == 'xmlChar_ptr' and name == 'name' and \
236 string.find(function, "EatName") != -1:
237 return('eaten_name')
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000238 if res == 'void_ptr*':
239 res = 'void_ptr_ptr'
240 if res == 'char_ptr*':
241 res = 'char_ptr_ptr'
242 if res == 'xmlChar_ptr*':
243 res = 'xmlChar_ptr_ptr'
244 if res == 'const_xmlChar_ptr*':
245 res = 'const_xmlChar_ptr_ptr'
246 if res == 'const_char_ptr*':
247 res = 'const_char_ptr_ptr'
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000248
249 return res
250
Daniel Veillard34099b42004-11-04 17:34:35 +0000251known_param_types = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000252
Daniel Veillardce682bc2004-11-05 17:22:25 +0000253def is_known_param_type(name, rtype):
254 global test
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000255 for type in known_param_types:
256 if type == name:
257 return 1
Daniel Veillardce682bc2004-11-05 17:22:25 +0000258 for type in generated_param_types:
259 if type == name:
260 return 1
261
262 if name[-3:] == 'Ptr' or name[-4:] == '_ptr':
263 if rtype[0:6] == 'const ':
264 crtype = rtype[6:]
265 else:
266 crtype = rtype
267
268 test.write("""
269#define gen_nb_%s 1
270static %s gen_%s(int no ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
271 return(NULL);
272}
273static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
274}
275""" % (name, crtype, name, name, rtype))
276 add_generated_param_type(name)
277 return 1
278
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000279 return 0
280
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000281#
282# Provide the type destructors for the return values
283#
284
Daniel Veillard34099b42004-11-04 17:34:35 +0000285known_return_types = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000286
287def is_known_return_type(name):
288 for type in known_return_types:
289 if type == name:
290 return 1
291 return 0
292
Daniel Veillard34099b42004-11-04 17:34:35 +0000293#
294# Copy the beginning of the C test program result
295#
296
297input = open("testapi.c", "r")
298test = open('testapi.c.new', 'w')
299
300def compare_and_save():
301 global test
302
303 test.close()
304 input = open("testapi.c", "r").read()
305 test = open('testapi.c.new', "r").read()
306 if input != test:
307 os.system("rm testapi.c ; mv testapi.c.new testapi.c")
308 print("Updated testapi.c")
309 else:
310 print("Generated testapi.c is identical")
311
312line = input.readline()
313while line != "":
314 if line == "/* CUT HERE: everything below that line is generated */\n":
315 break;
316 if line[0:15] == "#define gen_nb_":
317 type = string.split(line[15:])[0]
318 known_param_types.append(type)
319 if line[0:19] == "static void desret_":
320 type = string.split(line[19:], '(')[0]
321 known_return_types.append(type)
322 test.write(line)
323 line = input.readline()
324input.close()
325
326if line == "":
327 print "Could not find the CUT marker in testapi.c skipping generation"
328 test.close()
329 sys.exit(0)
330
331print("Scanned testapi.c: found %d parameters types and %d return types\n" % (
332 len(known_param_types), len(known_return_types)))
333test.write("/* CUT HERE: everything below that line is generated */\n")
334
335
336#
337# Open the input API description
338#
339doc = libxml2.readFile('doc/libxml2-api.xml', None, 0)
340if doc == None:
341 print "Failed to load doc/libxml2-api.xml"
342 sys.exit(1)
343ctxt = doc.xpathNewContext()
Daniel Veillard57b25162004-11-06 14:50:18 +0000344
345#
346# Generate constructors and return type handling for all enums
347#
348enums = ctxt.xpathEval("/api/symbols/typedef[@type='enum']")
349for enum in enums:
350 name = enum.xpathEval('string(@name)')
351 if name == None:
352 continue;
353
354 if is_known_param_type(name, name) == 0:
355 values = ctxt.xpathEval("/api/symbols/enum[@type='%s']" % name)
356 i = 0
357 vals = []
358 for value in values:
359 vname = value.xpathEval('string(@name)')
360 if vname == None:
361 continue;
362 i = i + 1
363 if i >= 5:
364 break;
365 vals.append(vname)
366 if vals == []:
367 print "Didn't found any value for enum %s" % (name)
368 continue
369 test.write("#define gen_nb_%s %d\n" % (name, len(vals)))
370 test.write("""static %s gen_%s(int no, int nr ATTRIBUTE_UNUSED) {\n""" %
371 (name, name))
372 i = 1
373 for value in vals:
374 test.write(" if (no == %d) return(%s);\n" % (i, value))
375 i = i + 1
376 test.write(""" return(0);
377}
378""");
379 known_param_types.append(name)
380
381 if is_known_return_type(name) == 0:
382 test.write("""static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
383}
384static void desret_%s(%s val ATTRIBUTE_UNUSED) {
385}
386
387""" % (name, name, name, name))
388 known_return_types.append(name)
Daniel Veillard34099b42004-11-04 17:34:35 +0000389
390#
391# Load the interfaces
392#
Daniel Veillard57b25162004-11-06 14:50:18 +0000393headers = ctxt.xpathEval("/api/files/file")
Daniel Veillard34099b42004-11-04 17:34:35 +0000394for file in headers:
395 name = file.xpathEval('string(@name)')
396 if (name == None) or (name == ''):
397 continue
398
399 #
400 # Some module may be skipped because they don't really consists
401 # of user callable APIs
402 #
403 if is_skipped_module(name):
404 continue
405
406 #
407 # do not test deprecated APIs
408 #
409 desc = file.xpathEval('string(description)')
410 if string.find(desc, 'DEPRECATED') != -1:
411 print "Skipping deprecated interface %s" % name
412 continue;
413
414 test.write("#include <libxml/%s.h>\n" % name)
415 modules.append(name)
416
417#
418# Generate the callers signatures
419#
420for module in modules:
421 test.write("static int test_%s(void);\n" % module);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000422
423#
424# Generate the top caller
425#
426
427test.write("""
428/**
429 * testlibxml2:
430 *
431 * Main entry point of the tester for the full libxml2 module,
432 * it calls all the tester entry point for each module.
433 *
434 * Returns the number of error found
435 */
436static int
437testlibxml2(void)
438{
439 int ret = 0;
440
441""")
442
443for module in modules:
444 test.write(" ret += test_%s();\n" % module)
445
446test.write("""
Daniel Veillard3d97e662004-11-04 10:49:00 +0000447 printf("Total: %d functions, %d tests, %d errors\\n",
448 function_tests, call_tests, ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000449 return(ret);
450}
451
452""")
453
454#
455# How to handle a function
456#
457nb_tests = 0
458
459def generate_test(module, node):
460 global test
461 global nb_tests
462 nb_cond = 0
463 no_gen = 0
464
465 name = node.xpathEval('string(@name)')
466 if is_skipped_function(name):
467 return
468
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000469 #
470 # check we know how to handle the args and return values
471 # and store the informations for the generation
472 #
473 try:
474 args = node.xpathEval("arg")
475 except:
476 args = []
477 t_args = []
Daniel Veillarda03e3652004-11-02 18:45:30 +0000478 n = 0
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000479 for arg in args:
Daniel Veillarda03e3652004-11-02 18:45:30 +0000480 n = n + 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000481 rtype = arg.xpathEval("string(@type)")
482 if rtype == 'void':
483 break;
484 info = arg.xpathEval("string(@info)")
485 nam = arg.xpathEval("string(@name)")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000486 type = type_convert(rtype, nam, info, module, name, n)
Daniel Veillardce682bc2004-11-05 17:22:25 +0000487 if is_known_param_type(type, rtype) == 0:
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000488 add_missing_type(type, name);
489 no_gen = 1
490 t_args.append((nam, type, rtype, info))
491
492 try:
493 rets = node.xpathEval("return")
494 except:
495 rets = []
496 t_ret = None
497 for ret in rets:
498 rtype = ret.xpathEval("string(@type)")
499 info = ret.xpathEval("string(@info)")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000500 type = type_convert(rtype, 'return', info, module, name, 0)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000501 if rtype == 'void':
502 break
503 if is_known_return_type(type) == 0:
504 add_missing_type(type, name);
505 no_gen = 1
506 t_ret = (type, rtype, info)
507 break
508
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000509 test.write("""
510static int
511test_%s(void) {
512 int ret = 0;
513
514""" % (name))
515
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000516 if no_gen == 1:
Daniel Veillard34099b42004-11-04 17:34:35 +0000517 add_missing_functions(name, module)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000518 test.write("""
519 /* missing type support */
520 return(ret);
521}
522
523""")
524 return
525
526 try:
527 conds = node.xpathEval("cond")
528 for cond in conds:
529 test.write("#ifdef %s\n" % (cond.get_content()))
530 nb_cond = nb_cond + 1
531 except:
532 pass
533
534 # Declare the memory usage counter
535 no_mem = is_skipped_memcheck(name)
536 if no_mem == 0:
537 test.write(" int mem_base;\n");
538
539 # Declare the return value
540 if t_ret != None:
541 test.write(" %s ret_val;\n" % (t_ret[1]))
542
543 # Declare the arguments
544 for arg in t_args:
545 (nam, type, rtype, info) = arg;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000546 if (type[-3:] == 'Ptr' or type[-4:] == '_ptr') and \
547 rtype[0:6] == 'const ':
548 crtype = rtype[6:]
549 else:
550 crtype = rtype
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000551 # add declaration
Daniel Veillardce682bc2004-11-05 17:22:25 +0000552 test.write(" %s %s; /* %s */\n" % (crtype, nam, info))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000553 test.write(" int n_%s;\n" % (nam))
554 test.write("\n")
555
556 # Cascade loop on of each argument list of values
557 for arg in t_args:
558 (nam, type, rtype, info) = arg;
559 #
560 test.write(" for (n_%s = 0;n_%s < gen_nb_%s;n_%s++) {\n" % (
561 nam, nam, type, nam))
562
563 # log the memory usage
564 if no_mem == 0:
565 test.write(" mem_base = xmlMemBlocks();\n");
566
567 # prepare the call
Daniel Veillard3d97e662004-11-04 10:49:00 +0000568 i = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000569 for arg in t_args:
570 (nam, type, rtype, info) = arg;
571 #
Daniel Veillard3d97e662004-11-04 10:49:00 +0000572 test.write(" %s = gen_%s(n_%s, %d);\n" % (nam, type, nam, i))
573 i = i + 1;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000574
575 # do the call, and clanup the result
Daniel Veillard34099b42004-11-04 17:34:35 +0000576 if extra_pre_call.has_key(name):
577 test.write(" %s\n"% (extra_pre_call[name]))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000578 if t_ret != None:
579 test.write("\n ret_val = %s(" % (name))
580 need = 0
581 for arg in t_args:
582 (nam, type, rtype, info) = arg
583 if need:
584 test.write(", ")
585 else:
586 need = 1
587 test.write("%s" % nam);
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000588 test.write(");\n")
589 if extra_post_call.has_key(name):
590 test.write(" %s\n"% (extra_post_call[name]))
591 test.write(" desret_%s(ret_val);\n" % t_ret[0])
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000592 else:
593 test.write("\n %s(" % (name));
594 need = 0;
595 for arg in t_args:
596 (nam, type, rtype, info) = arg;
597 if need:
598 test.write(", ")
599 else:
600 need = 1
601 test.write("%s" % nam)
602 test.write(");\n")
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000603 if extra_post_call.has_key(name):
604 test.write(" %s\n"% (extra_post_call[name]))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000605
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000606 test.write(" call_tests++;\n");
Daniel Veillarda03e3652004-11-02 18:45:30 +0000607
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000608 # Free the arguments
Daniel Veillard3d97e662004-11-04 10:49:00 +0000609 i = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000610 for arg in t_args:
611 (nam, type, rtype, info) = arg;
612 #
Daniel Veillard3d97e662004-11-04 10:49:00 +0000613 test.write(" des_%s(n_%s, %s, %d);\n" % (type, nam, nam, i))
614 i = i + 1;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000615
616 test.write(" xmlResetLastError();\n");
617 # Check the memory usage
618 if no_mem == 0:
619 test.write(""" if (mem_base != xmlMemBlocks()) {
Daniel Veillarda03e3652004-11-02 18:45:30 +0000620 printf("Leak of %%d blocks found in %s",
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000621 xmlMemBlocks() - mem_base);
622 ret++;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000623""" % (name));
Daniel Veillarda03e3652004-11-02 18:45:30 +0000624 for arg in t_args:
625 (nam, type, rtype, info) = arg;
626 test.write(""" printf(" %%d", n_%s);\n""" % (nam))
627 test.write(""" printf("\\n");\n""")
628 test.write(" }\n")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000629
630 for arg in t_args:
631 test.write(" }\n")
632
633 #
634 # end of conditional
635 #
636 while nb_cond > 0:
637 test.write("#endif\n")
638 nb_cond = nb_cond -1
639
640 nb_tests = nb_tests + 1;
641
642 test.write("""
Daniel Veillard3d97e662004-11-04 10:49:00 +0000643 function_tests++;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000644 return(ret);
645}
646
647""")
648
649#
650# Generate all module callers
651#
652for module in modules:
653 # gather all the functions exported by that module
654 try:
655 functions = ctxt.xpathEval("/api/symbols/function[@file='%s']" % (module))
656 except:
657 print "Failed to gather functions from module %s" % (module)
658 continue;
659
660 # iterate over all functions in the module generating the test
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000661 i = 0
662 nb_tests_old = nb_tests
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000663 for function in functions:
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000664 i = i + 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000665 generate_test(module, function);
666
667 # header
668 test.write("""static int
669test_%s(void) {
670 int ret = 0;
671
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000672 printf("Testing %s : %d of %d functions ...\\n");
673""" % (module, module, nb_tests - nb_tests_old, i))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000674
675 # iterate over all functions in the module generating the call
676 for function in functions:
677 name = function.xpathEval('string(@name)')
678 if is_skipped_function(name):
679 continue
680 test.write(" ret += test_%s();\n" % (name))
681
682 # footer
683 test.write("""
684 if (ret != 0)
685 printf("Module %s: %%d errors\\n", ret);
686 return(ret);
687}
688""" % (module))
689
Daniel Veillardce244ad2004-11-05 10:03:46 +0000690#
691# Generate direct module caller
692#
693test.write("""static int
694test_module(const char *module) {
695""");
696for module in modules:
697 test.write(""" if (!strcmp(module, "%s")) return(test_%s());\n""" % (
698 module, module))
699test.write(""" return(0);
700}
701""");
702
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000703print "Generated test for %d modules and %d functions" %(len(modules), nb_tests)
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000704
Daniel Veillard34099b42004-11-04 17:34:35 +0000705compare_and_save()
706
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000707missing_list = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000708for missing in missing_types.keys():
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000709 if missing == 'va_list' or missing == '...':
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000710 continue;
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000711
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000712 n = len(missing_types[missing])
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000713 missing_list.append((n, missing))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000714
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000715def compare_missing(a, b):
716 return b[0] - a[0]
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000717
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000718missing_list.sort(compare_missing)
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000719print "Missing support for %d functions and %d types see missing.lst" % (missing_functions_nr, len(missing_list))
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000720lst = open("missing.lst", "w")
Daniel Veillard34099b42004-11-04 17:34:35 +0000721lst.write("Missing support for %d types" % (len(missing_list)))
722lst.write("\n")
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000723for miss in missing_list:
724 lst.write("%s: %d :" % (miss[1], miss[0]))
725 i = 0
726 for n in missing_types[miss[1]]:
727 i = i + 1
728 if i > 5:
729 lst.write(" ...")
730 break
731 lst.write(" %s" % (n))
732 lst.write("\n")
Daniel Veillard34099b42004-11-04 17:34:35 +0000733lst.write("\n")
734lst.write("\n")
735lst.write("Missing support per module");
736for module in missing_functions.keys():
737 lst.write("module %s:\n %s\n" % (module, missing_functions[module]))
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000738
739lst.close()
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000740
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000741