1""" Tests for the linecache module """ 2 3import linecache 4import unittest 5import os.path 6import tempfile 7import tokenize 8from test import support 9 10 11FILENAME = linecache.__file__ 12NONEXISTENT_FILENAME = FILENAME + '.missing' 13INVALID_NAME = '!@$)(!@#_1' 14EMPTY = '' 15TEST_PATH = os.path.dirname(__file__) 16MODULES = "linecache abc".split() 17MODULE_PATH = os.path.dirname(FILENAME) 18 19SOURCE_1 = ''' 20" Docstring " 21 22def function(): 23 return result 24 25''' 26 27SOURCE_2 = ''' 28def f(): 29 return 1 + 1 30 31a = f() 32 33''' 34 35SOURCE_3 = ''' 36def f(): 37 return 3''' # No ending newline 38 39 40class 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 50class 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 71class 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 83class EmptyFile(GetLineTestsGoodData, unittest.TestCase): 84 file_list = [] 85 86 87class SingleEmptyLine(GetLineTestsGoodData, unittest.TestCase): 88 file_list = ['\n'] 89 90 91class GoodUnicode(GetLineTestsGoodData, unittest.TestCase): 92 file_list = ['á\n', 'b\n', 'abcdef\n', 'ááááá\n'] 93 94 95class BadUnicode(GetLineTestsBadData, unittest.TestCase): 96 file_byte_string = b'\x80abc' 97 98 99class 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 241if __name__ == "__main__": 242 unittest.main() 243