1 """Test parenmatch, coverage 91%.
2
3 This must currently be a gui test because ParenMatch methods use
4 several text methods not defined on idlelib.idle_test.mock_tk.Text.
5 """
6 from idlelib.parenmatch import ParenMatch
7 from test.support import requires
8 requires('gui')
9
10 import unittest
11 from unittest.mock import Mock
12 from tkinter import Tk, Text
13
14
15 class ESC[4;38;5;81mDummyEditwin:
16 def __init__(self, text):
17 self.text = text
18 self.indentwidth = 8
19 self.tabwidth = 8
20 self.prompt_last_line = '>>>' # Currently not used by parenmatch.
21
22
23 class ESC[4;38;5;81mParenMatchTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
24
25 @classmethod
26 def setUpClass(cls):
27 cls.root = Tk()
28 cls.root.withdraw()
29 cls.text = Text(cls.root)
30 cls.editwin = DummyEditwin(cls.text)
31 cls.editwin.text_frame = Mock()
32
33 @classmethod
34 def tearDownClass(cls):
35 del cls.text, cls.editwin
36 cls.root.update_idletasks()
37 cls.root.destroy()
38 del cls.root
39
40 def tearDown(self):
41 self.text.delete('1.0', 'end')
42
43 def get_parenmatch(self):
44 pm = ParenMatch(self.editwin)
45 pm.bell = lambda: None
46 return pm
47
48 def test_paren_styles(self):
49 """
50 Test ParenMatch with each style.
51 """
52 text = self.text
53 pm = self.get_parenmatch()
54 for style, range1, range2 in (
55 ('opener', ('1.10', '1.11'), ('1.10', '1.11')),
56 ('default',('1.10', '1.11'),('1.10', '1.11')),
57 ('parens', ('1.14', '1.15'), ('1.15', '1.16')),
58 ('expression', ('1.10', '1.15'), ('1.10', '1.16'))):
59 with self.subTest(style=style):
60 text.delete('1.0', 'end')
61 pm.STYLE = style
62 text.insert('insert', 'def foobar(a, b')
63
64 pm.flash_paren_event('event')
65 self.assertIn('<<parenmatch-check-restore>>', text.event_info())
66 if style == 'parens':
67 self.assertTupleEqual(text.tag_nextrange('paren', '1.0'),
68 ('1.10', '1.11'))
69 self.assertTupleEqual(
70 text.tag_prevrange('paren', 'end'), range1)
71
72 text.insert('insert', ')')
73 pm.restore_event()
74 self.assertNotIn('<<parenmatch-check-restore>>',
75 text.event_info())
76 self.assertEqual(text.tag_prevrange('paren', 'end'), ())
77
78 pm.paren_closed_event('event')
79 self.assertTupleEqual(
80 text.tag_prevrange('paren', 'end'), range2)
81
82 def test_paren_corner(self):
83 """
84 Test corner cases in flash_paren_event and paren_closed_event.
85
86 Force execution of conditional expressions and alternate paths.
87 """
88 text = self.text
89 pm = self.get_parenmatch()
90
91 text.insert('insert', '# Comment.)')
92 pm.paren_closed_event('event')
93
94 text.insert('insert', '\ndef')
95 pm.flash_paren_event('event')
96 pm.paren_closed_event('event')
97
98 text.insert('insert', ' a, *arg)')
99 pm.paren_closed_event('event')
100
101 def test_handle_restore_timer(self):
102 pm = self.get_parenmatch()
103 pm.restore_event = Mock()
104 pm.handle_restore_timer(0)
105 self.assertTrue(pm.restore_event.called)
106 pm.restore_event.reset_mock()
107 pm.handle_restore_timer(1)
108 self.assertFalse(pm.restore_event.called)
109
110
111 if __name__ == '__main__':
112 unittest.main(verbosity=2)