1"Test replace, coverage 78%."
2
3from idlelib.replace import ReplaceDialog
4import unittest
5from test.support import requires
6requires('gui')
7from tkinter import Tk, Text
8
9from unittest.mock import Mock
10from idlelib.idle_test.mock_tk import Mbox
11import idlelib.searchengine as se
12
13orig_mbox = se.messagebox
14showerror = Mbox.showerror
15
16
17class ReplaceDialogTest(unittest.TestCase):
18
19    @classmethod
20    def setUpClass(cls):
21        cls.root = Tk()
22        cls.root.withdraw()
23        se.messagebox = Mbox
24        cls.engine = se.SearchEngine(cls.root)
25        cls.dialog = ReplaceDialog(cls.root, cls.engine)
26        cls.dialog.bell = lambda: None
27        cls.dialog.ok = Mock()
28        cls.text = Text(cls.root)
29        cls.text.undo_block_start = Mock()
30        cls.text.undo_block_stop = Mock()
31        cls.dialog.text = cls.text
32
33    @classmethod
34    def tearDownClass(cls):
35        se.messagebox = orig_mbox
36        del cls.text, cls.dialog, cls.engine
37        cls.root.destroy()
38        del cls.root
39
40    def setUp(self):
41        self.text.insert('insert', 'This is a sample sTring')
42
43    def tearDown(self):
44        self.engine.patvar.set('')
45        self.dialog.replvar.set('')
46        self.engine.wordvar.set(False)
47        self.engine.casevar.set(False)
48        self.engine.revar.set(False)
49        self.engine.wrapvar.set(True)
50        self.engine.backvar.set(False)
51        showerror.title = ''
52        showerror.message = ''
53        self.text.delete('1.0', 'end')
54
55    def test_replace_simple(self):
56        # Test replace function with all options at default setting.
57        # Wrap around - True
58        # Regular Expression - False
59        # Match case - False
60        # Match word - False
61        # Direction - Forwards
62        text = self.text
63        equal = self.assertEqual
64        pv = self.engine.patvar
65        rv = self.dialog.replvar
66        replace = self.dialog.replace_it
67
68        # test accessor method
69        self.engine.setpat('asdf')
70        equal(self.engine.getpat(), pv.get())
71
72        # text found and replaced
73        pv.set('a')
74        rv.set('asdf')
75        replace()
76        equal(text.get('1.8', '1.12'), 'asdf')
77
78        # don't "match word" case
79        text.mark_set('insert', '1.0')
80        pv.set('is')
81        rv.set('hello')
82        replace()
83        equal(text.get('1.2', '1.7'), 'hello')
84
85        # don't "match case" case
86        pv.set('string')
87        rv.set('world')
88        replace()
89        equal(text.get('1.23', '1.28'), 'world')
90
91        # without "regular expression" case
92        text.mark_set('insert', 'end')
93        text.insert('insert', '\nline42:')
94        before_text = text.get('1.0', 'end')
95        pv.set(r'[a-z][\d]+')
96        replace()
97        after_text = text.get('1.0', 'end')
98        equal(before_text, after_text)
99
100        # test with wrap around selected and complete a cycle
101        text.mark_set('insert', '1.9')
102        pv.set('i')
103        rv.set('j')
104        replace()
105        equal(text.get('1.8'), 'i')
106        equal(text.get('2.1'), 'j')
107        replace()
108        equal(text.get('2.1'), 'j')
109        equal(text.get('1.8'), 'j')
110        before_text = text.get('1.0', 'end')
111        replace()
112        after_text = text.get('1.0', 'end')
113        equal(before_text, after_text)
114
115        # text not found
116        before_text = text.get('1.0', 'end')
117        pv.set('foobar')
118        replace()
119        after_text = text.get('1.0', 'end')
120        equal(before_text, after_text)
121
122        # test access method
123        self.dialog.find_it(0)
124
125    def test_replace_wrap_around(self):
126        text = self.text
127        equal = self.assertEqual
128        pv = self.engine.patvar
129        rv = self.dialog.replvar
130        replace = self.dialog.replace_it
131        self.engine.wrapvar.set(False)
132
133        # replace candidate found both after and before 'insert'
134        text.mark_set('insert', '1.4')
135        pv.set('i')
136        rv.set('j')
137        replace()
138        equal(text.get('1.2'), 'i')
139        equal(text.get('1.5'), 'j')
140        replace()
141        equal(text.get('1.2'), 'i')
142        equal(text.get('1.20'), 'j')
143        replace()
144        equal(text.get('1.2'), 'i')
145
146        # replace candidate found only before 'insert'
147        text.mark_set('insert', '1.8')
148        pv.set('is')
149        before_text = text.get('1.0', 'end')
150        replace()
151        after_text = text.get('1.0', 'end')
152        equal(before_text, after_text)
153
154    def test_replace_whole_word(self):
155        text = self.text
156        equal = self.assertEqual
157        pv = self.engine.patvar
158        rv = self.dialog.replvar
159        replace = self.dialog.replace_it
160        self.engine.wordvar.set(True)
161
162        pv.set('is')
163        rv.set('hello')
164        replace()
165        equal(text.get('1.0', '1.4'), 'This')
166        equal(text.get('1.5', '1.10'), 'hello')
167
168    def test_replace_match_case(self):
169        equal = self.assertEqual
170        text = self.text
171        pv = self.engine.patvar
172        rv = self.dialog.replvar
173        replace = self.dialog.replace_it
174        self.engine.casevar.set(True)
175
176        before_text = self.text.get('1.0', 'end')
177        pv.set('this')
178        rv.set('that')
179        replace()
180        after_text = self.text.get('1.0', 'end')
181        equal(before_text, after_text)
182
183        pv.set('This')
184        replace()
185        equal(text.get('1.0', '1.4'), 'that')
186
187    def test_replace_regex(self):
188        equal = self.assertEqual
189        text = self.text
190        pv = self.engine.patvar
191        rv = self.dialog.replvar
192        replace = self.dialog.replace_it
193        self.engine.revar.set(True)
194
195        before_text = text.get('1.0', 'end')
196        pv.set(r'[a-z][\d]+')
197        rv.set('hello')
198        replace()
199        after_text = text.get('1.0', 'end')
200        equal(before_text, after_text)
201
202        text.insert('insert', '\nline42')
203        replace()
204        equal(text.get('2.0', '2.8'), 'linhello')
205
206        pv.set('')
207        replace()
208        self.assertIn('error', showerror.title)
209        self.assertIn('Empty', showerror.message)
210
211        pv.set(r'[\d')
212        replace()
213        self.assertIn('error', showerror.title)
214        self.assertIn('Pattern', showerror.message)
215
216        showerror.title = ''
217        showerror.message = ''
218        pv.set('[a]')
219        rv.set('test\\')
220        replace()
221        self.assertIn('error', showerror.title)
222        self.assertIn('Invalid Replace Expression', showerror.message)
223
224        # test access method
225        self.engine.setcookedpat("?")
226        equal(pv.get(), "\\?")
227
228    def test_replace_backwards(self):
229        equal = self.assertEqual
230        text = self.text
231        pv = self.engine.patvar
232        rv = self.dialog.replvar
233        replace = self.dialog.replace_it
234        self.engine.backvar.set(True)
235
236        text.insert('insert', '\nis as ')
237
238        pv.set('is')
239        rv.set('was')
240        replace()
241        equal(text.get('1.2', '1.4'), 'is')
242        equal(text.get('2.0', '2.3'), 'was')
243        replace()
244        equal(text.get('1.5', '1.8'), 'was')
245        replace()
246        equal(text.get('1.2', '1.5'), 'was')
247
248    def test_replace_all(self):
249        text = self.text
250        pv = self.engine.patvar
251        rv = self.dialog.replvar
252        replace_all = self.dialog.replace_all
253
254        text.insert('insert', '\n')
255        text.insert('insert', text.get('1.0', 'end')*100)
256        pv.set('is')
257        rv.set('was')
258        replace_all()
259        self.assertNotIn('is', text.get('1.0', 'end'))
260
261        self.engine.revar.set(True)
262        pv.set('')
263        replace_all()
264        self.assertIn('error', showerror.title)
265        self.assertIn('Empty', showerror.message)
266
267        pv.set('[s][T]')
268        rv.set('\\')
269        replace_all()
270
271        self.engine.revar.set(False)
272        pv.set('text which is not present')
273        rv.set('foobar')
274        replace_all()
275
276    def test_default_command(self):
277        text = self.text
278        pv = self.engine.patvar
279        rv = self.dialog.replvar
280        replace_find = self.dialog.default_command
281        equal = self.assertEqual
282
283        pv.set('This')
284        rv.set('was')
285        replace_find()
286        equal(text.get('sel.first', 'sel.last'), 'was')
287
288        self.engine.revar.set(True)
289        pv.set('')
290        replace_find()
291
292
293if __name__ == '__main__':
294    unittest.main(verbosity=2)
295