5
5
import os .path
6
6
import tempfile
7
7
import tokenize
8
+ from importlib .machinery import ModuleSpec
8
9
from test import support
9
10
from test .support import os_helper
11
+ from test .support .script_helper import assert_python_ok
10
12
11
13
12
14
FILENAME = linecache .__file__
@@ -82,6 +84,10 @@ def test_getlines(self):
82
84
class EmptyFile (GetLineTestsGoodData , unittest .TestCase ):
83
85
file_list = []
84
86
87
+ def test_getlines (self ):
88
+ lines = linecache .getlines (self .file_name )
89
+ self .assertEqual (lines , ['\n ' ])
90
+
85
91
86
92
class SingleEmptyLine (GetLineTestsGoodData , unittest .TestCase ):
87
93
file_list = ['\n ' ]
@@ -97,6 +103,16 @@ class BadUnicode_WithDeclaration(GetLineTestsBadData, unittest.TestCase):
97
103
file_byte_string = b'# coding=utf-8\n \x80 abc'
98
104
99
105
106
+ class FakeLoader :
107
+ def get_source (self , fullname ):
108
+ return f'source for { fullname } '
109
+
110
+
111
+ class NoSourceLoader :
112
+ def get_source (self , fullname ):
113
+ return None
114
+
115
+
100
116
class LineCacheTests (unittest .TestCase ):
101
117
102
118
def test_getline (self ):
@@ -238,6 +254,70 @@ def raise_memoryerror(*args, **kwargs):
238
254
self .assertEqual (lines3 , [])
239
255
self .assertEqual (linecache .getlines (FILENAME ), lines )
240
256
257
+ def test_loader (self ):
258
+ filename = 'scheme://path'
259
+
260
+ for loader in (None , object (), NoSourceLoader ()):
261
+ linecache .clearcache ()
262
+ module_globals = {'__name__' : 'a.b.c' , '__loader__' : loader }
263
+ self .assertEqual (linecache .getlines (filename , module_globals ), [])
264
+
265
+ linecache .clearcache ()
266
+ module_globals = {'__name__' : 'a.b.c' , '__loader__' : FakeLoader ()}
267
+ self .assertEqual (linecache .getlines (filename , module_globals ),
268
+ ['source for a.b.c\n ' ])
269
+
270
+ for spec in (None , object (), ModuleSpec ('' , FakeLoader ())):
271
+ linecache .clearcache ()
272
+ module_globals = {'__name__' : 'a.b.c' , '__loader__' : FakeLoader (),
273
+ '__spec__' : spec }
274
+ self .assertEqual (linecache .getlines (filename , module_globals ),
275
+ ['source for a.b.c\n ' ])
276
+
277
+ linecache .clearcache ()
278
+ spec = ModuleSpec ('x.y.z' , FakeLoader ())
279
+ module_globals = {'__name__' : 'a.b.c' , '__loader__' : spec .loader ,
280
+ '__spec__' : spec }
281
+ self .assertEqual (linecache .getlines (filename , module_globals ),
282
+ ['source for x.y.z\n ' ])
283
+
284
+ def test_invalid_names (self ):
285
+ for name , desc in [
286
+ ('\x00 ' , 'NUL bytes filename' ),
287
+ (__file__ + '\x00 ' , 'filename with embedded NUL bytes' ),
288
+ # A filename with surrogate codes. A UnicodeEncodeError is raised
289
+ # by os.stat() upon querying, which is a subclass of ValueError.
290
+ ("\uD834 \uDD1E .py" , 'surrogate codes (MUSICAL SYMBOL G CLEF)' ),
291
+ # For POSIX platforms, an OSError will be raised but for Windows
292
+ # platforms, a ValueError is raised due to the path_t converter.
293
+ # See: https://github.com/python/cpython/issues/122170
294
+ ('a' * 1_000_000 , 'very long filename' ),
295
+ ]:
296
+ with self .subTest (f'updatecache: { desc } ' ):
297
+ linecache .clearcache ()
298
+ lines = linecache .updatecache (name )
299
+ self .assertListEqual (lines , [])
300
+ self .assertNotIn (name , linecache .cache )
301
+
302
+ # hack into the cache (it shouldn't be allowed
303
+ # but we never know what people do...)
304
+ for key , fullname in [(name , 'ok' ), ('key' , name ), (name , name )]:
305
+ with self .subTest (f'checkcache: { desc } ' ,
306
+ key = key , fullname = fullname ):
307
+ linecache .clearcache ()
308
+ linecache .cache [key ] = (0 , 1234 , [], fullname )
309
+ linecache .checkcache (key )
310
+ self .assertNotIn (key , linecache .cache )
311
+
312
+ # just to be sure that we did not mess with cache
313
+ linecache .clearcache ()
314
+
315
+ def test_linecache_python_string (self ):
316
+ cmdline = "import linecache;assert len(linecache.cache) == 0"
317
+ retcode , stdout , stderr = assert_python_ok ('-c' , cmdline )
318
+ self .assertEqual (retcode , 0 )
319
+ self .assertEqual (stdout , b'' )
320
+ self .assertEqual (stderr , b'' )
241
321
242
322
class LineCacheInvalidationTests (unittest .TestCase ):
243
323
def setUp (self ):
0 commit comments