1"""Test parenmatch, coverage 91%. 2 3This must currently be a gui test because ParenMatch methods use 4several text methods not defined on idlelib.idle_test.mock_tk.Text. 5""" 6from idlelib.parenmatch import ParenMatch 7from test.support import requires 8requires('gui') 9 10import unittest 11from unittest.mock import Mock 12from tkinter import Tk, Text 13 14 15class DummyEditwin: 16 def __init__(self, text): 17 self.text = text 18 self.indentwidth = 8 19 self.tabwidth = 8 20 self.context_use_ps1 = True 21 22 23class ParenMatchTest(unittest.TestCase): 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 These cases force conditional expression and alternate paths. 87 """ 88 text = self.text 89 pm = self.get_parenmatch() 90 91 text.insert('insert', '# this is a commen)') 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 111if __name__ == '__main__': 112 unittest.main(verbosity=2) 113