1"Test undo, coverage 77%."
2# Only test UndoDelegator so far.
3
4from idlelib.undo import UndoDelegator
5import unittest
6from test.support import requires
7requires('gui')
8
9from unittest.mock import Mock
10from tkinter import Text, Tk
11from idlelib.percolator import Percolator
12
13
14class UndoDelegatorTest(unittest.TestCase):
15
16    @classmethod
17    def setUpClass(cls):
18        cls.root = Tk()
19        cls.text = Text(cls.root)
20        cls.percolator = Percolator(cls.text)
21
22    @classmethod
23    def tearDownClass(cls):
24        cls.percolator.redir.close()
25        del cls.percolator, cls.text
26        cls.root.destroy()
27        del cls.root
28
29    def setUp(self):
30        self.delegator = UndoDelegator()
31        self.delegator.bell = Mock()
32        self.percolator.insertfilter(self.delegator)
33
34    def tearDown(self):
35        self.percolator.removefilter(self.delegator)
36        self.text.delete('1.0', 'end')
37        self.delegator.resetcache()
38
39    def test_undo_event(self):
40        text = self.text
41
42        text.insert('insert', 'foobar')
43        text.insert('insert', 'h')
44        text.event_generate('<<undo>>')
45        self.assertEqual(text.get('1.0', 'end'), '\n')
46
47        text.insert('insert', 'foo')
48        text.insert('insert', 'bar')
49        text.delete('1.2', '1.4')
50        text.insert('insert', 'hello')
51        text.event_generate('<<undo>>')
52        self.assertEqual(text.get('1.0', '1.4'), 'foar')
53        text.event_generate('<<undo>>')
54        self.assertEqual(text.get('1.0', '1.6'), 'foobar')
55        text.event_generate('<<undo>>')
56        self.assertEqual(text.get('1.0', '1.3'), 'foo')
57        text.event_generate('<<undo>>')
58        self.delegator.undo_event('event')
59        self.assertTrue(self.delegator.bell.called)
60
61    def test_redo_event(self):
62        text = self.text
63
64        text.insert('insert', 'foo')
65        text.insert('insert', 'bar')
66        text.delete('1.0', '1.3')
67        text.event_generate('<<undo>>')
68        text.event_generate('<<redo>>')
69        self.assertEqual(text.get('1.0', '1.3'), 'bar')
70        text.event_generate('<<redo>>')
71        self.assertTrue(self.delegator.bell.called)
72
73    def test_dump_event(self):
74        """
75        Dump_event cannot be tested directly without changing
76        environment variables. So, test statements in dump_event
77        indirectly
78        """
79        text = self.text
80        d = self.delegator
81
82        text.insert('insert', 'foo')
83        text.insert('insert', 'bar')
84        text.delete('1.2', '1.4')
85        self.assertTupleEqual((d.pointer, d.can_merge), (3, True))
86        text.event_generate('<<undo>>')
87        self.assertTupleEqual((d.pointer, d.can_merge), (2, False))
88
89    def test_get_set_saved(self):
90        # test the getter method get_saved
91        # test the setter method set_saved
92        # indirectly test check_saved
93        d = self.delegator
94
95        self.assertTrue(d.get_saved())
96        self.text.insert('insert', 'a')
97        self.assertFalse(d.get_saved())
98        d.saved_change_hook = Mock()
99
100        d.set_saved(True)
101        self.assertEqual(d.pointer, d.saved)
102        self.assertTrue(d.saved_change_hook.called)
103
104        d.set_saved(False)
105        self.assertEqual(d.saved, -1)
106        self.assertTrue(d.saved_change_hook.called)
107
108    def test_undo_start_stop(self):
109        # test the undo_block_start and undo_block_stop methods
110        text = self.text
111
112        text.insert('insert', 'foo')
113        self.delegator.undo_block_start()
114        text.insert('insert', 'bar')
115        text.insert('insert', 'bar')
116        self.delegator.undo_block_stop()
117        self.assertEqual(text.get('1.0', '1.3'), 'foo')
118
119        # test another code path
120        self.delegator.undo_block_start()
121        text.insert('insert', 'bar')
122        self.delegator.undo_block_stop()
123        self.assertEqual(text.get('1.0', '1.3'), 'foo')
124
125    def test_addcmd(self):
126        text = self.text
127        # when number of undo operations exceeds max_undo
128        self.delegator.max_undo = max_undo = 10
129        for i in range(max_undo + 10):
130            text.insert('insert', 'foo')
131            self.assertLessEqual(len(self.delegator.undolist), max_undo)
132
133
134if __name__ == '__main__':
135    unittest.main(verbosity=2, exit=False)
136