File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / gentest.py
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:37:57 2012 UTC (12 years, 4 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_9_1p0, v2_9_1, v2_8_0p0, v2_8_0, v2_7_8, HEAD
libxml2

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>