Home | History | Annotate | Download | only in test
      1 '''
      2    Test cases for pyclbr.py
      3    Nick Mathewson
      4 '''
      5 from test.test_support import run_unittest, import_module
      6 import sys
      7 from types import ClassType, FunctionType, MethodType, BuiltinFunctionType
      8 import pyclbr
      9 from unittest import TestCase
     10 
     11 StaticMethodType = type(staticmethod(lambda: None))
     12 ClassMethodType = type(classmethod(lambda c: None))
     13 
     14 # Silence Py3k warning
     15 import_module('commands', deprecated=True)
     16 
     17 # This next line triggers an error on old versions of pyclbr.
     18 from commands import getstatus
     19 
     20 # Here we test the python class browser code.
     21 #
     22 # The main function in this suite, 'testModule', compares the output
     23 # of pyclbr with the introspected members of a module.  Because pyclbr
     24 # is imperfect (as designed), testModule is called with a set of
     25 # members to ignore.
     26 
     27 class PyclbrTest(TestCase):
     28 
     29     def assertListEq(self, l1, l2, ignore):
     30         ''' succeed iff {l1} - {ignore} == {l2} - {ignore} '''
     31         missing = (set(l1) ^ set(l2)) - set(ignore)
     32         if missing:
     33             print >>sys.stderr, "l1=%r\nl2=%r\nignore=%r" % (l1, l2, ignore)
     34             self.fail("%r missing" % missing.pop())
     35 
     36     def assertHasattr(self, obj, attr, ignore):
     37         ''' succeed iff hasattr(obj,attr) or attr in ignore. '''
     38         if attr in ignore: return
     39         if not hasattr(obj, attr): print "???", attr
     40         self.assertTrue(hasattr(obj, attr),
     41                         'expected hasattr(%r, %r)' % (obj, attr))
     42 
     43 
     44     def assertHaskey(self, obj, key, ignore):
     45         ''' succeed iff key in obj or key in ignore. '''
     46         if key in ignore: return
     47         if key not in obj:
     48             print >>sys.stderr, "***", key
     49         self.assertIn(key, obj)
     50 
     51     def assertEqualsOrIgnored(self, a, b, ignore):
     52         ''' succeed iff a == b or a in ignore or b in ignore '''
     53         if a not in ignore and b not in ignore:
     54             self.assertEqual(a, b)
     55 
     56     def checkModule(self, moduleName, module=None, ignore=()):
     57         ''' succeed iff pyclbr.readmodule_ex(modulename) corresponds
     58             to the actual module object, module.  Any identifiers in
     59             ignore are ignored.   If no module is provided, the appropriate
     60             module is loaded with __import__.'''
     61 
     62         if module is None:
     63             # Import it.
     64             # ('<silly>' is to work around an API silliness in __import__)
     65             module = __import__(moduleName, globals(), {}, ['<silly>'])
     66 
     67         dict = pyclbr.readmodule_ex(moduleName)
     68 
     69         def ismethod(oclass, obj, name):
     70             classdict = oclass.__dict__
     71             if isinstance(obj, FunctionType):
     72                 if not isinstance(classdict[name], StaticMethodType):
     73                     return False
     74             else:
     75                 if not  isinstance(obj, MethodType):
     76                     return False
     77                 if obj.im_self is not None:
     78                     if (not isinstance(classdict[name], ClassMethodType) or
     79                         obj.im_self is not oclass):
     80                         return False
     81                 else:
     82                     if not isinstance(classdict[name], FunctionType):
     83                         return False
     84 
     85             objname = obj.__name__
     86             if objname.startswith("__") and not objname.endswith("__"):
     87                 objname = "_%s%s" % (obj.im_class.__name__, objname)
     88             return objname == name
     89 
     90         # Make sure the toplevel functions and classes are the same.
     91         for name, value in dict.items():
     92             if name in ignore:
     93                 continue
     94             self.assertHasattr(module, name, ignore)
     95             py_item = getattr(module, name)
     96             if isinstance(value, pyclbr.Function):
     97                 self.assertIsInstance(py_item, (FunctionType, BuiltinFunctionType))
     98                 if py_item.__module__ != moduleName:
     99                     continue   # skip functions that came from somewhere else
    100                 self.assertEqual(py_item.__module__, value.module)
    101             else:
    102                 self.assertIsInstance(py_item, (ClassType, type))
    103                 if py_item.__module__ != moduleName:
    104                     continue   # skip classes that came from somewhere else
    105 
    106                 real_bases = [base.__name__ for base in py_item.__bases__]
    107                 pyclbr_bases = [ getattr(base, 'name', base)
    108                                  for base in value.super ]
    109 
    110                 try:
    111                     self.assertListEq(real_bases, pyclbr_bases, ignore)
    112                 except:
    113                     print >>sys.stderr, "class=%s" % py_item
    114                     raise
    115 
    116                 actualMethods = []
    117                 for m in py_item.__dict__.keys():
    118                     if ismethod(py_item, getattr(py_item, m), m):
    119                         actualMethods.append(m)
    120                 foundMethods = []
    121                 for m in value.methods.keys():
    122                     if m[:2] == '__' and m[-2:] != '__':
    123                         foundMethods.append('_'+name+m)
    124                     else:
    125                         foundMethods.append(m)
    126 
    127                 try:
    128                     self.assertListEq(foundMethods, actualMethods, ignore)
    129                     self.assertEqual(py_item.__module__, value.module)
    130 
    131                     self.assertEqualsOrIgnored(py_item.__name__, value.name,
    132                                                ignore)
    133                     # can't check file or lineno
    134                 except:
    135                     print >>sys.stderr, "class=%s" % py_item
    136                     raise
    137 
    138         # Now check for missing stuff.
    139         def defined_in(item, module):
    140             if isinstance(item, ClassType):
    141                 return item.__module__ == module.__name__
    142             if isinstance(item, FunctionType):
    143                 return item.func_globals is module.__dict__
    144             return False
    145         for name in dir(module):
    146             item = getattr(module, name)
    147             if isinstance(item,  (ClassType, FunctionType)):
    148                 if defined_in(item, module):
    149                     self.assertHaskey(dict, name, ignore)
    150 
    151     def test_easy(self):
    152         self.checkModule('pyclbr')
    153         self.checkModule('doctest', ignore=("DocTestCase",))
    154         # Silence Py3k warning
    155         rfc822 = import_module('rfc822', deprecated=True)
    156         self.checkModule('rfc822', rfc822)
    157         self.checkModule('difflib')
    158 
    159     def test_decorators(self):
    160         # XXX: See comment in pyclbr_input.py for a test that would fail
    161         #      if it were not commented out.
    162         #
    163         self.checkModule('test.pyclbr_input')
    164 
    165     def test_others(self):
    166         cm = self.checkModule
    167 
    168         # These were once about the 10 longest modules
    169         cm('random', ignore=('Random',))  # from _random import Random as CoreGenerator
    170         cm('cgi', ignore=('log',))      # set with = in module
    171         cm('urllib', ignore=('_CFNumberToInt32',
    172                              '_CStringFromCFString',
    173                              '_CFSetup',
    174                              'getproxies_registry',
    175                              'proxy_bypass_registry',
    176                              'proxy_bypass_macosx_sysconf',
    177                              'open_https',
    178                              'getproxies_macosx_sysconf',
    179                              'getproxies_internetconfig',)) # not on all platforms
    180         cm('pickle')
    181         cm('aifc', ignore=('openfp',))  # set with = in module
    182         cm('Cookie')
    183         cm('sre_parse', ignore=('dump', 'groups')) # from sre_constants import *; property
    184         cm('pdb')
    185         cm('pydoc')
    186 
    187         # Tests for modules inside packages
    188         cm('email.parser')
    189         cm('test.test_pyclbr')
    190 
    191     def test_issue_14798(self):
    192         # test ImportError is raised when the first part of a dotted name is
    193         # not a package
    194         self.assertRaises(ImportError, pyclbr.readmodule_ex, 'asyncore.foo')
    195 
    196 
    197 def test_main():
    198     run_unittest(PyclbrTest)
    199 
    200 
    201 if __name__ == "__main__":
    202     test_main()
    203