Annotation of embedaddon/libxml2/gentest.py, revision 1.1.1.1

1.1       misho       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>