1""" Tests for the linecache module """
2
3import linecache
4import unittest
5import os.path
6from test import test_support as support
7
8
9FILENAME = linecache.__file__
10INVALID_NAME = '!@$)(!@#_1'
11EMPTY = ''
12TESTS = 'inspect_fodder inspect_fodder2 mapping_tests'
13TESTS = TESTS.split()
14TEST_PATH = os.path.dirname(support.__file__)
15MODULES = "linecache abc".split()
16MODULE_PATH = os.path.dirname(FILENAME)
17
18SOURCE_1 = '''
19" Docstring "
20
21def function():
22    return result
23
24'''
25
26SOURCE_2 = '''
27def f():
28    return 1 + 1
29
30a = f()
31
32'''
33
34SOURCE_3 = '''
35def f():
36    return 3''' # No ending newline
37
38
39class LineCacheTests(unittest.TestCase):
40
41    def test_getline(self):
42        getline = linecache.getline
43
44        # Bad values for line number should return an empty string
45        self.assertEqual(getline(FILENAME, 2**15), EMPTY)
46        self.assertEqual(getline(FILENAME, -1), EMPTY)
47
48        # Float values currently raise TypeError, should it?
49        self.assertRaises(TypeError, getline, FILENAME, 1.1)
50
51        # Bad filenames should return an empty string
52        self.assertEqual(getline(EMPTY, 1), EMPTY)
53        self.assertEqual(getline(INVALID_NAME, 1), EMPTY)
54
55        # Check whether lines correspond to those from file iteration
56        for entry in TESTS:
57            filename = os.path.join(TEST_PATH, entry) + '.py'
58            for index, line in enumerate(open(filename)):
59                self.assertEqual(line, getline(filename, index + 1))
60
61        # Check module loading
62        for entry in MODULES:
63            filename = os.path.join(MODULE_PATH, entry) + '.py'
64            for index, line in enumerate(open(filename)):
65                self.assertEqual(line, getline(filename, index + 1))
66
67        # Check that bogus data isn't returned (issue #1309567)
68        empty = linecache.getlines('a/b/c/__init__.py')
69        self.assertEqual(empty, [])
70
71    def test_no_ending_newline(self):
72        self.addCleanup(support.unlink, support.TESTFN)
73        with open(support.TESTFN, "w") as fp:
74            fp.write(SOURCE_3)
75        lines = linecache.getlines(support.TESTFN)
76        self.assertEqual(lines, ["\n", "def f():\n", "    return 3\n"])
77
78    def test_clearcache(self):
79        cached = []
80        for entry in TESTS:
81            filename = os.path.join(TEST_PATH, entry) + '.py'
82            cached.append(filename)
83            linecache.getline(filename, 1)
84
85        # Are all files cached?
86        cached_empty = [fn for fn in cached if fn not in linecache.cache]
87        self.assertEqual(cached_empty, [])
88
89        # Can we clear the cache?
90        linecache.clearcache()
91        cached_empty = [fn for fn in cached if fn in linecache.cache]
92        self.assertEqual(cached_empty, [])
93
94    def test_checkcache(self):
95        getline = linecache.getline
96        # Create a source file and cache its contents
97        source_name = support.TESTFN + '.py'
98        self.addCleanup(support.unlink, source_name)
99        with open(source_name, 'w') as source:
100            source.write(SOURCE_1)
101        getline(source_name, 1)
102
103        # Keep a copy of the old contents
104        source_list = []
105        with open(source_name) as source:
106            for index, line in enumerate(source):
107                self.assertEqual(line, getline(source_name, index + 1))
108                source_list.append(line)
109
110        with open(source_name, 'w') as source:
111            source.write(SOURCE_2)
112
113        # Try to update a bogus cache entry
114        linecache.checkcache('dummy')
115
116        # Check that the cache matches the old contents
117        for index, line in enumerate(source_list):
118            self.assertEqual(line, getline(source_name, index + 1))
119
120        # Update the cache and check whether it matches the new source file
121        linecache.checkcache(source_name)
122        with open(source_name) as source:
123            for index, line in enumerate(source):
124                self.assertEqual(line, getline(source_name, index + 1))
125                source_list.append(line)
126
127    def test_memoryerror(self):
128        lines = linecache.getlines(FILENAME)
129        self.assertTrue(lines)
130        def raise_memoryerror(*args, **kwargs):
131            raise MemoryError
132        with support.swap_attr(linecache, 'updatecache', raise_memoryerror):
133            lines2 = linecache.getlines(FILENAME)
134        self.assertEqual(lines2, lines)
135
136        linecache.clearcache()
137        with support.swap_attr(linecache, 'updatecache', raise_memoryerror):
138            lines3 = linecache.getlines(FILENAME)
139        self.assertEqual(lines3, [])
140        self.assertEqual(linecache.getlines(FILENAME), lines)
141
142
143def test_main():
144    support.run_unittest(LineCacheTests)
145
146if __name__ == "__main__":
147    test_main()
148