gentest.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  1. #!/usr/bin/env python
  2. #
  3. # generate a tester program for the API
  4. #
  5. import sys
  6. import os
  7. import string
  8. try:
  9. import libxml2
  10. except:
  11. print("libxml2 python bindings not available, skipping testapi.c generation")
  12. sys.exit(0)
  13. if len(sys.argv) > 1:
  14. srcPref = sys.argv[1] + '/'
  15. else:
  16. srcPref = ''
  17. #
  18. # Modules we want to skip in API test
  19. #
  20. skipped_modules = [ "SAX", "xlink", "threads", "globals",
  21. "xmlmemory", "xmlversion", "xmlexports",
  22. ]
  23. #
  24. # defines for each module
  25. #
  26. modules_defines = {
  27. "HTMLparser": "LIBXML_HTML_ENABLED",
  28. "catalog": "LIBXML_CATALOG_ENABLED",
  29. "xmlreader": "LIBXML_READER_ENABLED",
  30. "relaxng": "LIBXML_SCHEMAS_ENABLED",
  31. "schemasInternals": "LIBXML_SCHEMAS_ENABLED",
  32. "xmlschemas": "LIBXML_SCHEMAS_ENABLED",
  33. "xmlschemastypes": "LIBXML_SCHEMAS_ENABLED",
  34. "xpath": "LIBXML_XPATH_ENABLED",
  35. "xpathInternals": "LIBXML_XPATH_ENABLED",
  36. "xinclude": "LIBXML_XINCLUDE_ENABLED",
  37. "xpointer": "LIBXML_XPTR_ENABLED",
  38. "xmlregexp" : "LIBXML_REGEXP_ENABLED",
  39. "xmlautomata" : "LIBXML_AUTOMATA_ENABLED",
  40. "xmlsave" : "LIBXML_OUTPUT_ENABLED",
  41. "xmlmodule" : "LIBXML_MODULES_ENABLED",
  42. "pattern" : "LIBXML_PATTERN_ENABLED",
  43. "schematron" : "LIBXML_SCHEMATRON_ENABLED",
  44. }
  45. #
  46. # defines for specific functions
  47. #
  48. function_defines = {
  49. "htmlDefaultSAXHandlerInit": "LIBXML_HTML_ENABLED",
  50. "xmlSAX2EndElement" : "LIBXML_SAX1_ENABLED",
  51. "xmlSAX2StartElement" : "LIBXML_SAX1_ENABLED",
  52. "xmlSAXDefaultVersion" : "LIBXML_SAX1_ENABLED",
  53. "UTF8Toisolat1" : "LIBXML_OUTPUT_ENABLED",
  54. "xmlIOParseDTD": "LIBXML_VALID_ENABLED",
  55. "xmlParseDTD": "LIBXML_VALID_ENABLED",
  56. "xmlParseDoc": "LIBXML_SAX1_ENABLED",
  57. "xmlParseMemory": "LIBXML_SAX1_ENABLED",
  58. "xmlRecoverDoc": "LIBXML_SAX1_ENABLED",
  59. "xmlParseFile": "LIBXML_SAX1_ENABLED",
  60. "xmlRecoverFile": "LIBXML_SAX1_ENABLED",
  61. "xmlRecoverMemory": "LIBXML_SAX1_ENABLED",
  62. "xmlSAXParseFileWithData": "LIBXML_SAX1_ENABLED",
  63. "xmlSAXParseMemory": "LIBXML_SAX1_ENABLED",
  64. "xmlSAXUserParseMemory": "LIBXML_SAX1_ENABLED",
  65. "xmlSAXParseDoc": "LIBXML_SAX1_ENABLED",
  66. "xmlSAXParseDTD": "LIBXML_SAX1_ENABLED",
  67. "xmlSAXUserParseFile": "LIBXML_SAX1_ENABLED",
  68. "xmlParseEntity": "LIBXML_SAX1_ENABLED",
  69. "xmlParseExternalEntity": "LIBXML_SAX1_ENABLED",
  70. "xmlSAXParseMemoryWithData": "LIBXML_SAX1_ENABLED",
  71. "xmlParseBalancedChunkMemory": "LIBXML_SAX1_ENABLED",
  72. "xmlParseBalancedChunkMemoryRecover": "LIBXML_SAX1_ENABLED",
  73. "xmlSetupParserForBuffer": "LIBXML_SAX1_ENABLED",
  74. "xmlStopParser": "LIBXML_PUSH_ENABLED",
  75. "xmlAttrSerializeTxtContent": "LIBXML_OUTPUT_ENABLED",
  76. "xmlSAXParseFile": "LIBXML_SAX1_ENABLED",
  77. "xmlSAXParseEntity": "LIBXML_SAX1_ENABLED",
  78. "xmlNewTextChild": "LIBXML_TREE_ENABLED",
  79. "xmlNewDocRawNode": "LIBXML_TREE_ENABLED",
  80. "xmlNewProp": "LIBXML_TREE_ENABLED",
  81. "xmlReconciliateNs": "LIBXML_TREE_ENABLED",
  82. "xmlValidateNCName": "LIBXML_TREE_ENABLED",
  83. "xmlValidateNMToken": "LIBXML_TREE_ENABLED",
  84. "xmlValidateName": "LIBXML_TREE_ENABLED",
  85. "xmlNewChild": "LIBXML_TREE_ENABLED",
  86. "xmlValidateQName": "LIBXML_TREE_ENABLED",
  87. "xmlSprintfElementContent": "LIBXML_OUTPUT_ENABLED",
  88. "xmlValidGetPotentialChildren" : "LIBXML_VALID_ENABLED",
  89. "xmlValidGetValidElements" : "LIBXML_VALID_ENABLED",
  90. "xmlTextReaderPreservePattern" : "LIBXML_PATTERN_ENABLED",
  91. }
  92. #
  93. # Some functions really need to be skipped for the tests.
  94. #
  95. skipped_functions = [
  96. # block on I/O
  97. "xmlFdRead", "xmlReadFd", "xmlCtxtReadFd",
  98. "htmlFdRead", "htmlReadFd", "htmlCtxtReadFd",
  99. "xmlReaderNewFd", "xmlReaderForFd",
  100. "xmlIORead", "xmlReadIO", "xmlCtxtReadIO",
  101. "htmlIORead", "htmlReadIO", "htmlCtxtReadIO",
  102. "xmlReaderNewIO", "xmlBufferDump", "xmlNanoFTPConnect",
  103. "xmlNanoFTPConnectTo", "xmlNanoHTTPMethod", "xmlNanoHTTPMethodRedir",
  104. # Complex I/O APIs
  105. "xmlCreateIOParserCtxt", "xmlParserInputBufferCreateIO",
  106. "xmlRegisterInputCallbacks", "xmlReaderForIO",
  107. "xmlOutputBufferCreateIO", "xmlRegisterOutputCallbacks",
  108. "xmlSaveToIO", "xmlIOHTTPOpenW",
  109. # library state cleanup, generate false leak information and other
  110. # troubles, heavillyb tested otherwise.
  111. "xmlCleanupParser", "xmlRelaxNGCleanupTypes", "xmlSetListDoc",
  112. "xmlSetTreeDoc", "xmlUnlinkNode",
  113. # hard to avoid leaks in the tests
  114. "xmlStrcat", "xmlStrncat", "xmlCatalogAddLocal", "xmlNewTextWriterDoc",
  115. "xmlXPathNewValueTree", "xmlXPathWrapString",
  116. # unimplemented
  117. "xmlTextReaderReadInnerXml", "xmlTextReaderReadOuterXml",
  118. "xmlTextReaderReadString",
  119. # destructor
  120. "xmlListDelete", "xmlOutputBufferClose", "xmlNanoFTPClose", "xmlNanoHTTPClose",
  121. # deprecated
  122. "xmlCatalogGetPublic", "xmlCatalogGetSystem", "xmlEncodeEntities",
  123. "xmlNewGlobalNs", "xmlHandleEntity", "xmlNamespaceParseNCName",
  124. "xmlNamespaceParseNSDef", "xmlNamespaceParseQName",
  125. "xmlParseNamespace", "xmlParseQuotedString", "xmlParserHandleReference",
  126. "xmlScanName",
  127. "xmlDecodeEntities",
  128. # allocators
  129. "xmlMemFree",
  130. # verbosity
  131. "xmlCatalogSetDebug", "xmlShellPrintXPathError", "xmlShellPrintNode",
  132. # Internal functions, no user space should really call them
  133. "xmlParseAttribute", "xmlParseAttributeListDecl", "xmlParseName",
  134. "xmlParseNmtoken", "xmlParseEntityValue", "xmlParseAttValue",
  135. "xmlParseSystemLiteral", "xmlParsePubidLiteral", "xmlParseCharData",
  136. "xmlParseExternalID", "xmlParseComment", "xmlParsePITarget", "xmlParsePI",
  137. "xmlParseNotationDecl", "xmlParseEntityDecl", "xmlParseDefaultDecl",
  138. "xmlParseNotationType", "xmlParseEnumerationType", "xmlParseEnumeratedType",
  139. "xmlParseAttributeType", "xmlParseAttributeListDecl",
  140. "xmlParseElementMixedContentDecl", "xmlParseElementChildrenContentDecl",
  141. "xmlParseElementContentDecl", "xmlParseElementDecl", "xmlParseMarkupDecl",
  142. "xmlParseCharRef", "xmlParseEntityRef", "xmlParseReference",
  143. "xmlParsePEReference", "xmlParseDocTypeDecl", "xmlParseAttribute",
  144. "xmlParseStartTag", "xmlParseEndTag", "xmlParseCDSect", "xmlParseContent",
  145. "xmlParseElement", "xmlParseVersionNum", "xmlParseVersionInfo",
  146. "xmlParseEncName", "xmlParseEncodingDecl", "xmlParseSDDecl",
  147. "xmlParseXMLDecl", "xmlParseTextDecl", "xmlParseMisc",
  148. "xmlParseExternalSubset", "xmlParserHandlePEReference",
  149. "xmlSkipBlankChars",
  150. # Legacy
  151. "xmlCleanupPredefinedEntities", "xmlInitializePredefinedEntities",
  152. "xmlSetFeature", "xmlGetFeature", "xmlGetFeaturesList",
  153. # location sets
  154. "xmlXPtrLocationSetAdd",
  155. "xmlXPtrLocationSetCreate",
  156. "xmlXPtrLocationSetDel",
  157. "xmlXPtrLocationSetMerge",
  158. "xmlXPtrLocationSetRemove",
  159. "xmlXPtrWrapLocationSet",
  160. ]
  161. #
  162. # These functions have side effects on the global state
  163. # and hence generate errors on memory allocation tests
  164. #
  165. skipped_memcheck = [ "xmlLoadCatalog", "xmlAddEncodingAlias",
  166. "xmlSchemaInitTypes", "xmlNanoFTPProxy", "xmlNanoFTPScanProxy",
  167. "xmlNanoHTTPScanProxy", "xmlResetLastError", "xmlCatalogConvert",
  168. "xmlCatalogRemove", "xmlLoadCatalogs", "xmlCleanupCharEncodingHandlers",
  169. "xmlInitCharEncodingHandlers", "xmlCatalogCleanup",
  170. "xmlSchemaGetBuiltInType",
  171. "htmlParseFile", "htmlCtxtReadFile", # loads the catalogs
  172. "xmlTextReaderSchemaValidate", "xmlSchemaCleanupTypes", # initialize the schemas type system
  173. "xmlCatalogResolve", "xmlIOParseDTD" # loads the catalogs
  174. ]
  175. #
  176. # Extra code needed for some test cases
  177. #
  178. extra_pre_call = {
  179. "xmlSAXUserParseFile": """
  180. #ifdef LIBXML_SAX1_ENABLED
  181. if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;
  182. #endif
  183. """,
  184. "xmlSAXUserParseMemory": """
  185. #ifdef LIBXML_SAX1_ENABLED
  186. if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;
  187. #endif
  188. """,
  189. "xmlParseBalancedChunkMemory": """
  190. #ifdef LIBXML_SAX1_ENABLED
  191. if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;
  192. #endif
  193. """,
  194. "xmlParseBalancedChunkMemoryRecover": """
  195. #ifdef LIBXML_SAX1_ENABLED
  196. if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL;
  197. #endif
  198. """,
  199. "xmlParserInputBufferCreateFd":
  200. "if (fd >= 0) fd = -1;",
  201. }
  202. extra_post_call = {
  203. "xmlAddChild":
  204. "if (ret_val == NULL) { xmlFreeNode(cur) ; cur = NULL ; }",
  205. "xmlAddEntity":
  206. "if (ret_val != NULL) { xmlFreeNode(ret_val) ; ret_val = NULL; }",
  207. "xmlAddChildList":
  208. "if (ret_val == NULL) { xmlFreeNodeList(cur) ; cur = NULL ; }",
  209. "xmlAddSibling":
  210. "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
  211. "xmlAddNextSibling":
  212. "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
  213. "xmlAddPrevSibling":
  214. "if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; }",
  215. "xmlDocSetRootElement":
  216. "if (doc == NULL) { xmlFreeNode(root) ; root = NULL ; }",
  217. "xmlReplaceNode":
  218. """if (cur != NULL) {
  219. xmlUnlinkNode(cur);
  220. xmlFreeNode(cur) ; cur = NULL ; }
  221. if (old != NULL) {
  222. xmlUnlinkNode(old);
  223. xmlFreeNode(old) ; old = NULL ; }
  224. \t ret_val = NULL;""",
  225. "xmlTextMerge":
  226. """if ((first != NULL) && (first->type != XML_TEXT_NODE)) {
  227. xmlUnlinkNode(second);
  228. xmlFreeNode(second) ; second = NULL ; }""",
  229. "xmlBuildQName":
  230. """if ((ret_val != NULL) && (ret_val != ncname) &&
  231. (ret_val != prefix) && (ret_val != memory))
  232. xmlFree(ret_val);
  233. \t ret_val = NULL;""",
  234. "xmlNewDocElementContent":
  235. """xmlFreeDocElementContent(doc, ret_val); ret_val = NULL;""",
  236. "xmlDictReference": "xmlDictFree(dict);",
  237. # Functions which deallocates one of their parameters
  238. "xmlXPathConvertBoolean": """val = NULL;""",
  239. "xmlXPathConvertNumber": """val = NULL;""",
  240. "xmlXPathConvertString": """val = NULL;""",
  241. "xmlSaveFileTo": """buf = NULL;""",
  242. "xmlSaveFormatFileTo": """buf = NULL;""",
  243. "xmlIOParseDTD": "input = NULL;",
  244. "xmlRemoveProp": "cur = NULL;",
  245. "xmlNewNs": "if ((node == NULL) && (ret_val != NULL)) xmlFreeNs(ret_val);",
  246. "xmlCopyNamespace": "if (ret_val != NULL) xmlFreeNs(ret_val);",
  247. "xmlCopyNamespaceList": "if (ret_val != NULL) xmlFreeNsList(ret_val);",
  248. "xmlNewTextWriter": "if (ret_val != NULL) out = NULL;",
  249. "xmlNewTextWriterPushParser": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;} if (ret_val != NULL) ctxt = NULL;",
  250. "xmlNewIOInputStream": "if (ret_val != NULL) input = NULL;",
  251. "htmlParseChunk": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}",
  252. "htmlParseDocument": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}",
  253. "xmlParseDocument": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}",
  254. "xmlParseChunk": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}",
  255. "xmlParseExtParsedEnt": "if (ctxt != NULL) {xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL;}",
  256. "xmlDOMWrapAdoptNode": "if ((node != NULL) && (node->parent == NULL)) {xmlUnlinkNode(node);xmlFreeNode(node);node = NULL;}",
  257. "xmlBufferSetAllocationScheme": "if ((buf != NULL) && (scheme == XML_BUFFER_ALLOC_IMMUTABLE) && (buf->content != NULL) && (buf->content != static_buf_content)) { xmlFree(buf->content); buf->content = NULL;}"
  258. }
  259. modules = []
  260. def is_skipped_module(name):
  261. for mod in skipped_modules:
  262. if mod == name:
  263. return 1
  264. return 0
  265. def is_skipped_function(name):
  266. for fun in skipped_functions:
  267. if fun == name:
  268. return 1
  269. # Do not test destructors
  270. if name.find('Free') != -1:
  271. return 1
  272. return 0
  273. def is_skipped_memcheck(name):
  274. for fun in skipped_memcheck:
  275. if fun == name:
  276. return 1
  277. return 0
  278. missing_types = {}
  279. def add_missing_type(name, func):
  280. try:
  281. list = missing_types[name]
  282. list.append(func)
  283. except:
  284. missing_types[name] = [func]
  285. generated_param_types = []
  286. def add_generated_param_type(name):
  287. generated_param_types.append(name)
  288. generated_return_types = []
  289. def add_generated_return_type(name):
  290. generated_return_types.append(name)
  291. missing_functions = {}
  292. missing_functions_nr = 0
  293. def add_missing_functions(name, module):
  294. global missing_functions_nr
  295. missing_functions_nr = missing_functions_nr + 1
  296. try:
  297. list = missing_functions[module]
  298. list.append(name)
  299. except:
  300. missing_functions[module] = [name]
  301. #
  302. # Provide the type generators and destructors for the parameters
  303. #
  304. def type_convert(str, name, info, module, function, pos):
  305. # res = str.replace(" ", " ")
  306. # res = str.replace(" ", " ")
  307. # res = str.replace(" ", " ")
  308. res = str.replace(" *", "_ptr")
  309. # res = str.replace("*", "_ptr")
  310. res = res.replace(" ", "_")
  311. if res == 'const_char_ptr':
  312. if name.find("file") != -1 or \
  313. name.find("uri") != -1 or \
  314. name.find("URI") != -1 or \
  315. info.find("filename") != -1 or \
  316. info.find("URI") != -1 or \
  317. info.find("URL") != -1:
  318. if function.find("Save") != -1 or \
  319. function.find("Create") != -1 or \
  320. function.find("Write") != -1 or \
  321. function.find("Fetch") != -1:
  322. return('fileoutput')
  323. return('filepath')
  324. if res == 'void_ptr':
  325. if module == 'nanoftp' and name == 'ctx':
  326. return('xmlNanoFTPCtxtPtr')
  327. if function == 'xmlNanoFTPNewCtxt' or \
  328. function == 'xmlNanoFTPConnectTo' or \
  329. function == 'xmlNanoFTPOpen':
  330. return('xmlNanoFTPCtxtPtr')
  331. if module == 'nanohttp' and name == 'ctx':
  332. return('xmlNanoHTTPCtxtPtr')
  333. if function == 'xmlNanoHTTPMethod' or \
  334. function == 'xmlNanoHTTPMethodRedir' or \
  335. function == 'xmlNanoHTTPOpen' or \
  336. function == 'xmlNanoHTTPOpenRedir':
  337. return('xmlNanoHTTPCtxtPtr');
  338. if function == 'xmlIOHTTPOpen':
  339. return('xmlNanoHTTPCtxtPtr')
  340. if name.find("data") != -1:
  341. return('userdata')
  342. if name.find("user") != -1:
  343. return('userdata')
  344. if res == 'xmlDoc_ptr':
  345. res = 'xmlDocPtr'
  346. if res == 'xmlNode_ptr':
  347. res = 'xmlNodePtr'
  348. if res == 'xmlDict_ptr':
  349. res = 'xmlDictPtr'
  350. if res == 'xmlNodePtr' and pos != 0:
  351. if (function == 'xmlAddChild' and pos == 2) or \
  352. (function == 'xmlAddChildList' and pos == 2) or \
  353. (function == 'xmlAddNextSibling' and pos == 2) or \
  354. (function == 'xmlAddSibling' and pos == 2) or \
  355. (function == 'xmlDocSetRootElement' and pos == 2) or \
  356. (function == 'xmlReplaceNode' and pos == 2) or \
  357. (function == 'xmlTextMerge') or \
  358. (function == 'xmlAddPrevSibling' and pos == 2):
  359. return('xmlNodePtr_in');
  360. if res == 'const xmlBufferPtr':
  361. res = 'xmlBufferPtr'
  362. if res == 'xmlChar_ptr' and name == 'name' and \
  363. function.find("EatName") != -1:
  364. return('eaten_name')
  365. if res == 'void_ptr*':
  366. res = 'void_ptr_ptr'
  367. if res == 'char_ptr*':
  368. res = 'char_ptr_ptr'
  369. if res == 'xmlChar_ptr*':
  370. res = 'xmlChar_ptr_ptr'
  371. if res == 'const_xmlChar_ptr*':
  372. res = 'const_xmlChar_ptr_ptr'
  373. if res == 'const_char_ptr*':
  374. res = 'const_char_ptr_ptr'
  375. if res == 'FILE_ptr' and module == 'debugXML':
  376. res = 'debug_FILE_ptr';
  377. if res == 'int' and name == 'options':
  378. if module == 'parser' or module == 'xmlreader':
  379. res = 'parseroptions'
  380. return res
  381. known_param_types = []
  382. def is_known_param_type(name):
  383. for type in known_param_types:
  384. if type == name:
  385. return 1
  386. return name[-3:] == 'Ptr' or name[-4:] == '_ptr'
  387. def generate_param_type(name, rtype):
  388. global test
  389. for type in known_param_types:
  390. if type == name:
  391. return
  392. for type in generated_param_types:
  393. if type == name:
  394. return
  395. if name[-3:] == 'Ptr' or name[-4:] == '_ptr':
  396. if rtype[0:6] == 'const ':
  397. crtype = rtype[6:]
  398. else:
  399. crtype = rtype
  400. define = 0
  401. if module in modules_defines:
  402. test.write("#ifdef %s\n" % (modules_defines[module]))
  403. define = 1
  404. test.write("""
  405. #define gen_nb_%s 1
  406. #define gen_%s(no, nr) NULL
  407. #define des_%s(no, val, nr)
  408. """ % (name, name, name))
  409. if define == 1:
  410. test.write("#endif\n\n")
  411. add_generated_param_type(name)
  412. #
  413. # Provide the type destructors for the return values
  414. #
  415. known_return_types = []
  416. def is_known_return_type(name):
  417. for type in known_return_types:
  418. if type == name:
  419. return 1
  420. return 0
  421. #
  422. # Copy the beginning of the C test program result
  423. #
  424. try:
  425. input = open("testapi.c", "r")
  426. except:
  427. input = open(srcPref + "testapi.c", "r")
  428. test = open('testapi.c.new', 'w')
  429. def compare_and_save():
  430. global test
  431. test.close()
  432. try:
  433. input = open("testapi.c", "r").read()
  434. except:
  435. input = ''
  436. test = open('testapi.c.new', "r").read()
  437. if input != test:
  438. try:
  439. os.system("rm testapi.c; mv testapi.c.new testapi.c")
  440. except:
  441. os.system("mv testapi.c.new testapi.c")
  442. print("Updated testapi.c")
  443. else:
  444. print("Generated testapi.c is identical")
  445. line = input.readline()
  446. while line != "":
  447. if line == "/* CUT HERE: everything below that line is generated */\n":
  448. break;
  449. if line[0:15] == "#define gen_nb_":
  450. type = line[15:].split()[0]
  451. known_param_types.append(type)
  452. if line[0:19] == "static void desret_":
  453. type = line[19:].split('(')[0]
  454. known_return_types.append(type)
  455. test.write(line)
  456. line = input.readline()
  457. input.close()
  458. if line == "":
  459. print("Could not find the CUT marker in testapi.c skipping generation")
  460. test.close()
  461. sys.exit(0)
  462. print("Scanned testapi.c: found %d parameters types and %d return types\n" % (
  463. len(known_param_types), len(known_return_types)))
  464. test.write("/* CUT HERE: everything below that line is generated */\n")
  465. #
  466. # Open the input API description
  467. #
  468. doc = libxml2.readFile(srcPref + 'doc/libxml2-api.xml', None, 0)
  469. if doc == None:
  470. print("Failed to load doc/libxml2-api.xml")
  471. sys.exit(1)
  472. ctxt = doc.xpathNewContext()
  473. #
  474. # Generate a list of all function parameters and select only
  475. # those used in the api tests
  476. #
  477. argtypes = {}
  478. args = ctxt.xpathEval("/api/symbols/function/arg")
  479. for arg in args:
  480. mod = arg.xpathEval('string(../@file)')
  481. func = arg.xpathEval('string(../@name)')
  482. if (mod not in skipped_modules) and (func not in skipped_functions):
  483. type = arg.xpathEval('string(@type)')
  484. if type not in argtypes:
  485. argtypes[type] = func
  486. # similarly for return types
  487. rettypes = {}
  488. rets = ctxt.xpathEval("/api/symbols/function/return")
  489. for ret in rets:
  490. mod = ret.xpathEval('string(../@file)')
  491. func = ret.xpathEval('string(../@name)')
  492. if (mod not in skipped_modules) and (func not in skipped_functions):
  493. type = ret.xpathEval('string(@type)')
  494. if type not in rettypes:
  495. rettypes[type] = func
  496. #
  497. # Generate constructors and return type handling for all enums
  498. # which are used as function parameters
  499. #
  500. enums = ctxt.xpathEval("/api/symbols/typedef[@type='enum']")
  501. for enum in enums:
  502. module = enum.xpathEval('string(@file)')
  503. name = enum.xpathEval('string(@name)')
  504. #
  505. # Skip any enums which are not in our filtered lists
  506. #
  507. if (name == None) or ((name not in argtypes) and (name not in rettypes)):
  508. continue;
  509. define = 0
  510. if (name in argtypes) and is_known_param_type(name) == 0:
  511. values = ctxt.xpathEval("/api/symbols/enum[@type='%s']" % name)
  512. i = 0
  513. vals = []
  514. for value in values:
  515. vname = value.xpathEval('string(@name)')
  516. if vname == None:
  517. continue;
  518. i = i + 1
  519. if i >= 5:
  520. break;
  521. vals.append(vname)
  522. if vals == []:
  523. print("Didn't find any value for enum %s" % (name))
  524. continue
  525. if module in modules_defines:
  526. test.write("#ifdef %s\n" % (modules_defines[module]))
  527. define = 1
  528. test.write("#define gen_nb_%s %d\n" % (name, len(vals)))
  529. test.write("""static %s gen_%s(int no, int nr ATTRIBUTE_UNUSED) {\n""" %
  530. (name, name))
  531. i = 1
  532. for value in vals:
  533. test.write(" if (no == %d) return(%s);\n" % (i, value))
  534. i = i + 1
  535. test.write(""" return(0);
  536. }
  537. static void des_%s(int no ATTRIBUTE_UNUSED, %s val ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) {
  538. }
  539. """ % (name, name));
  540. known_param_types.append(name)
  541. if (is_known_return_type(name) == 0) and (name in rettypes):
  542. if define == 0 and (module in modules_defines):
  543. test.write("#ifdef %s\n" % (modules_defines[module]))
  544. define = 1
  545. test.write("""static void desret_%s(%s val ATTRIBUTE_UNUSED) {
  546. }
  547. """ % (name, name))
  548. known_return_types.append(name)
  549. if define == 1:
  550. test.write("#endif\n\n")
  551. #
  552. # Load the interfaces
  553. #
  554. headers = ctxt.xpathEval("/api/files/file")
  555. for file in headers:
  556. name = file.xpathEval('string(@name)')
  557. if (name == None) or (name == ''):
  558. continue
  559. #
  560. # Some module may be skipped because they don't really consists
  561. # of user callable APIs
  562. #
  563. if is_skipped_module(name):
  564. continue
  565. #
  566. # do not test deprecated APIs
  567. #
  568. desc = file.xpathEval('string(description)')
  569. if desc.find('DEPRECATED') != -1:
  570. print("Skipping deprecated interface %s" % name)
  571. continue;
  572. test.write("#include <libxml/%s.h>\n" % name)
  573. modules.append(name)
  574. #
  575. # Generate the callers signatures
  576. #
  577. for module in modules:
  578. test.write("static int test_%s(void);\n" % module);
  579. #
  580. # Generate the top caller
  581. #
  582. test.write("""
  583. /**
  584. * testlibxml2:
  585. *
  586. * Main entry point of the tester for the full libxml2 module,
  587. * it calls all the tester entry point for each module.
  588. *
  589. * Returns the number of error found
  590. */
  591. static int
  592. testlibxml2(void)
  593. {
  594. int test_ret = 0;
  595. """)
  596. for module in modules:
  597. test.write(" test_ret += test_%s();\n" % module)
  598. test.write("""
  599. printf("Total: %d functions, %d tests, %d errors\\n",
  600. function_tests, call_tests, test_ret);
  601. return(test_ret);
  602. }
  603. """)
  604. #
  605. # How to handle a function
  606. #
  607. nb_tests = 0
  608. def generate_test(module, node):
  609. global test
  610. global nb_tests
  611. nb_cond = 0
  612. no_gen = 0
  613. name = node.xpathEval('string(@name)')
  614. if is_skipped_function(name):
  615. return
  616. #
  617. # check we know how to handle the args and return values
  618. # and store the information for the generation
  619. #
  620. try:
  621. args = node.xpathEval("arg")
  622. except:
  623. args = []
  624. t_args = []
  625. n = 0
  626. for arg in args:
  627. n = n + 1
  628. rtype = arg.xpathEval("string(@type)")
  629. if rtype == 'void':
  630. break;
  631. info = arg.xpathEval("string(@info)")
  632. nam = arg.xpathEval("string(@name)")
  633. type = type_convert(rtype, nam, info, module, name, n)
  634. if is_known_param_type(type) == 0:
  635. add_missing_type(type, name);
  636. no_gen = 1
  637. if (type[-3:] == 'Ptr' or type[-4:] == '_ptr') and \
  638. rtype[0:6] == 'const ':
  639. crtype = rtype[6:]
  640. else:
  641. crtype = rtype
  642. t_args.append((nam, type, rtype, crtype, info))
  643. try:
  644. rets = node.xpathEval("return")
  645. except:
  646. rets = []
  647. t_ret = None
  648. for ret in rets:
  649. rtype = ret.xpathEval("string(@type)")
  650. info = ret.xpathEval("string(@info)")
  651. type = type_convert(rtype, 'return', info, module, name, 0)
  652. if rtype == 'void':
  653. break
  654. if is_known_return_type(type) == 0:
  655. add_missing_type(type, name);
  656. no_gen = 1
  657. t_ret = (type, rtype, info)
  658. break
  659. if no_gen == 0:
  660. for t_arg in t_args:
  661. (nam, type, rtype, crtype, info) = t_arg
  662. generate_param_type(type, rtype)
  663. test.write("""
  664. static int
  665. test_%s(void) {
  666. int test_ret = 0;
  667. """ % (name))
  668. if no_gen == 1:
  669. add_missing_functions(name, module)
  670. test.write("""
  671. /* missing type support */
  672. return(test_ret);
  673. }
  674. """)
  675. return
  676. try:
  677. conds = node.xpathEval("cond")
  678. for cond in conds:
  679. test.write("#if %s\n" % (cond.get_content()))
  680. nb_cond = nb_cond + 1
  681. except:
  682. pass
  683. define = 0
  684. if name in function_defines:
  685. test.write("#ifdef %s\n" % (function_defines[name]))
  686. define = 1
  687. # Declare the memory usage counter
  688. no_mem = is_skipped_memcheck(name)
  689. if no_mem == 0:
  690. test.write(" int mem_base;\n");
  691. # Declare the return value
  692. if t_ret != None:
  693. test.write(" %s ret_val;\n" % (t_ret[1]))
  694. # Declare the arguments
  695. for arg in t_args:
  696. (nam, type, rtype, crtype, info) = arg;
  697. # add declaration
  698. test.write(" %s %s; /* %s */\n" % (crtype, nam, info))
  699. test.write(" int n_%s;\n" % (nam))
  700. test.write("\n")
  701. # Cascade loop on of each argument list of values
  702. for arg in t_args:
  703. (nam, type, rtype, crtype, info) = arg;
  704. #
  705. test.write(" for (n_%s = 0;n_%s < gen_nb_%s;n_%s++) {\n" % (
  706. nam, nam, type, nam))
  707. # log the memory usage
  708. if no_mem == 0:
  709. test.write(" mem_base = xmlMemBlocks();\n");
  710. # prepare the call
  711. i = 0;
  712. for arg in t_args:
  713. (nam, type, rtype, crtype, info) = arg;
  714. #
  715. test.write(" %s = gen_%s(n_%s, %d);\n" % (nam, type, nam, i))
  716. i = i + 1;
  717. # add checks to avoid out-of-bounds array access
  718. i = 0;
  719. for arg in t_args:
  720. (nam, type, rtype, crtype, info) = arg;
  721. # assume that "size", "len", and "start" parameters apply to either
  722. # the nearest preceding or following char pointer
  723. if type == "int" and (nam == "size" or nam == "len" or nam == "start"):
  724. for j in (*range(i - 1, -1, -1), *range(i + 1, len(t_args))):
  725. (bnam, btype) = t_args[j][:2]
  726. if btype == "const_char_ptr" or btype == "const_xmlChar_ptr":
  727. test.write(
  728. " if ((%s != NULL) &&\n"
  729. " (%s > (int) strlen((const char *) %s) + 1))\n"
  730. " continue;\n"
  731. % (bnam, nam, bnam))
  732. break
  733. i = i + 1;
  734. # do the call, and clanup the result
  735. if name in extra_pre_call:
  736. test.write(" %s\n"% (extra_pre_call[name]))
  737. if t_ret != None:
  738. test.write("\n ret_val = %s(" % (name))
  739. need = 0
  740. for arg in t_args:
  741. (nam, type, rtype, crtype, info) = arg
  742. if need:
  743. test.write(", ")
  744. else:
  745. need = 1
  746. if rtype != crtype:
  747. test.write("(%s)" % rtype)
  748. test.write("%s" % nam);
  749. test.write(");\n")
  750. if name in extra_post_call:
  751. test.write(" %s\n"% (extra_post_call[name]))
  752. test.write(" desret_%s(ret_val);\n" % t_ret[0])
  753. else:
  754. test.write("\n %s(" % (name));
  755. need = 0;
  756. for arg in t_args:
  757. (nam, type, rtype, crtype, info) = arg;
  758. if need:
  759. test.write(", ")
  760. else:
  761. need = 1
  762. if rtype != crtype:
  763. test.write("(%s)" % rtype)
  764. test.write("%s" % nam)
  765. test.write(");\n")
  766. if name in extra_post_call:
  767. test.write(" %s\n"% (extra_post_call[name]))
  768. test.write(" call_tests++;\n");
  769. # Free the arguments
  770. i = 0;
  771. for arg in t_args:
  772. (nam, type, rtype, crtype, info) = arg;
  773. # This is a hack to prevent generating a destructor for the
  774. # 'input' argument in xmlTextReaderSetup. There should be
  775. # a better, more generic way to do this!
  776. if info.find('destroy') == -1:
  777. test.write(" des_%s(n_%s, " % (type, nam))
  778. if rtype != crtype:
  779. test.write("(%s)" % rtype)
  780. test.write("%s, %d);\n" % (nam, i))
  781. i = i + 1;
  782. test.write(" xmlResetLastError();\n");
  783. # Check the memory usage
  784. if no_mem == 0:
  785. test.write(""" if (mem_base != xmlMemBlocks()) {
  786. printf("Leak of %%d blocks found in %s",
  787. \t xmlMemBlocks() - mem_base);
  788. \t test_ret++;
  789. """ % (name));
  790. for arg in t_args:
  791. (nam, type, rtype, crtype, info) = arg;
  792. test.write(""" printf(" %%d", n_%s);\n""" % (nam))
  793. test.write(""" printf("\\n");\n""")
  794. test.write(" }\n")
  795. for arg in t_args:
  796. test.write(" }\n")
  797. test.write(" function_tests++;\n")
  798. #
  799. # end of conditional
  800. #
  801. while nb_cond > 0:
  802. test.write("#endif\n")
  803. nb_cond = nb_cond -1
  804. if define == 1:
  805. test.write("#endif\n")
  806. nb_tests = nb_tests + 1;
  807. test.write("""
  808. return(test_ret);
  809. }
  810. """)
  811. #
  812. # Generate all module callers
  813. #
  814. for module in modules:
  815. # gather all the functions exported by that module
  816. try:
  817. functions = ctxt.xpathEval("/api/symbols/function[@file='%s']" % (module))
  818. except:
  819. print("Failed to gather functions from module %s" % (module))
  820. continue;
  821. # iterate over all functions in the module generating the test
  822. i = 0
  823. nb_tests_old = nb_tests
  824. for function in functions:
  825. i = i + 1
  826. generate_test(module, function);
  827. # header
  828. test.write("""static int
  829. test_%s(void) {
  830. int test_ret = 0;
  831. if (quiet == 0) printf("Testing %s : %d of %d functions ...\\n");
  832. """ % (module, module, nb_tests - nb_tests_old, i))
  833. # iterate over all functions in the module generating the call
  834. for function in functions:
  835. name = function.xpathEval('string(@name)')
  836. if is_skipped_function(name):
  837. continue
  838. test.write(" test_ret += test_%s();\n" % (name))
  839. # footer
  840. test.write("""
  841. if (test_ret != 0)
  842. \tprintf("Module %s: %%d errors\\n", test_ret);
  843. return(test_ret);
  844. }
  845. """ % (module))
  846. #
  847. # Generate direct module caller
  848. #
  849. test.write("""static int
  850. test_module(const char *module) {
  851. """);
  852. for module in modules:
  853. test.write(""" if (!strcmp(module, "%s")) return(test_%s());\n""" % (
  854. module, module))
  855. test.write(""" return(0);
  856. }
  857. """);
  858. print("Generated test for %d modules and %d functions" %(len(modules), nb_tests))
  859. compare_and_save()
  860. missing_list = []
  861. for missing in missing_types.keys():
  862. if missing == 'va_list' or missing == '...':
  863. continue;
  864. n = len(missing_types[missing])
  865. missing_list.append((n, missing))
  866. missing_list.sort(key=lambda a: a[0])
  867. print("Missing support for %d functions and %d types see missing.lst" % (missing_functions_nr, len(missing_list)))
  868. lst = open("missing.lst", "w")
  869. lst.write("Missing support for %d types" % (len(missing_list)))
  870. lst.write("\n")
  871. for miss in missing_list:
  872. lst.write("%s: %d :" % (miss[1], miss[0]))
  873. i = 0
  874. for n in missing_types[miss[1]]:
  875. i = i + 1
  876. if i > 5:
  877. lst.write(" ...")
  878. break
  879. lst.write(" %s" % (n))
  880. lst.write("\n")
  881. lst.write("\n")
  882. lst.write("\n")
  883. lst.write("Missing support per module");
  884. for module in missing_functions.keys():
  885. lst.write("module %s:\n %s\n" % (module, missing_functions[module]))
  886. lst.close()