(root)/
Python-3.12.0/
Lib/
test/
test_linecache.py
       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()