Home | History | Annotate | Download | only in test
      1 """ Tests for the linecache module """
      2 
      3 import linecache
      4 import unittest
      5 import os.path
      6 import tempfile
      7 import tokenize
      8 from test import support
      9 
     10 
     11 FILENAME = linecache.__file__
     12 NONEXISTENT_FILENAME = FILENAME + '.missing'
     13 INVALID_NAME = '!@$)(!@#_1'
     14 EMPTY = ''
     15 TEST_PATH = os.path.dirname(__file__)
     16 MODULES = "linecache abc".split()
     17 MODULE_PATH = os.path.dirname(FILENAME)
     18 
     19 SOURCE_1 = '''
     20 " Docstring "
     21 
     22 def function():
     23     return result
     24 
     25 '''
     26 
     27 SOURCE_2 = '''
     28 def f():
     29     return 1 + 1
     30 
     31 a = f()
     32 
     33 '''
     34 
     35 SOURCE_3 = '''
     36 def f():
     37     return 3''' # No ending newline
     38 
     39 
     40 class TempFile:
     41 
     42     def setUp(self):
     43         super().setUp()
     44         with tempfile.NamedTemporaryFile(delete=False) as fp:
     45             self.file_name = fp.name
     46             fp.write(self.file_byte_string)
     47         self.addCleanup(support.unlink, self.file_name)
     48 
     49 
     50 class GetLineTestsGoodData(TempFile):
     51     # file_list   = ['list\n', 'of\n', 'good\n', 'strings\n']
     52 
     53     def setUp(self):
     54         self.file_byte_string = ''.join(self.file_list).encode('utf-8')
     55         super().setUp()
     56 
     57     def test_getline(self):
     58         with tokenize.open(self.file_name) as fp:
     59             for index, line in enumerate(fp):
     60                 if not line.endswith('\n'):
     61                     line += '\n'
     62 
     63                 cached_line = linecache.getline(self.file_name, index + 1)
     64                 self.assertEqual(line, cached_line)
     65 
     66     def test_getlines(self):
     67         lines = linecache.getlines(self.file_name)
     68         self.assertEqual(lines, self.file_list)
     69 
     70 
     71 class GetLineTestsBadData(TempFile):
     72     # file_byte_string = b'Bad data goes here'
     73 
     74     def test_getline(self):
     75         self.assertRaises((SyntaxError, UnicodeDecodeError),
     76                           linecache.getline, self.file_name, 1)
     77 
     78     def test_getlines(self):
     79         self.assertRaises((SyntaxError, UnicodeDecodeError),
     80                           linecache.getlines, self.file_name)
     81 
     82 
     83 class EmptyFile(GetLineTestsGoodData, unittest.TestCase):
     84     file_list = []
     85 
     86 
     87 class SingleEmptyLine(GetLineTestsGoodData, unittest.TestCase):
     88     file_list = ['\n']
     89 
     90 
     91 class GoodUnicode(GetLineTestsGoodData, unittest.TestCase):
     92     file_list = ['\n', 'b\n', 'abcdef\n', '\n']
     93 
     94 
     95 class BadUnicode(GetLineTestsBadData, unittest.TestCase):
     96     file_byte_string = b'\x80abc'
     97 
     98 
     99 class LineCacheTests(unittest.TestCase):
    100 
    101     def test_getline(self):
    102         getline = linecache.getline
    103 
    104         # Bad values for line number should return an empty string
    105         self.assertEqual(getline(FILENAME, 2**15), EMPTY)
    106         self.assertEqual(getline(FILENAME, -1), EMPTY)
    107 
    108         # Float values currently raise TypeError, should it?
    109         self.assertRaises(TypeError, getline, FILENAME, 1.1)
    110 
    111         # Bad filenames should return an empty string
    112         self.assertEqual(getline(EMPTY, 1), EMPTY)
    113         self.assertEqual(getline(INVALID_NAME, 1), EMPTY)
    114 
    115         # Check module loading
    116         for entry in MODULES:
    117             filename = os.path.join(MODULE_PATH, entry) + '.py'
    118             with open(filename) as file:
    119                 for index, line in enumerate(file):
    120                     self.assertEqual(line, getline(filename, index + 1))
    121 
    122         # Check that bogus data isn't returned (issue #1309567)
    123         empty = linecache.getlines('a/b/c/__init__.py')
    124         self.assertEqual(empty, [])
    125 
    126     def test_no_ending_newline(self):
    127         self.addCleanup(support.unlink, support.TESTFN)
    128         with open(support.TESTFN, "w") as fp:
    129             fp.write(SOURCE_3)
    130         lines = linecache.getlines(support.TESTFN)
    131         self.assertEqual(lines, ["\n", "def f():\n", "    return 3\n"])
    132 
    133     def test_clearcache(self):
    134         cached = []
    135         for entry in MODULES:
    136             filename = os.path.join(MODULE_PATH, entry) + '.py'
    137             cached.append(filename)
    138             linecache.getline(filename, 1)
    139 
    140         # Are all files cached?
    141         self.assertNotEqual(cached, [])
    142         cached_empty = [fn for fn in cached if fn not in linecache.cache]
    143         self.assertEqual(cached_empty, [])
    144 
    145         # Can we clear the cache?
    146         linecache.clearcache()
    147         cached_empty = [fn for fn in cached if fn in linecache.cache]
    148         self.assertEqual(cached_empty, [])
    149 
    150     def test_checkcache(self):
    151         getline = linecache.getline
    152         # Create a source file and cache its contents
    153         source_name = support.TESTFN + '.py'
    154         self.addCleanup(support.unlink, source_name)
    155         with open(source_name, 'w') as source:
    156             source.write(SOURCE_1)
    157         getline(source_name, 1)
    158 
    159         # Keep a copy of the old contents
    160         source_list = []
    161         with open(source_name) as source:
    162             for index, line in enumerate(source):
    163                 self.assertEqual(line, getline(source_name, index + 1))
    164                 source_list.append(line)
    165 
    166         with open(source_name, 'w') as source:
    167             source.write(SOURCE_2)
    168 
    169         # Try to update a bogus cache entry
    170         linecache.checkcache('dummy')
    171 
    172         # Check that the cache matches the old contents
    173         for index, line in enumerate(source_list):
    174             self.assertEqual(line, getline(source_name, index + 1))
    175 
    176         # Update the cache and check whether it matches the new source file
    177         linecache.checkcache(source_name)
    178         with open(source_name) as source:
    179             for index, line in enumerate(source):
    180                 self.assertEqual(line, getline(source_name, index + 1))
    181                 source_list.append(line)
    182 
    183     def test_lazycache_no_globals(self):
    184         lines = linecache.getlines(FILENAME)
    185         linecache.clearcache()
    186         self.assertEqual(False, linecache.lazycache(FILENAME, None))
    187         self.assertEqual(lines, linecache.getlines(FILENAME))
    188 
    189     def test_lazycache_smoke(self):
    190         lines = linecache.getlines(NONEXISTENT_FILENAME, globals())
    191         linecache.clearcache()
    192         self.assertEqual(
    193             True, linecache.lazycache(NONEXISTENT_FILENAME, globals()))
    194         self.assertEqual(1, len(linecache.cache[NONEXISTENT_FILENAME]))
    195         # Note here that we're looking up a nonexistent filename with no
    196         # globals: this would error if the lazy value wasn't resolved.
    197         self.assertEqual(lines, linecache.getlines(NONEXISTENT_FILENAME))
    198 
    199     def test_lazycache_provide_after_failed_lookup(self):
    200         linecache.clearcache()
    201         lines = linecache.getlines(NONEXISTENT_FILENAME, globals())
    202         linecache.clearcache()
    203         linecache.getlines(NONEXISTENT_FILENAME)
    204         linecache.lazycache(NONEXISTENT_FILENAME, globals())
    205         self.assertEqual(lines, linecache.updatecache(NONEXISTENT_FILENAME))
    206 
    207     def test_lazycache_check(self):
    208         linecache.clearcache()
    209         linecache.lazycache(NONEXISTENT_FILENAME, globals())
    210         linecache.checkcache()
    211 
    212     def test_lazycache_bad_filename(self):
    213         linecache.clearcache()
    214         self.assertEqual(False, linecache.lazycache('', globals()))
    215         self.assertEqual(False, linecache.lazycache('<foo>', globals()))
    216 
    217     def test_lazycache_already_cached(self):
    218         linecache.clearcache()
    219         lines = linecache.getlines(NONEXISTENT_FILENAME, globals())
    220         self.assertEqual(
    221             False,
    222             linecache.lazycache(NONEXISTENT_FILENAME, globals()))
    223         self.assertEqual(4, len(linecache.cache[NONEXISTENT_FILENAME]))
    224 
    225     def test_memoryerror(self):
    226         lines = linecache.getlines(FILENAME)
    227         self.assertTrue(lines)
    228         def raise_memoryerror(*args, **kwargs):
    229             raise MemoryError
    230         with support.swap_attr(linecache, 'updatecache', raise_memoryerror):
    231             lines2 = linecache.getlines(FILENAME)
    232         self.assertEqual(lines2, lines)
    233 
    234         linecache.clearcache()
    235         with support.swap_attr(linecache, 'updatecache', raise_memoryerror):
    236             lines3 = linecache.getlines(FILENAME)
    237         self.assertEqual(lines3, [])
    238         self.assertEqual(linecache.getlines(FILENAME), lines)
    239 
    240 
    241 if __name__ == "__main__":
    242     unittest.main()
    243