1"""Unittest for idlelib.HyperParser"""
2import unittest
3from test.test_support import requires
4from Tkinter import Tk, Text
5from idlelib.EditorWindow import EditorWindow
6from idlelib.HyperParser import HyperParser
7
8class DummyEditwin:
9    def __init__(self, text):
10        self.text = text
11        self.indentwidth = 8
12        self.tabwidth = 8
13        self.context_use_ps1 = True
14        self.num_context_lines = 50, 500, 1000
15
16    _build_char_in_string_func = EditorWindow._build_char_in_string_func.im_func
17    is_char_in_string = EditorWindow.is_char_in_string.im_func
18
19
20class HyperParserTest(unittest.TestCase):
21    code = (
22            '"""This is a module docstring"""\n'
23            '# this line is a comment\n'
24            'x = "this is a string"\n'
25            "y = 'this is also a string'\n"
26            'l = [i for i in range(10)]\n'
27            'm = [py*py for # comment\n'
28            '       py in l]\n'
29            'x.__len__\n'
30            "z = ((r'asdf')+('a')))\n"
31            '[x for x in\n'
32            'for = False\n'
33            )
34
35    @classmethod
36    def setUpClass(cls):
37        requires('gui')
38        cls.root = Tk()
39        cls.root.withdraw()
40        cls.text = Text(cls.root)
41        cls.editwin = DummyEditwin(cls.text)
42
43    @classmethod
44    def tearDownClass(cls):
45        del cls.text, cls.editwin
46        cls.root.destroy()
47        del cls.root
48
49    def setUp(self):
50        self.text.insert('insert', self.code)
51
52    def tearDown(self):
53        self.text.delete('1.0', 'end')
54        self.editwin.context_use_ps1 = True
55
56    def get_parser(self, index):
57        """
58        Return a parser object with index at 'index'
59        """
60        return HyperParser(self.editwin, index)
61
62    def test_init(self):
63        """
64        test corner cases in the init method
65        """
66        with self.assertRaises(ValueError) as ve:
67            self.text.tag_add('console', '1.0', '1.end')
68            p = self.get_parser('1.5')
69        self.assertIn('precedes', str(ve.exception))
70
71        # test without ps1
72        self.editwin.context_use_ps1 = False
73
74        # number of lines lesser than 50
75        p = self.get_parser('end')
76        self.assertEqual(p.rawtext, self.text.get('1.0', 'end'))
77
78        # number of lines greater than 50
79        self.text.insert('end', self.text.get('1.0', 'end')*4)
80        p = self.get_parser('54.5')
81
82    def test_is_in_string(self):
83        get = self.get_parser
84
85        p = get('1.0')
86        self.assertFalse(p.is_in_string())
87        p = get('1.4')
88        self.assertTrue(p.is_in_string())
89        p = get('2.3')
90        self.assertFalse(p.is_in_string())
91        p = get('3.3')
92        self.assertFalse(p.is_in_string())
93        p = get('3.7')
94        self.assertTrue(p.is_in_string())
95        p = get('4.6')
96        self.assertTrue(p.is_in_string())
97
98    def test_is_in_code(self):
99        get = self.get_parser
100
101        p = get('1.0')
102        self.assertTrue(p.is_in_code())
103        p = get('1.1')
104        self.assertFalse(p.is_in_code())
105        p = get('2.5')
106        self.assertFalse(p.is_in_code())
107        p = get('3.4')
108        self.assertTrue(p.is_in_code())
109        p = get('3.6')
110        self.assertFalse(p.is_in_code())
111        p = get('4.14')
112        self.assertFalse(p.is_in_code())
113
114    def test_get_surrounding_bracket(self):
115        get = self.get_parser
116
117        def without_mustclose(parser):
118            # a utility function to get surrounding bracket
119            # with mustclose=False
120            return parser.get_surrounding_brackets(mustclose=False)
121
122        def with_mustclose(parser):
123            # a utility function to get surrounding bracket
124            # with mustclose=True
125            return parser.get_surrounding_brackets(mustclose=True)
126
127        p = get('3.2')
128        self.assertIsNone(with_mustclose(p))
129        self.assertIsNone(without_mustclose(p))
130
131        p = get('5.6')
132        self.assertTupleEqual(without_mustclose(p), ('5.4', '5.25'))
133        self.assertTupleEqual(without_mustclose(p), with_mustclose(p))
134
135        p = get('5.23')
136        self.assertTupleEqual(without_mustclose(p), ('5.21', '5.24'))
137        self.assertTupleEqual(without_mustclose(p), with_mustclose(p))
138
139        p = get('6.15')
140        self.assertTupleEqual(without_mustclose(p), ('6.4', '6.end'))
141        self.assertIsNone(with_mustclose(p))
142
143        p = get('9.end')
144        self.assertIsNone(with_mustclose(p))
145        self.assertIsNone(without_mustclose(p))
146
147    def test_get_expression(self):
148        get = self.get_parser
149
150        p = get('4.2')
151        self.assertEqual(p.get_expression(), 'y ')
152
153        p = get('4.7')
154        with self.assertRaises(ValueError) as ve:
155            p.get_expression()
156        self.assertIn('is inside a code', str(ve.exception))
157
158        p = get('5.25')
159        self.assertEqual(p.get_expression(), 'range(10)')
160
161        p = get('6.7')
162        self.assertEqual(p.get_expression(), 'py')
163
164        p = get('6.8')
165        self.assertEqual(p.get_expression(), '')
166
167        p = get('7.9')
168        self.assertEqual(p.get_expression(), 'py')
169
170        p = get('8.end')
171        self.assertEqual(p.get_expression(), 'x.__len__')
172
173        p = get('9.13')
174        self.assertEqual(p.get_expression(), "r'asdf'")
175
176        p = get('9.17')
177        with self.assertRaises(ValueError) as ve:
178            p.get_expression()
179        self.assertIn('is inside a code', str(ve.exception))
180
181        p = get('10.0')
182        self.assertEqual(p.get_expression(), '')
183
184        p = get('11.3')
185        self.assertEqual(p.get_expression(), '')
186
187        p = get('11.11')
188        self.assertEqual(p.get_expression(), 'False')
189
190
191if __name__ == '__main__':
192    unittest.main(verbosity=2)
193