test_parenmatch.py 3.5 KB

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