blob: b77b8857d100c4a83d71629f060c35bd5b263994 [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",
Daniel Veillarda82b1822004-11-08 16:24:57 +000018 "xmlmemory", "xmlversion", "xmlexports",
19 #deprecated
20 "DOCBparser",
Daniel Veillardd005b9e2004-11-03 17:07:05 +000021]
Daniel Veillard36e5cd52004-11-02 14:52:23 +000022
23#
24# Some function really need to be skipped for the tests.
25#
Daniel Veillarddd6d3002004-11-03 14:20:29 +000026skipped_functions = [
27# block on I/O
28"xmlFdRead", "xmlReadFd", "xmlCtxtReadFd",
29"htmlFdRead", "htmlReadFd", "htmlCtxtReadFd",
Daniel Veillard1ba06bb2004-11-04 12:32:18 +000030"xmlReaderNewFd", "xmlReaderForFd",
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +000031"xmlIORead", "xmlReadIO", "xmlCtxtReadIO",
32"htmlIORead", "htmlReadIO", "htmlCtxtReadIO",
Daniel Veillard27f20102004-11-05 11:50:11 +000033"xmlReaderNewIO", "xmlBufferDump", "xmlNanoFTPConnect",
34"xmlNanoFTPConnectTo",
Daniel Veillard42595322004-11-08 10:52:06 +000035# Complex I/O APIs
36"xmlCreateIOParserCtxt", "xmlParserInputBufferCreateIO",
37"xmlRegisterInputCallbacks", "xmlReaderForIO",
38"xmlOutputBufferCreateIO", "xmlRegisterOutputCallbacks",
39"xmlSaveToIO",
Daniel Veillarddd6d3002004-11-03 14:20:29 +000040# library state cleanup, generate false leak informations and other
41# troubles, heavillyb tested otherwise.
Daniel Veillardce244ad2004-11-05 10:03:46 +000042"xmlCleanupParser", "xmlRelaxNGCleanupTypes", "xmlSetListDoc",
43"xmlSetTreeDoc", "xmlUnlinkNode",
Daniel Veillarddd6d3002004-11-03 14:20:29 +000044# hard to avoid leaks in the tests
Daniel Veillardd5cc0f72004-11-06 19:24:28 +000045"xmlStrcat", "xmlStrncat", "xmlCatalogAddLocal", "xmlNewTextWriterDoc",
Daniel Veillarda82b1822004-11-08 16:24:57 +000046"xmlXPathNewValueTree", "xmlXPathWrapString",
Daniel Veillarddd6d3002004-11-03 14:20:29 +000047# unimplemented
48"xmlTextReaderReadInnerXml", "xmlTextReaderReadOuterXml",
Daniel Veillardd005b9e2004-11-03 17:07:05 +000049"xmlTextReaderReadString",
50# destructor
Daniel Veillard27f20102004-11-05 11:50:11 +000051"xmlListDelete", "xmlOutputBufferClose", "xmlNanoFTPClose",
Daniel Veillardd005b9e2004-11-03 17:07:05 +000052# deprecated
53"xmlCatalogGetPublic", "xmlCatalogGetSystem", "xmlEncodeEntities",
Daniel Veillard2a4fb5a2004-11-08 14:02:18 +000054"xmlNewGlobalNs", "xmlHandleEntity", "xmlNamespaceParseNCName",
55"xmlNamespaceParseNSDef", "xmlNamespaceParseQName",
56"xmlParseNamespace", "xmlParseQuotedString", "xmlParserHandleReference",
57"xmlScanName",
Daniel Veillarda82b1822004-11-08 16:24:57 +000058"xmlDecodeEntities",
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +000059# allocators
60"xmlMemFree",
Daniel Veillardc2c894f2004-11-07 12:17:35 +000061# verbosity
Daniel Veillarda82b1822004-11-08 16:24:57 +000062"xmlCatalogSetDebug", "xmlShellPrintXPathError", "xmlShellPrintNode",
Daniel Veillard2a4fb5a2004-11-08 14:02:18 +000063# Internal functions, no user space should really call them
64"xmlParseAttribute", "xmlParseAttributeListDecl", "xmlParseName",
65"xmlParseNmtoken", "xmlParseEntityValue", "xmlParseAttValue",
66"xmlParseSystemLiteral", "xmlParsePubidLiteral", "xmlParseCharData",
67"xmlParseExternalID", "xmlParseComment", "xmlParsePITarget", "xmlParsePI",
68"xmlParseNotationDecl", "xmlParseEntityDecl", "xmlParseDefaultDecl",
69"xmlParseNotationType", "xmlParseEnumerationType", "xmlParseEnumeratedType",
70"xmlParseAttributeType", "xmlParseAttributeListDecl",
71"xmlParseElementMixedContentDecl", "xmlParseElementChildrenContentDecl",
72"xmlParseElementContentDecl", "xmlParseElementDecl", "xmlParseMarkupDecl",
73"xmlParseCharRef", "xmlParseEntityRef", "xmlParseReference",
74"xmlParsePEReference", "xmlParseDocTypeDecl", "xmlParseAttribute",
75"xmlParseStartTag", "xmlParseEndTag", "xmlParseCDSect", "xmlParseContent",
76"xmlParseElement", "xmlParseVersionNum", "xmlParseVersionInfo",
77"xmlParseEncName", "xmlParseEncodingDecl", "xmlParseSDDecl",
78"xmlParseXMLDecl", "xmlParseTextDecl", "xmlParseMisc",
79"xmlParseExternalSubset", "xmlParserHandlePEReference",
80"xmlSkipBlankChars",
Daniel Veillarddd6d3002004-11-03 14:20:29 +000081]
Daniel Veillard36e5cd52004-11-02 14:52:23 +000082
83#
84# Those functions have side effect on the global state
85# and hence generate errors on memory allocation tests
86#
87skipped_memcheck = [ "xmlLoadCatalog", "xmlAddEncodingAlias",
88 "xmlSchemaInitTypes", "xmlNanoFTPProxy", "xmlNanoFTPScanProxy",
89 "xmlNanoHTTPScanProxy", "xmlResetLastError", "xmlCatalogConvert",
90 "xmlCatalogRemove", "xmlLoadCatalogs", "xmlCleanupCharEncodingHandlers",
Daniel Veillarda03e3652004-11-02 18:45:30 +000091 "xmlInitCharEncodingHandlers", "xmlCatalogCleanup",
Daniel Veillard42595322004-11-08 10:52:06 +000092 "xmlSchemaGetBuiltInType",
93 "htmlParseFile", # loads the catalogs
Daniel Veillarda03e3652004-11-02 18:45:30 +000094]
95
96#
97# Extra code needed for some test cases
98#
Daniel Veillard34099b42004-11-04 17:34:35 +000099extra_pre_call = {
100 "xmlSAXUserParseFile":
Daniel Veillardce244ad2004-11-05 10:03:46 +0000101 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
Daniel Veillard34099b42004-11-04 17:34:35 +0000102 "xmlSAXUserParseMemory":
Daniel Veillardce244ad2004-11-05 10:03:46 +0000103 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
Daniel Veillardce682bc2004-11-05 17:22:25 +0000104 "xmlParseBalancedChunkMemory":
105 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
106 "xmlParseBalancedChunkMemoryRecover":
107 "if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;",
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000108 "xmlParserInputBufferCreateFd":
109 "if (fd >= 0) fd = -1;",
Daniel Veillard34099b42004-11-04 17:34:35 +0000110}
Daniel Veillarda03e3652004-11-02 18:45:30 +0000111extra_post_call = {
112 "xmlAddChild":
113 "if (ret_val == NULL) { xmlFreeNode(cur) ; cur = NULL ; }",
114 "xmlAddChildList":
115 "if (ret_val == NULL) { xmlFreeNodeList(cur) ; cur = NULL ; }",
116 "xmlAddSibling":
117 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
118 "xmlAddNextSibling":
119 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
120 "xmlAddPrevSibling":
121 "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
122 "xmlDocSetRootElement":
123 "if (doc == NULL) { xmlFreeNode(root) ; root = NULL ; }",
124 "xmlReplaceNode":
Daniel Veillardce244ad2004-11-05 10:03:46 +0000125 """if (cur != NULL) {
126 xmlUnlinkNode(cur);
127 xmlFreeNode(cur) ; cur = NULL ; }
128 if (old != NULL) {
129 xmlUnlinkNode(old);
130 xmlFreeNode(old) ; old = NULL ; }
131 ret_val = NULL;""",
Daniel Veillarda03e3652004-11-02 18:45:30 +0000132 "xmlTextMerge":
133 """if ((first != NULL) && (first->type != XML_TEXT_NODE)) {
Daniel Veillardce244ad2004-11-05 10:03:46 +0000134 xmlUnlinkNode(second);
Daniel Veillarda03e3652004-11-02 18:45:30 +0000135 xmlFreeNode(second) ; second = NULL ; }""",
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000136 "xmlBuildQName":
137 """if ((ret_val != NULL) && (ret_val != ncname) &&
138 (ret_val != prefix) && (ret_val != memory))
139 xmlFree(ret_val);
140 ret_val = NULL;""",
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000141 "xmlDictReference": "xmlDictFree(dict);",
Daniel Veillard3d97e662004-11-04 10:49:00 +0000142 # Functions which deallocates one of their parameters
143 "xmlXPathConvertBoolean": """val = NULL;""",
144 "xmlXPathConvertNumber": """val = NULL;""",
145 "xmlXPathConvertString": """val = NULL;""",
146 "xmlSaveFileTo": """buf = NULL;""",
Daniel Veillard34099b42004-11-04 17:34:35 +0000147 "xmlSaveFormatFileTo": """buf = NULL;""",
148 "xmlIOParseDTD": "input = NULL;",
Daniel Veillardce244ad2004-11-05 10:03:46 +0000149 "xmlRemoveProp": "cur = NULL;",
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000150 "xmlNewNs": "if ((node == NULL) && (ret_val != NULL)) xmlFreeNs(ret_val);",
151 "xmlCopyNamespace": "if (ret_val != NULL) xmlFreeNs(ret_val);",
152 "xmlCopyNamespaceList": "if (ret_val != NULL) xmlFreeNsList(ret_val);",
153 "xmlNewTextWriter": "if (ret_val != NULL) out = NULL;",
154 "xmlNewTextWriterPushParser": "if (ret_val != NULL) ctxt = NULL;",
Daniel Veillard42595322004-11-08 10:52:06 +0000155 "xmlNewIOInputStream": "if (ret_val != NULL) input = NULL;",
Daniel Veillarda03e3652004-11-02 18:45:30 +0000156}
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000157
158modules = []
159
160def is_skipped_module(name):
161 for mod in skipped_modules:
162 if mod == name:
163 return 1
164 return 0
165
166def is_skipped_function(name):
167 for fun in skipped_functions:
168 if fun == name:
169 return 1
170 # Do not test destructors
171 if string.find(name, 'Free') != -1:
172 return 1
173 return 0
174
175def is_skipped_memcheck(name):
176 for fun in skipped_memcheck:
177 if fun == name:
178 return 1
179 return 0
180
181missing_types = {}
182def add_missing_type(name, func):
183 try:
184 list = missing_types[name]
185 list.append(func)
186 except:
187 missing_types[name] = [func]
188
Daniel Veillardce682bc2004-11-05 17:22:25 +0000189generated_param_types = []
190def add_generated_param_type(name):
191 generated_param_types.append(name)
192
193generated_return_types = []
194def add_generated_return_type(name):
195 generated_return_types.append(name)
196
Daniel Veillard34099b42004-11-04 17:34:35 +0000197missing_functions = {}
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000198missing_functions_nr = 0
Daniel Veillard34099b42004-11-04 17:34:35 +0000199def add_missing_functions(name, module):
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000200 global missing_functions_nr
201
202 missing_functions_nr = missing_functions_nr + 1
Daniel Veillard34099b42004-11-04 17:34:35 +0000203 try:
204 list = missing_functions[module]
205 list.append(name)
206 except:
207 missing_functions[module] = [name]
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000208
209#
210# Provide the type generators and destructors for the parameters
211#
212
Daniel Veillarda03e3652004-11-02 18:45:30 +0000213def type_convert(str, name, info, module, function, pos):
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000214# res = string.replace(str, " ", " ")
215# res = string.replace(str, " ", " ")
216# res = string.replace(str, " ", " ")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000217 res = string.replace(str, " *", "_ptr")
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000218# res = string.replace(str, "*", "_ptr")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000219 res = string.replace(res, " ", "_")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000220 res = string.replace(res, "htmlNode", "xmlNode")
221 res = string.replace(res, "htmlDoc", "xmlDoc")
222 res = string.replace(res, "htmlParser", "xmlParser")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000223 if res == 'const_char_ptr':
224 if string.find(name, "file") != -1 or \
225 string.find(name, "uri") != -1 or \
226 string.find(name, "URI") != -1 or \
227 string.find(info, "filename") != -1 or \
228 string.find(info, "URI") != -1 or \
229 string.find(info, "URL") != -1:
William M. Brack83d9c372004-11-08 02:26:08 +0000230 if string.find(function, "Save") != -1 or \
231 string.find(function, "Create") != -1 or \
232 string.find(function, "Write") != -1:
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000233 return('fileoutput')
234 return('filepath')
235 if res == 'void_ptr':
236 if module == 'nanoftp' and name == 'ctx':
237 return('xmlNanoFTPCtxtPtr')
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000238 if function == 'xmlNanoFTPNewCtxt':
239 return('xmlNanoFTPCtxtPtr')
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000240 if module == 'nanohttp' and name == 'ctx':
241 return('xmlNanoHTTPCtxtPtr')
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000242 if function == 'xmlIOHTTPOpenW':
243 return('xmlNanoHTTPCtxtPtr')
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000244 if string.find(name, "data") != -1:
245 return('userdata');
Daniel Veillardd005b9e2004-11-03 17:07:05 +0000246 if string.find(name, "user") != -1:
247 return('userdata');
Daniel Veillard3d97e662004-11-04 10:49:00 +0000248 if res == 'xmlDoc_ptr':
249 res = 'xmlDocPtr';
250 if res == 'xmlNode_ptr':
251 res = 'xmlNodePtr';
252 if res == 'xmlDict_ptr':
253 res = 'xmlDictPtr';
Daniel Veillarda03e3652004-11-02 18:45:30 +0000254 if res == 'xmlNodePtr' and pos != 0:
255 if (function == 'xmlAddChild' and pos == 2) or \
256 (function == 'xmlAddChildList' and pos == 2) or \
257 (function == 'xmlAddNextSibling' and pos == 2) or \
258 (function == 'xmlAddSibling' and pos == 2) or \
259 (function == 'xmlDocSetRootElement' and pos == 2) or \
260 (function == 'xmlReplaceNode' and pos == 2) or \
261 (function == 'xmlTextMerge') or \
262 (function == 'xmlAddPrevSibling' and pos == 2):
263 return('xmlNodePtr_in');
Daniel Veillard34099b42004-11-04 17:34:35 +0000264 if res == 'const xmlBufferPtr':
265 res = 'xmlBufferPtr';
Daniel Veillard27f20102004-11-05 11:50:11 +0000266 if res == 'xmlChar_ptr' and name == 'name' and \
267 string.find(function, "EatName") != -1:
268 return('eaten_name')
Daniel Veillardd5cc0f72004-11-06 19:24:28 +0000269 if res == 'void_ptr*':
270 res = 'void_ptr_ptr'
271 if res == 'char_ptr*':
272 res = 'char_ptr_ptr'
273 if res == 'xmlChar_ptr*':
274 res = 'xmlChar_ptr_ptr'
275 if res == 'const_xmlChar_ptr*':
276 res = 'const_xmlChar_ptr_ptr'
277 if res == 'const_char_ptr*':
278 res = 'const_char_ptr_ptr'
Daniel Veillarda82b1822004-11-08 16:24:57 +0000279 if res == 'FILE_ptr' and module == 'debugXML':
280 res = 'debug_FILE_ptr';
Daniel Veillard6128c012004-11-08 17:16:15 +0000281 if res == 'int' and name == 'options':
282 if module == 'parser' or module == 'xmlreader':
283 res = 'parseroptions'
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000284
285 return res
286
Daniel Veillard34099b42004-11-04 17:34:35 +0000287known_param_types = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000288
Daniel Veillardce682bc2004-11-05 17:22:25 +0000289def is_known_param_type(name, rtype):
290 global test
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000291 for type in known_param_types:
292 if type == name:
293 return 1
Daniel Veillardce682bc2004-11-05 17:22:25 +0000294 for type in generated_param_types:
295 if type == name:
296 return 1
297
298 if name[-3:] == 'Ptr' or name[-4:] == '_ptr':
299 if rtype[0:6] == 'const ':
300 crtype = rtype[6:]
301 else:
302 crtype = rtype
303
304 test.write("""
305#define gen_nb_%s 1
306static %s gen_%s(int no ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
307 return(NULL);
308}
309static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
310}
311""" % (name, crtype, name, name, rtype))
312 add_generated_param_type(name)
313 return 1
314
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000315 return 0
316
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000317#
318# Provide the type destructors for the return values
319#
320
Daniel Veillard34099b42004-11-04 17:34:35 +0000321known_return_types = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000322
323def is_known_return_type(name):
324 for type in known_return_types:
325 if type == name:
326 return 1
327 return 0
328
Daniel Veillard34099b42004-11-04 17:34:35 +0000329#
330# Copy the beginning of the C test program result
331#
332
333input = open("testapi.c", "r")
334test = open('testapi.c.new', 'w')
335
336def compare_and_save():
337 global test
338
339 test.close()
340 input = open("testapi.c", "r").read()
341 test = open('testapi.c.new', "r").read()
342 if input != test:
343 os.system("rm testapi.c ; mv testapi.c.new testapi.c")
344 print("Updated testapi.c")
345 else:
346 print("Generated testapi.c is identical")
347
348line = input.readline()
349while line != "":
350 if line == "/* CUT HERE: everything below that line is generated */\n":
351 break;
352 if line[0:15] == "#define gen_nb_":
353 type = string.split(line[15:])[0]
354 known_param_types.append(type)
355 if line[0:19] == "static void desret_":
356 type = string.split(line[19:], '(')[0]
357 known_return_types.append(type)
358 test.write(line)
359 line = input.readline()
360input.close()
361
362if line == "":
363 print "Could not find the CUT marker in testapi.c skipping generation"
364 test.close()
365 sys.exit(0)
366
367print("Scanned testapi.c: found %d parameters types and %d return types\n" % (
368 len(known_param_types), len(known_return_types)))
369test.write("/* CUT HERE: everything below that line is generated */\n")
370
371
372#
373# Open the input API description
374#
375doc = libxml2.readFile('doc/libxml2-api.xml', None, 0)
376if doc == None:
377 print "Failed to load doc/libxml2-api.xml"
378 sys.exit(1)
379ctxt = doc.xpathNewContext()
Daniel Veillard57b25162004-11-06 14:50:18 +0000380
381#
382# Generate constructors and return type handling for all enums
383#
384enums = ctxt.xpathEval("/api/symbols/typedef[@type='enum']")
385for enum in enums:
386 name = enum.xpathEval('string(@name)')
387 if name == None:
388 continue;
389
390 if is_known_param_type(name, name) == 0:
391 values = ctxt.xpathEval("/api/symbols/enum[@type='%s']" % name)
392 i = 0
393 vals = []
394 for value in values:
395 vname = value.xpathEval('string(@name)')
396 if vname == None:
397 continue;
398 i = i + 1
399 if i >= 5:
400 break;
401 vals.append(vname)
402 if vals == []:
403 print "Didn't found any value for enum %s" % (name)
404 continue
405 test.write("#define gen_nb_%s %d\n" % (name, len(vals)))
406 test.write("""static %s gen_%s(int no, int nr ATTRIBUTE_UNUSED) {\n""" %
407 (name, name))
408 i = 1
409 for value in vals:
410 test.write(" if (no == %d) return(%s);\n" % (i, value))
411 i = i + 1
412 test.write(""" return(0);
413}
414""");
415 known_param_types.append(name)
416
417 if is_known_return_type(name) == 0:
418 test.write("""static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
419}
420static void desret_%s(%s val ATTRIBUTE_UNUSED) {
421}
422
423""" % (name, name, name, name))
424 known_return_types.append(name)
Daniel Veillard34099b42004-11-04 17:34:35 +0000425
426#
427# Load the interfaces
428#
Daniel Veillard57b25162004-11-06 14:50:18 +0000429headers = ctxt.xpathEval("/api/files/file")
Daniel Veillard34099b42004-11-04 17:34:35 +0000430for file in headers:
431 name = file.xpathEval('string(@name)')
432 if (name == None) or (name == ''):
433 continue
434
435 #
436 # Some module may be skipped because they don't really consists
437 # of user callable APIs
438 #
439 if is_skipped_module(name):
440 continue
441
442 #
443 # do not test deprecated APIs
444 #
445 desc = file.xpathEval('string(description)')
446 if string.find(desc, 'DEPRECATED') != -1:
447 print "Skipping deprecated interface %s" % name
448 continue;
449
450 test.write("#include <libxml/%s.h>\n" % name)
451 modules.append(name)
452
453#
454# Generate the callers signatures
455#
456for module in modules:
457 test.write("static int test_%s(void);\n" % module);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000458
459#
460# Generate the top caller
461#
462
463test.write("""
464/**
465 * testlibxml2:
466 *
467 * Main entry point of the tester for the full libxml2 module,
468 * it calls all the tester entry point for each module.
469 *
470 * Returns the number of error found
471 */
472static int
473testlibxml2(void)
474{
Daniel Veillard42595322004-11-08 10:52:06 +0000475 int test_ret = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000476
477""")
478
479for module in modules:
Daniel Veillard42595322004-11-08 10:52:06 +0000480 test.write(" test_ret += test_%s();\n" % module)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000481
482test.write("""
Daniel Veillard3d97e662004-11-04 10:49:00 +0000483 printf("Total: %d functions, %d tests, %d errors\\n",
Daniel Veillard42595322004-11-08 10:52:06 +0000484 function_tests, call_tests, test_ret);
485 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000486}
487
488""")
489
490#
491# How to handle a function
492#
493nb_tests = 0
494
495def generate_test(module, node):
496 global test
497 global nb_tests
498 nb_cond = 0
499 no_gen = 0
500
501 name = node.xpathEval('string(@name)')
502 if is_skipped_function(name):
503 return
504
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000505 #
506 # check we know how to handle the args and return values
507 # and store the informations for the generation
508 #
509 try:
510 args = node.xpathEval("arg")
511 except:
512 args = []
513 t_args = []
Daniel Veillarda03e3652004-11-02 18:45:30 +0000514 n = 0
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000515 for arg in args:
Daniel Veillarda03e3652004-11-02 18:45:30 +0000516 n = n + 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000517 rtype = arg.xpathEval("string(@type)")
518 if rtype == 'void':
519 break;
520 info = arg.xpathEval("string(@info)")
521 nam = arg.xpathEval("string(@name)")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000522 type = type_convert(rtype, nam, info, module, name, n)
Daniel Veillardce682bc2004-11-05 17:22:25 +0000523 if is_known_param_type(type, rtype) == 0:
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000524 add_missing_type(type, name);
525 no_gen = 1
526 t_args.append((nam, type, rtype, info))
527
528 try:
529 rets = node.xpathEval("return")
530 except:
531 rets = []
532 t_ret = None
533 for ret in rets:
534 rtype = ret.xpathEval("string(@type)")
535 info = ret.xpathEval("string(@info)")
Daniel Veillarda03e3652004-11-02 18:45:30 +0000536 type = type_convert(rtype, 'return', info, module, name, 0)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000537 if rtype == 'void':
538 break
539 if is_known_return_type(type) == 0:
540 add_missing_type(type, name);
541 no_gen = 1
542 t_ret = (type, rtype, info)
543 break
544
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000545 test.write("""
546static int
547test_%s(void) {
Daniel Veillard42595322004-11-08 10:52:06 +0000548 int test_ret = 0;
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000549
550""" % (name))
551
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000552 if no_gen == 1:
Daniel Veillard34099b42004-11-04 17:34:35 +0000553 add_missing_functions(name, module)
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000554 test.write("""
555 /* missing type support */
Daniel Veillard42595322004-11-08 10:52:06 +0000556 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000557}
558
559""")
560 return
561
562 try:
563 conds = node.xpathEval("cond")
564 for cond in conds:
565 test.write("#ifdef %s\n" % (cond.get_content()))
566 nb_cond = nb_cond + 1
567 except:
568 pass
569
570 # Declare the memory usage counter
571 no_mem = is_skipped_memcheck(name)
572 if no_mem == 0:
573 test.write(" int mem_base;\n");
574
575 # Declare the return value
576 if t_ret != None:
577 test.write(" %s ret_val;\n" % (t_ret[1]))
578
579 # Declare the arguments
580 for arg in t_args:
581 (nam, type, rtype, info) = arg;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000582 if (type[-3:] == 'Ptr' or type[-4:] == '_ptr') and \
583 rtype[0:6] == 'const ':
584 crtype = rtype[6:]
585 else:
586 crtype = rtype
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000587 # add declaration
Daniel Veillardce682bc2004-11-05 17:22:25 +0000588 test.write(" %s %s; /* %s */\n" % (crtype, nam, info))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000589 test.write(" int n_%s;\n" % (nam))
590 test.write("\n")
591
592 # Cascade loop on of each argument list of values
593 for arg in t_args:
594 (nam, type, rtype, info) = arg;
595 #
596 test.write(" for (n_%s = 0;n_%s < gen_nb_%s;n_%s++) {\n" % (
597 nam, nam, type, nam))
598
599 # log the memory usage
600 if no_mem == 0:
601 test.write(" mem_base = xmlMemBlocks();\n");
602
603 # prepare the call
Daniel Veillard3d97e662004-11-04 10:49:00 +0000604 i = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000605 for arg in t_args:
606 (nam, type, rtype, info) = arg;
607 #
Daniel Veillard3d97e662004-11-04 10:49:00 +0000608 test.write(" %s = gen_%s(n_%s, %d);\n" % (nam, type, nam, i))
609 i = i + 1;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000610
611 # do the call, and clanup the result
Daniel Veillard34099b42004-11-04 17:34:35 +0000612 if extra_pre_call.has_key(name):
613 test.write(" %s\n"% (extra_pre_call[name]))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000614 if t_ret != None:
615 test.write("\n ret_val = %s(" % (name))
616 need = 0
617 for arg in t_args:
618 (nam, type, rtype, info) = arg
619 if need:
620 test.write(", ")
621 else:
622 need = 1
623 test.write("%s" % nam);
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000624 test.write(");\n")
625 if extra_post_call.has_key(name):
626 test.write(" %s\n"% (extra_post_call[name]))
627 test.write(" desret_%s(ret_val);\n" % t_ret[0])
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000628 else:
629 test.write("\n %s(" % (name));
630 need = 0;
631 for arg in t_args:
632 (nam, type, rtype, info) = arg;
633 if need:
634 test.write(", ")
635 else:
636 need = 1
637 test.write("%s" % nam)
638 test.write(");\n")
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000639 if extra_post_call.has_key(name):
640 test.write(" %s\n"% (extra_post_call[name]))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000641
Daniel Veillard8a32fe42004-11-02 22:10:16 +0000642 test.write(" call_tests++;\n");
Daniel Veillarda03e3652004-11-02 18:45:30 +0000643
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000644 # Free the arguments
Daniel Veillard3d97e662004-11-04 10:49:00 +0000645 i = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000646 for arg in t_args:
647 (nam, type, rtype, info) = arg;
648 #
Daniel Veillard3d97e662004-11-04 10:49:00 +0000649 test.write(" des_%s(n_%s, %s, %d);\n" % (type, nam, nam, i))
650 i = i + 1;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000651
652 test.write(" xmlResetLastError();\n");
653 # Check the memory usage
654 if no_mem == 0:
655 test.write(""" if (mem_base != xmlMemBlocks()) {
Daniel Veillarda03e3652004-11-02 18:45:30 +0000656 printf("Leak of %%d blocks found in %s",
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000657 xmlMemBlocks() - mem_base);
Daniel Veillard42595322004-11-08 10:52:06 +0000658 test_ret++;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000659""" % (name));
Daniel Veillarda03e3652004-11-02 18:45:30 +0000660 for arg in t_args:
661 (nam, type, rtype, info) = arg;
662 test.write(""" printf(" %%d", n_%s);\n""" % (nam))
663 test.write(""" printf("\\n");\n""")
664 test.write(" }\n")
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000665
666 for arg in t_args:
667 test.write(" }\n")
668
669 #
670 # end of conditional
671 #
672 while nb_cond > 0:
673 test.write("#endif\n")
674 nb_cond = nb_cond -1
675
676 nb_tests = nb_tests + 1;
677
678 test.write("""
Daniel Veillard3d97e662004-11-04 10:49:00 +0000679 function_tests++;
Daniel Veillard42595322004-11-08 10:52:06 +0000680 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000681}
682
683""")
684
685#
686# Generate all module callers
687#
688for module in modules:
689 # gather all the functions exported by that module
690 try:
691 functions = ctxt.xpathEval("/api/symbols/function[@file='%s']" % (module))
692 except:
693 print "Failed to gather functions from module %s" % (module)
694 continue;
695
696 # iterate over all functions in the module generating the test
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000697 i = 0
698 nb_tests_old = nb_tests
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000699 for function in functions:
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000700 i = i + 1
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000701 generate_test(module, function);
702
703 # header
704 test.write("""static int
705test_%s(void) {
Daniel Veillard42595322004-11-08 10:52:06 +0000706 int test_ret = 0;
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000707
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000708 printf("Testing %s : %d of %d functions ...\\n");
709""" % (module, module, nb_tests - nb_tests_old, i))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000710
711 # iterate over all functions in the module generating the call
712 for function in functions:
713 name = function.xpathEval('string(@name)')
714 if is_skipped_function(name):
715 continue
Daniel Veillard42595322004-11-08 10:52:06 +0000716 test.write(" test_ret += test_%s();\n" % (name))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000717
718 # footer
719 test.write("""
Daniel Veillard42595322004-11-08 10:52:06 +0000720 if (test_ret != 0)
721 printf("Module %s: %%d errors\\n", test_ret);
722 return(test_ret);
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000723}
724""" % (module))
725
Daniel Veillardce244ad2004-11-05 10:03:46 +0000726#
727# Generate direct module caller
728#
729test.write("""static int
730test_module(const char *module) {
731""");
732for module in modules:
733 test.write(""" if (!strcmp(module, "%s")) return(test_%s());\n""" % (
734 module, module))
735test.write(""" return(0);
736}
737""");
738
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000739print "Generated test for %d modules and %d functions" %(len(modules), nb_tests)
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000740
Daniel Veillard34099b42004-11-04 17:34:35 +0000741compare_and_save()
742
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000743missing_list = []
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000744for missing in missing_types.keys():
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000745 if missing == 'va_list' or missing == '...':
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000746 continue;
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000747
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000748 n = len(missing_types[missing])
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000749 missing_list.append((n, missing))
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000750
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000751def compare_missing(a, b):
752 return b[0] - a[0]
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000753
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000754missing_list.sort(compare_missing)
Daniel Veillard0ea9c9f2004-11-05 14:30:41 +0000755print "Missing support for %d functions and %d types see missing.lst" % (missing_functions_nr, len(missing_list))
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000756lst = open("missing.lst", "w")
Daniel Veillard34099b42004-11-04 17:34:35 +0000757lst.write("Missing support for %d types" % (len(missing_list)))
758lst.write("\n")
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000759for miss in missing_list:
760 lst.write("%s: %d :" % (miss[1], miss[0]))
761 i = 0
762 for n in missing_types[miss[1]]:
763 i = i + 1
764 if i > 5:
765 lst.write(" ...")
766 break
767 lst.write(" %s" % (n))
768 lst.write("\n")
Daniel Veillard34099b42004-11-04 17:34:35 +0000769lst.write("\n")
770lst.write("\n")
771lst.write("Missing support per module");
772for module in missing_functions.keys():
773 lst.write("module %s:\n %s\n" % (module, missing_functions[module]))
Daniel Veillard1ba06bb2004-11-04 12:32:18 +0000774
775lst.close()
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000776
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000777