blob: 3553dcd69d1671f902c76e47331b14af86284b54 [file] [log] [blame]
Daniel Veillard36e5cd52004-11-02 14:52:23 +00001#!/usr/bin/python -u
2#
3# generate a tester program for the API
4#
5import sys
Daniel Veillard34099b42004-11-04 17:34:35 +00006import os
Daniel Veillard36e5cd52004-11-02 14:52:23 +00007import string
8try:
9 import libxml2
10except:
11 print "libxml2 python bindings not available, skipping testapi.c generation"
12 sys.exit(0)
13
14#
15# Modules we don't want skip in API test
16#
Daniel Veillard2a4fb5a2004-11-08 14:02:18 +000017skipped_modules = [ "SAX", "xlink", "threads", "globals",
18 "xpathInternals", "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 Veillard2a4fb5a2004-11-08 14:02:18 +000056"xmlNewGlobalNs", "xmlHandleEntity", "xmlNamespaceParseNCName",
57"xmlNamespaceParseNSDef", "xmlNamespaceParseQName",
58"xmlParseNamespace", "xmlParseQuotedString", "xmlParserHandleReference",
59"xmlScanName",
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +000060# allocators
61"xmlMemFree",
Daniel Veillardc2c894f2004-11-07 12:17:35 +000062# verbosity
63"xmlCatalogSetDebug",
Daniel Veillard2a4fb5a2004-11-08 14:02:18 +000064# Internal functions, no user space should really call them
65"xmlParseAttribute", "xmlParseAttributeListDecl", "xmlParseName",
66"xmlParseNmtoken", "xmlParseEntityValue", "xmlParseAttValue",
67"xmlParseSystemLiteral", "xmlParsePubidLiteral", "xmlParseCharData",
68"xmlParseExternalID", "xmlParseComment", "xmlParsePITarget", "xmlParsePI",
69"xmlParseNotationDecl", "xmlParseEntityDecl", "xmlParseDefaultDecl",
70"xmlParseNotationType", "xmlParseEnumerationType", "xmlParseEnumeratedType",
71"xmlParseAttributeType", "xmlParseAttributeListDecl",
72"xmlParseElementMixedContentDecl", "xmlParseElementChildrenContentDecl",
73"xmlParseElementContentDecl", "xmlParseElementDecl", "xmlParseMarkupDecl",
74"xmlParseCharRef", "xmlParseEntityRef", "xmlParseReference",
75"xmlParsePEReference", "xmlParseDocTypeDecl", "xmlParseAttribute",
76"xmlParseStartTag", "xmlParseEndTag", "xmlParseCDSect", "xmlParseContent",
77"xmlParseElement", "xmlParseVersionNum", "xmlParseVersionInfo",
78"xmlParseEncName", "xmlParseEncodingDecl", "xmlParseSDDecl",
79"xmlParseXMLDecl", "xmlParseTextDecl", "xmlParseMisc",
80"xmlParseExternalSubset", "xmlParserHandlePEReference",
81"xmlSkipBlankChars",
Daniel Veillarddd6d3002004-11-03 14:20:29 +000082]
Daniel Veillard36e5cd52004-11-02 14:52:23 +000083
84#
85# Those functions have side effect on the global state
86# and hence generate errors on memory allocation tests
87#
88skipped_memcheck = [ "xmlLoadCatalog", "xmlAddEncodingAlias",
89 "xmlSchemaInitTypes", "xmlNanoFTPProxy", "xmlNanoFTPScanProxy",
90 "xmlNanoHTTPScanProxy", "xmlResetLastError", "xmlCatalogConvert",
91 "xmlCatalogRemove", "xmlLoadCatalogs", "xmlCleanupCharEncodingHandlers",
Daniel Veillarda03e3652004-11-02 18:45:30 +000092 "xmlInitCharEncodingHandlers", "xmlCatalogCleanup",
Daniel Veillard42595322004-11-08 10:52:06 +000093 "xmlSchemaGetBuiltInType",
94 "htmlParseFile", # loads the catalogs
Daniel Veillarda03e3652004-11-02 18:45:30 +000095]
96
97#
98# Extra code needed for some test cases
99#
Daniel Veillard34099b42004-11-04 17:34:35 +0000100extra_pre_call = {
101 "xmlSAXUserParseFile":
Daniel Veillardce244ad2004-11-05 10:03:46 +0000102 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
Daniel Veillard34099b42004-11-04 17:34:35 +0000103 "xmlSAXUserParseMemory":
Daniel Veillardce244ad2004-11-05 10:03:46 +0000104 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
Daniel Veillardce682bc2004-11-05 17:22:25 +0000105 "xmlParseBalancedChunkMemory":
106 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
107 "xmlParseBalancedChunkMemoryRecover":
108 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000109 "xmlParserInputBufferCreateFd":
110 "if (fd >= 0) fd = -1;",
Daniel Veillard34099b42004-11-04 17:34:35 +0000111}
Daniel Veillarda03e3652004-11-02 18:45:30 +0000112extra_post_call = {
113 "xmlAddChild":
114 "if (ret_val == NULL) { xmlFreeNode(cur) ; cur = NULL ; }",
115 "xmlAddChildList":
116 "if (ret_val == NULL) { xmlFreeNodeList(cur) ; cur = NULL ; }",
117 "xmlAddSibling":
118 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
119 "xmlAddNextSibling":
120 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
121 "xmlAddPrevSibling":
122 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
123 "xmlDocSetRootElement":
124 "if (doc == NULL) { xmlFreeNode(root) ; root = NULL ; }",
125 "xmlReplaceNode":
Daniel Veillardce244ad2004-11-05 10:03:46 +0000126 """if (cur != NULL) {
127 xmlUnlinkNode(cur);
128 xmlFreeNode(cur) ; cur = NULL ; }
129 if (old != NULL) {
130 xmlUnlinkNode(old);
131 xmlFreeNode(old) ; old = NULL ; }
132 ret_val = NULL;""",
Daniel Veillarda03e3652004-11-02 18:45:30 +0000133 "xmlTextMerge":
134 """if ((first != NULL) && (first->type != XML_TEXT_NODE)) {
Daniel Veillardce244ad2004-11-05 10:03:46 +0000135 xmlUnlinkNode(second);
Daniel Veillarda03e3652004-11-02 18:45:30 +0000136 xmlFreeNode(second) ; second = NULL ; }""",
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000137 "xmlBuildQName":
138 """if ((ret_val != NULL) && (ret_val != ncname) &&
139 (ret_val != prefix) && (ret_val != memory))
140 xmlFree(ret_val);
141 ret_val = NULL;""",
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000142 "xmlDictReference": "xmlDictFree(dict);",
Daniel Veillard3d97e662004-11-04 10:49:00 +0000143 # Functions which deallocates one of their parameters
144 "xmlXPathConvertBoolean": """val = NULL;""",
145 "xmlXPathConvertNumber": """val = NULL;""",
146 "xmlXPathConvertString": """val = NULL;""",
147 "xmlSaveFileTo": """buf = NULL;""",
Daniel Veillard34099b42004-11-04 17:34:35 +0000148 "xmlSaveFormatFileTo": """buf = NULL;""",
149 "xmlIOParseDTD": "input = NULL;",
Daniel Veillardce244ad2004-11-05 10:03:46 +0000150 "xmlRemoveProp": "cur = NULL;",
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000151 "xmlNewNs": "if ((node == NULL) && (ret_val != NULL)) xmlFreeNs(ret_val);",
152 "xmlCopyNamespace": "if (ret_val != NULL) xmlFreeNs(ret_val);",
153 "xmlCopyNamespaceList": "if (ret_val != NULL) xmlFreeNsList(ret_val);",
154 "xmlNewTextWriter": "if (ret_val != NULL) out = NULL;",
155 "xmlNewTextWriterPushParser": "if (ret_val != NULL) ctxt = NULL;",
Daniel Veillard42595322004-11-08 10:52:06 +0000156 "xmlNewIOInputStream": "if (ret_val != NULL) input = NULL;",
Daniel Veillarda03e3652004-11-02 18:45:30 +0000157}
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000158
159modules = []
160
161def is_skipped_module(name):
162 for mod in skipped_modules:
163 if mod == name:
164 return 1
165 return 0
166
167def is_skipped_function(name):
168 for fun in skipped_functions:
169 if fun == name:
170 return 1
171 # Do not test destructors
172 if string.find(name, 'Free') != -1:
173 return 1
174 return 0
175
176def is_skipped_memcheck(name):
177 for fun in skipped_memcheck:
178 if fun == name:
179 return 1
180 return 0
181
182missing_types = {}
183def add_missing_type(name, func):
184 try:
185 list = missing_types[name]
186 list.append(func)
187 except:
188 missing_types[name] = [func]
189
Daniel Veillardce682bc2004-11-05 17:22:25 +0000190generated_param_types = []
191def add_generated_param_type(name):
192 generated_param_types.append(name)
193
194generated_return_types = []
195def add_generated_return_type(name):
196 generated_return_types.append(name)
197
Daniel Veillard34099b42004-11-04 17:34:35 +0000198missing_functions = {}
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000199missing_functions_nr = 0
Daniel Veillard34099b42004-11-04 17:34:35 +0000200def add_missing_functions(name, module):
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000201 global missing_functions_nr
202
203 missing_functions_nr = missing_functions_nr + 1
Daniel Veillard34099b42004-11-04 17:34:35 +0000204 try:
205 list = missing_functions[module]
206 list.append(name)
207 except:
208 missing_functions[module] = [name]
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000209
210#
211# Provide the type generators and destructors for the parameters
212#
213
Daniel Veillarda03e3652004-11-02 18:45:30 +0000214def type_convert(str, name, info, module, function, pos):
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000215# res = string.replace(str, " ", " ")
216# res = string.replace(str, " ", " ")
217# res = string.replace(str, " ", " ")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000218 res = string.replace(str, " *", "_ptr")
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000219# res = string.replace(str, "*", "_ptr")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000220 res = string.replace(res, " ", "_")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000221 res = string.replace(res, "htmlNode", "xmlNode")
222 res = string.replace(res, "htmlDoc", "xmlDoc")
223 res = string.replace(res, "htmlParser", "xmlParser")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000224 if res == 'const_char_ptr':
225 if string.find(name, "file") != -1 or \
226 string.find(name, "uri") != -1 or \
227 string.find(name, "URI") != -1 or \
228 string.find(info, "filename") != -1 or \
229 string.find(info, "URI") != -1 or \
230 string.find(info, "URL") != -1:
William M. Brack83d9c372004-11-08 02:26:08 +0000231 if string.find(function, "Save") != -1 or \
232 string.find(function, "Create") != -1 or \
233 string.find(function, "Write") != -1:
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000234 return('fileoutput')
235 return('filepath')
236 if res == 'void_ptr':
237 if module == 'nanoftp' and name == 'ctx':
238 return('xmlNanoFTPCtxtPtr')
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000239 if function == 'xmlNanoFTPNewCtxt':
240 return('xmlNanoFTPCtxtPtr')
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000241 if module == 'nanohttp' and name == 'ctx':
242 return('xmlNanoHTTPCtxtPtr')
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000243 if function == 'xmlIOHTTPOpenW':
244 return('xmlNanoHTTPCtxtPtr')
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000245 if string.find(name, "data") != -1:
246 return('userdata');
Daniel Veillardd005b9e2004-11-03 17:07:05 +0000247 if string.find(name, "user") != -1:
248 return('userdata');
Daniel Veillard3d97e662004-11-04 10:49:00 +0000249 if res == 'xmlDoc_ptr':
250 res = 'xmlDocPtr';
251 if res == 'xmlNode_ptr':
252 res = 'xmlNodePtr';
253 if res == 'xmlDict_ptr':
254 res = 'xmlDictPtr';
Daniel Veillarda03e3652004-11-02 18:45:30 +0000255 if res == 'xmlNodePtr' and pos != 0:
256 if (function == 'xmlAddChild' and pos == 2) or \
257 (function == 'xmlAddChildList' and pos == 2) or \
258 (function == 'xmlAddNextSibling' and pos == 2) or \
259 (function == 'xmlAddSibling' and pos == 2) or \
260 (function == 'xmlDocSetRootElement' and pos == 2) or \
261 (function == 'xmlReplaceNode' and pos == 2) or \
262 (function == 'xmlTextMerge') or \
263 (function == 'xmlAddPrevSibling' and pos == 2):
264 return('xmlNodePtr_in');
Daniel Veillard34099b42004-11-04 17:34:35 +0000265 if res == 'const xmlBufferPtr':
266 res = 'xmlBufferPtr';
Daniel Veillard27f20102004-11-05 11:50:11 +0000267 if res == 'xmlChar_ptr' and name == 'name' and \
268 string.find(function, "EatName") != -1:
269 return('eaten_name')
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000270 if res == 'void_ptr*':
271 res = 'void_ptr_ptr'
272 if res == 'char_ptr*':
273 res = 'char_ptr_ptr'
274 if res == 'xmlChar_ptr*':
275 res = 'xmlChar_ptr_ptr'
276 if res == 'const_xmlChar_ptr*':
277 res = 'const_xmlChar_ptr_ptr'
278 if res == 'const_char_ptr*':
279 res = 'const_char_ptr_ptr'
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000280
281 return res
282
Daniel Veillard34099b42004-11-04 17:34:35 +0000283known_param_types = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000284
Daniel Veillardce682bc2004-11-05 17:22:25 +0000285def is_known_param_type(name, rtype):
286 global test
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000287 for type in known_param_types:
288 if type == name:
289 return 1
Daniel Veillardce682bc2004-11-05 17:22:25 +0000290 for type in generated_param_types:
291 if type == name:
292 return 1
293
294 if name[-3:] == 'Ptr' or name[-4:] == '_ptr':
295 if rtype[0:6] == 'const ':
296 crtype = rtype[6:]
297 else:
298 crtype = rtype
299
300 test.write("""
301#define gen_nb_%s 1
302static %s gen_%s(int no ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
303 return(NULL);
304}
305static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
306}
307""" % (name, crtype, name, name, rtype))
308 add_generated_param_type(name)
309 return 1
310
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000311 return 0
312
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000313#
314# Provide the type destructors for the return values
315#
316
Daniel Veillard34099b42004-11-04 17:34:35 +0000317known_return_types = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000318
319def is_known_return_type(name):
320 for type in known_return_types:
321 if type == name:
322 return 1
323 return 0
324
Daniel Veillard34099b42004-11-04 17:34:35 +0000325#
326# Copy the beginning of the C test program result
327#
328
329input = open("testapi.c", "r")
330test = open('testapi.c.new', 'w')
331
332def compare_and_save():
333 global test
334
335 test.close()
336 input = open("testapi.c", "r").read()
337 test = open('testapi.c.new', "r").read()
338 if input != test:
339 os.system("rm testapi.c ; mv testapi.c.new testapi.c")
340 print("Updated testapi.c")
341 else:
342 print("Generated testapi.c is identical")
343
344line = input.readline()
345while line != "":
346 if line == "/* CUT HERE: everything below that line is generated */\n":
347 break;
348 if line[0:15] == "#define gen_nb_":
349 type = string.split(line[15:])[0]
350 known_param_types.append(type)
351 if line[0:19] == "static void desret_":
352 type = string.split(line[19:], '(')[0]
353 known_return_types.append(type)
354 test.write(line)
355 line = input.readline()
356input.close()
357
358if line == "":
359 print "Could not find the CUT marker in testapi.c skipping generation"
360 test.close()
361 sys.exit(0)
362
363print("Scanned testapi.c: found %d parameters types and %d return types\n" % (
364 len(known_param_types), len(known_return_types)))
365test.write("/* CUT HERE: everything below that line is generated */\n")
366
367
368#
369# Open the input API description
370#
371doc = libxml2.readFile('doc/libxml2-api.xml', None, 0)
372if doc == None:
373 print "Failed to load doc/libxml2-api.xml"
374 sys.exit(1)
375ctxt = doc.xpathNewContext()
Daniel Veillard57b25162004-11-06 14:50:18 +0000376
377#
378# Generate constructors and return type handling for all enums
379#
380enums = ctxt.xpathEval("/api/symbols/typedef[@type='enum']")
381for enum in enums:
382 name = enum.xpathEval('string(@name)')
383 if name == None:
384 continue;
385
386 if is_known_param_type(name, name) == 0:
387 values = ctxt.xpathEval("/api/symbols/enum[@type='%s']" % name)
388 i = 0
389 vals = []
390 for value in values:
391 vname = value.xpathEval('string(@name)')
392 if vname == None:
393 continue;
394 i = i + 1
395 if i >= 5:
396 break;
397 vals.append(vname)
398 if vals == []:
399 print "Didn't found any value for enum %s" % (name)
400 continue
401 test.write("#define gen_nb_%s %d\n" % (name, len(vals)))
402 test.write("""static %s gen_%s(int no, int nr ATTRIBUTE_UNUSED) {\n""" %
403 (name, name))
404 i = 1
405 for value in vals:
406 test.write(" if (no == %d) return(%s);\n" % (i, value))
407 i = i + 1
408 test.write(""" return(0);
409}
410""");
411 known_param_types.append(name)
412
413 if is_known_return_type(name) == 0:
414 test.write("""static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
415}
416static void desret_%s(%s val ATTRIBUTE_UNUSED) {
417}
418
419""" % (name, name, name, name))
420 known_return_types.append(name)
Daniel Veillard34099b42004-11-04 17:34:35 +0000421
422#
423# Load the interfaces
424#
Daniel Veillard57b25162004-11-06 14:50:18 +0000425headers = ctxt.xpathEval("/api/files/file")
Daniel Veillard34099b42004-11-04 17:34:35 +0000426for file in headers:
427 name = file.xpathEval('string(@name)')
428 if (name == None) or (name == ''):
429 continue
430
431 #
432 # Some module may be skipped because they don't really consists
433 # of user callable APIs
434 #
435 if is_skipped_module(name):
436 continue
437
438 #
439 # do not test deprecated APIs
440 #
441 desc = file.xpathEval('string(description)')
442 if string.find(desc, 'DEPRECATED') != -1:
443 print "Skipping deprecated interface %s" % name
444 continue;
445
446 test.write("#include <libxml/%s.h>\n" % name)
447 modules.append(name)
448
449#
450# Generate the callers signatures
451#
452for module in modules:
453 test.write("static int test_%s(void);\n" % module);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000454
455#
456# Generate the top caller
457#
458
459test.write("""
460/**
461 * testlibxml2:
462 *
463 * Main entry point of the tester for the full libxml2 module,
464 * it calls all the tester entry point for each module.
465 *
466 * Returns the number of error found
467 */
468static int
469testlibxml2(void)
470{
Daniel Veillard42595322004-11-08 10:52:06 +0000471 int test_ret = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000472
473""")
474
475for module in modules:
Daniel Veillard42595322004-11-08 10:52:06 +0000476 test.write(" test_ret += test_%s();\n" % module)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000477
478test.write("""
Daniel Veillard3d97e662004-11-04 10:49:00 +0000479 printf("Total: %d functions, %d tests, %d errors\\n",
Daniel Veillard42595322004-11-08 10:52:06 +0000480 function_tests, call_tests, test_ret);
481 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000482}
483
484""")
485
486#
487# How to handle a function
488#
489nb_tests = 0
490
491def generate_test(module, node):
492 global test
493 global nb_tests
494 nb_cond = 0
495 no_gen = 0
496
497 name = node.xpathEval('string(@name)')
498 if is_skipped_function(name):
499 return
500
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000501 #
502 # check we know how to handle the args and return values
503 # and store the informations for the generation
504 #
505 try:
506 args = node.xpathEval("arg")
507 except:
508 args = []
509 t_args = []
Daniel Veillarda03e3652004-11-02 18:45:30 +0000510 n = 0
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000511 for arg in args:
Daniel Veillarda03e3652004-11-02 18:45:30 +0000512 n = n + 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000513 rtype = arg.xpathEval("string(@type)")
514 if rtype == 'void':
515 break;
516 info = arg.xpathEval("string(@info)")
517 nam = arg.xpathEval("string(@name)")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000518 type = type_convert(rtype, nam, info, module, name, n)
Daniel Veillardce682bc2004-11-05 17:22:25 +0000519 if is_known_param_type(type, rtype) == 0:
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000520 add_missing_type(type, name);
521 no_gen = 1
522 t_args.append((nam, type, rtype, info))
523
524 try:
525 rets = node.xpathEval("return")
526 except:
527 rets = []
528 t_ret = None
529 for ret in rets:
530 rtype = ret.xpathEval("string(@type)")
531 info = ret.xpathEval("string(@info)")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000532 type = type_convert(rtype, 'return', info, module, name, 0)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000533 if rtype == 'void':
534 break
535 if is_known_return_type(type) == 0:
536 add_missing_type(type, name);
537 no_gen = 1
538 t_ret = (type, rtype, info)
539 break
540
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000541 test.write("""
542static int
543test_%s(void) {
Daniel Veillard42595322004-11-08 10:52:06 +0000544 int test_ret = 0;
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000545
546""" % (name))
547
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000548 if no_gen == 1:
Daniel Veillard34099b42004-11-04 17:34:35 +0000549 add_missing_functions(name, module)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000550 test.write("""
551 /* missing type support */
Daniel Veillard42595322004-11-08 10:52:06 +0000552 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000553}
554
555""")
556 return
557
558 try:
559 conds = node.xpathEval("cond")
560 for cond in conds:
561 test.write("#ifdef %s\n" % (cond.get_content()))
562 nb_cond = nb_cond + 1
563 except:
564 pass
565
566 # Declare the memory usage counter
567 no_mem = is_skipped_memcheck(name)
568 if no_mem == 0:
569 test.write(" int mem_base;\n");
570
571 # Declare the return value
572 if t_ret != None:
573 test.write(" %s ret_val;\n" % (t_ret[1]))
574
575 # Declare the arguments
576 for arg in t_args:
577 (nam, type, rtype, info) = arg;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000578 if (type[-3:] == 'Ptr' or type[-4:] == '_ptr') and \
579 rtype[0:6] == 'const ':
580 crtype = rtype[6:]
581 else:
582 crtype = rtype
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000583 # add declaration
Daniel Veillardce682bc2004-11-05 17:22:25 +0000584 test.write(" %s %s; /* %s */\n" % (crtype, nam, info))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000585 test.write(" int n_%s;\n" % (nam))
586 test.write("\n")
587
588 # Cascade loop on of each argument list of values
589 for arg in t_args:
590 (nam, type, rtype, info) = arg;
591 #
592 test.write(" for (n_%s = 0;n_%s < gen_nb_%s;n_%s++) {\n" % (
593 nam, nam, type, nam))
594
595 # log the memory usage
596 if no_mem == 0:
597 test.write(" mem_base = xmlMemBlocks();\n");
598
599 # prepare the call
Daniel Veillard3d97e662004-11-04 10:49:00 +0000600 i = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000601 for arg in t_args:
602 (nam, type, rtype, info) = arg;
603 #
Daniel Veillard3d97e662004-11-04 10:49:00 +0000604 test.write(" %s = gen_%s(n_%s, %d);\n" % (nam, type, nam, i))
605 i = i + 1;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000606
607 # do the call, and clanup the result
Daniel Veillard34099b42004-11-04 17:34:35 +0000608 if extra_pre_call.has_key(name):
609 test.write(" %s\n"% (extra_pre_call[name]))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000610 if t_ret != None:
611 test.write("\n ret_val = %s(" % (name))
612 need = 0
613 for arg in t_args:
614 (nam, type, rtype, info) = arg
615 if need:
616 test.write(", ")
617 else:
618 need = 1
619 test.write("%s" % nam);
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000620 test.write(");\n")
621 if extra_post_call.has_key(name):
622 test.write(" %s\n"% (extra_post_call[name]))
623 test.write(" desret_%s(ret_val);\n" % t_ret[0])
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000624 else:
625 test.write("\n %s(" % (name));
626 need = 0;
627 for arg in t_args:
628 (nam, type, rtype, info) = arg;
629 if need:
630 test.write(", ")
631 else:
632 need = 1
633 test.write("%s" % nam)
634 test.write(");\n")
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000635 if extra_post_call.has_key(name):
636 test.write(" %s\n"% (extra_post_call[name]))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000637
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000638 test.write(" call_tests++;\n");
Daniel Veillarda03e3652004-11-02 18:45:30 +0000639
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000640 # Free the arguments
Daniel Veillard3d97e662004-11-04 10:49:00 +0000641 i = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000642 for arg in t_args:
643 (nam, type, rtype, info) = arg;
644 #
Daniel Veillard3d97e662004-11-04 10:49:00 +0000645 test.write(" des_%s(n_%s, %s, %d);\n" % (type, nam, nam, i))
646 i = i + 1;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000647
648 test.write(" xmlResetLastError();\n");
649 # Check the memory usage
650 if no_mem == 0:
651 test.write(""" if (mem_base != xmlMemBlocks()) {
Daniel Veillarda03e3652004-11-02 18:45:30 +0000652 printf("Leak of %%d blocks found in %s",
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000653 xmlMemBlocks() - mem_base);
Daniel Veillard42595322004-11-08 10:52:06 +0000654 test_ret++;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000655""" % (name));
Daniel Veillarda03e3652004-11-02 18:45:30 +0000656 for arg in t_args:
657 (nam, type, rtype, info) = arg;
658 test.write(""" printf(" %%d", n_%s);\n""" % (nam))
659 test.write(""" printf("\\n");\n""")
660 test.write(" }\n")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000661
662 for arg in t_args:
663 test.write(" }\n")
664
665 #
666 # end of conditional
667 #
668 while nb_cond > 0:
669 test.write("#endif\n")
670 nb_cond = nb_cond -1
671
672 nb_tests = nb_tests + 1;
673
674 test.write("""
Daniel Veillard3d97e662004-11-04 10:49:00 +0000675 function_tests++;
Daniel Veillard42595322004-11-08 10:52:06 +0000676 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000677}
678
679""")
680
681#
682# Generate all module callers
683#
684for module in modules:
685 # gather all the functions exported by that module
686 try:
687 functions = ctxt.xpathEval("/api/symbols/function[@file='%s']" % (module))
688 except:
689 print "Failed to gather functions from module %s" % (module)
690 continue;
691
692 # iterate over all functions in the module generating the test
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000693 i = 0
694 nb_tests_old = nb_tests
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000695 for function in functions:
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000696 i = i + 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000697 generate_test(module, function);
698
699 # header
700 test.write("""static int
701test_%s(void) {
Daniel Veillard42595322004-11-08 10:52:06 +0000702 int test_ret = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000703
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000704 printf("Testing %s : %d of %d functions ...\\n");
705""" % (module, module, nb_tests - nb_tests_old, i))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000706
707 # iterate over all functions in the module generating the call
708 for function in functions:
709 name = function.xpathEval('string(@name)')
710 if is_skipped_function(name):
711 continue
Daniel Veillard42595322004-11-08 10:52:06 +0000712 test.write(" test_ret += test_%s();\n" % (name))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000713
714 # footer
715 test.write("""
Daniel Veillard42595322004-11-08 10:52:06 +0000716 if (test_ret != 0)
717 printf("Module %s: %%d errors\\n", test_ret);
718 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000719}
720""" % (module))
721
Daniel Veillardce244ad2004-11-05 10:03:46 +0000722#
723# Generate direct module caller
724#
725test.write("""static int
726test_module(const char *module) {
727""");
728for module in modules:
729 test.write(""" if (!strcmp(module, "%s")) return(test_%s());\n""" % (
730 module, module))
731test.write(""" return(0);
732}
733""");
734
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000735print "Generated test for %d modules and %d functions" %(len(modules), nb_tests)
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000736
Daniel Veillard34099b42004-11-04 17:34:35 +0000737compare_and_save()
738
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000739missing_list = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000740for missing in missing_types.keys():
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000741 if missing == 'va_list' or missing == '...':
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000742 continue;
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000743
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000744 n = len(missing_types[missing])
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000745 missing_list.append((n, missing))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000746
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000747def compare_missing(a, b):
748 return b[0] - a[0]
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000749
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000750missing_list.sort(compare_missing)
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000751print "Missing support for %d functions and %d types see missing.lst" % (missing_functions_nr, len(missing_list))
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000752lst = open("missing.lst", "w")
Daniel Veillard34099b42004-11-04 17:34:35 +0000753lst.write("Missing support for %d types" % (len(missing_list)))
754lst.write("\n")
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000755for miss in missing_list:
756 lst.write("%s: %d :" % (miss[1], miss[0]))
757 i = 0
758 for n in missing_types[miss[1]]:
759 i = i + 1
760 if i > 5:
761 lst.write(" ...")
762 break
763 lst.write(" %s" % (n))
764 lst.write("\n")
Daniel Veillard34099b42004-11-04 17:34:35 +0000765lst.write("\n")
766lst.write("\n")
767lst.write("Missing support per module");
768for module in missing_functions.keys():
769 lst.write("module %s:\n %s\n" % (module, missing_functions[module]))
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000770
771lst.close()
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000772
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000773