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