1 """Test query, coverage 93%.
2
3 Non-gui tests for Query, SectionName, ModuleName, and HelpSource use
4 dummy versions that extract the non-gui methods and add other needed
5 attributes. GUI tests create an instance of each class and simulate
6 entries and button clicks. Subclass tests only target the new code in
7 the subclass definition.
8
9 The appearance of the widgets is checked by the Query and
10 HelpSource htests. These are run by running query.py.
11 """
12 from idlelib import query
13 import unittest
14 from test.support import requires
15 from tkinter import Tk, END
16
17 import sys
18 from unittest import mock
19 from idlelib.idle_test.mock_tk import Var
20
21
22 # NON-GUI TESTS
23
24 class ESC[4;38;5;81mQueryTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
25 "Test Query base class."
26
27 class ESC[4;38;5;81mDummy_Query:
28 # Test the following Query methods.
29 entry_ok = query.Query.entry_ok
30 ok = query.Query.ok
31 cancel = query.Query.cancel
32 # Add attributes and initialization needed for tests.
33 def __init__(self, dummy_entry):
34 self.entry = Var(value=dummy_entry)
35 self.entry_error = {'text': ''}
36 self.result = None
37 self.destroyed = False
38 def showerror(self, message):
39 self.entry_error['text'] = message
40 def destroy(self):
41 self.destroyed = True
42
43 def test_entry_ok_blank(self):
44 dialog = self.Dummy_Query(' ')
45 self.assertEqual(dialog.entry_ok(), None)
46 self.assertEqual((dialog.result, dialog.destroyed), (None, False))
47 self.assertIn('blank line', dialog.entry_error['text'])
48
49 def test_entry_ok_good(self):
50 dialog = self.Dummy_Query(' good ')
51 Equal = self.assertEqual
52 Equal(dialog.entry_ok(), 'good')
53 Equal((dialog.result, dialog.destroyed), (None, False))
54 Equal(dialog.entry_error['text'], '')
55
56 def test_ok_blank(self):
57 dialog = self.Dummy_Query('')
58 dialog.entry.focus_set = mock.Mock()
59 self.assertEqual(dialog.ok(), None)
60 self.assertTrue(dialog.entry.focus_set.called)
61 del dialog.entry.focus_set
62 self.assertEqual((dialog.result, dialog.destroyed), (None, False))
63
64 def test_ok_good(self):
65 dialog = self.Dummy_Query('good')
66 self.assertEqual(dialog.ok(), None)
67 self.assertEqual((dialog.result, dialog.destroyed), ('good', True))
68
69 def test_cancel(self):
70 dialog = self.Dummy_Query('does not matter')
71 self.assertEqual(dialog.cancel(), None)
72 self.assertEqual((dialog.result, dialog.destroyed), (None, True))
73
74
75 class ESC[4;38;5;81mSectionNameTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
76 "Test SectionName subclass of Query."
77
78 class ESC[4;38;5;81mDummy_SectionName:
79 entry_ok = query.SectionName.entry_ok # Function being tested.
80 used_names = ['used']
81 def __init__(self, dummy_entry):
82 self.entry = Var(value=dummy_entry)
83 self.entry_error = {'text': ''}
84 def showerror(self, message):
85 self.entry_error['text'] = message
86
87 def test_blank_section_name(self):
88 dialog = self.Dummy_SectionName(' ')
89 self.assertEqual(dialog.entry_ok(), None)
90 self.assertIn('no name', dialog.entry_error['text'])
91
92 def test_used_section_name(self):
93 dialog = self.Dummy_SectionName('used')
94 self.assertEqual(dialog.entry_ok(), None)
95 self.assertIn('use', dialog.entry_error['text'])
96
97 def test_long_section_name(self):
98 dialog = self.Dummy_SectionName('good'*8)
99 self.assertEqual(dialog.entry_ok(), None)
100 self.assertIn('longer than 30', dialog.entry_error['text'])
101
102 def test_good_section_name(self):
103 dialog = self.Dummy_SectionName(' good ')
104 self.assertEqual(dialog.entry_ok(), 'good')
105 self.assertEqual(dialog.entry_error['text'], '')
106
107
108 class ESC[4;38;5;81mModuleNameTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
109 "Test ModuleName subclass of Query."
110
111 class ESC[4;38;5;81mDummy_ModuleName:
112 entry_ok = query.ModuleName.entry_ok # Function being tested.
113 text0 = ''
114 def __init__(self, dummy_entry):
115 self.entry = Var(value=dummy_entry)
116 self.entry_error = {'text': ''}
117 def showerror(self, message):
118 self.entry_error['text'] = message
119
120 def test_blank_module_name(self):
121 dialog = self.Dummy_ModuleName(' ')
122 self.assertEqual(dialog.entry_ok(), None)
123 self.assertIn('no name', dialog.entry_error['text'])
124
125 def test_bogus_module_name(self):
126 dialog = self.Dummy_ModuleName('__name_xyz123_should_not_exist__')
127 self.assertEqual(dialog.entry_ok(), None)
128 self.assertIn('not found', dialog.entry_error['text'])
129
130 def test_c_source_name(self):
131 dialog = self.Dummy_ModuleName('itertools')
132 self.assertEqual(dialog.entry_ok(), None)
133 self.assertIn('source-based', dialog.entry_error['text'])
134
135 def test_good_module_name(self):
136 dialog = self.Dummy_ModuleName('idlelib')
137 self.assertTrue(dialog.entry_ok().endswith('__init__.py'))
138 self.assertEqual(dialog.entry_error['text'], '')
139 dialog = self.Dummy_ModuleName('idlelib.idle')
140 self.assertTrue(dialog.entry_ok().endswith('idle.py'))
141 self.assertEqual(dialog.entry_error['text'], '')
142
143
144 class ESC[4;38;5;81mGotoTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
145 "Test Goto subclass of Query."
146
147 class ESC[4;38;5;81mDummy_ModuleName:
148 entry_ok = query.Goto.entry_ok # Function being tested.
149 def __init__(self, dummy_entry):
150 self.entry = Var(value=dummy_entry)
151 self.entry_error = {'text': ''}
152 def showerror(self, message):
153 self.entry_error['text'] = message
154
155 def test_bogus_goto(self):
156 dialog = self.Dummy_ModuleName('a')
157 self.assertEqual(dialog.entry_ok(), None)
158 self.assertIn('not a base 10 integer', dialog.entry_error['text'])
159
160 def test_bad_goto(self):
161 dialog = self.Dummy_ModuleName('0')
162 self.assertEqual(dialog.entry_ok(), None)
163 self.assertIn('not a positive integer', dialog.entry_error['text'])
164
165 def test_good_goto(self):
166 dialog = self.Dummy_ModuleName('1')
167 self.assertEqual(dialog.entry_ok(), 1)
168 self.assertEqual(dialog.entry_error['text'], '')
169
170
171 # 3 HelpSource test classes each test one method.
172
173 class ESC[4;38;5;81mHelpsourceBrowsefileTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
174 "Test browse_file method of ModuleName subclass of Query."
175
176 class ESC[4;38;5;81mDummy_HelpSource:
177 browse_file = query.HelpSource.browse_file
178 pathvar = Var()
179
180 def test_file_replaces_path(self):
181 dialog = self.Dummy_HelpSource()
182 # Path is widget entry, either '' or something.
183 # Func return is file dialog return, either '' or something.
184 # Func return should override widget entry.
185 # We need all 4 combinations to test all (most) code paths.
186 for path, func, result in (
187 ('', lambda a,b,c:'', ''),
188 ('', lambda a,b,c: __file__, __file__),
189 ('htest', lambda a,b,c:'', 'htest'),
190 ('htest', lambda a,b,c: __file__, __file__)):
191 with self.subTest():
192 dialog.pathvar.set(path)
193 dialog.askfilename = func
194 dialog.browse_file()
195 self.assertEqual(dialog.pathvar.get(), result)
196
197
198 class ESC[4;38;5;81mHelpsourcePathokTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
199 "Test path_ok method of HelpSource subclass of Query."
200
201 class ESC[4;38;5;81mDummy_HelpSource:
202 path_ok = query.HelpSource.path_ok
203 def __init__(self, dummy_path):
204 self.path = Var(value=dummy_path)
205 self.path_error = {'text': ''}
206 def showerror(self, message, widget=None):
207 self.path_error['text'] = message
208
209 orig_platform = query.platform # Set in test_path_ok_file.
210 @classmethod
211 def tearDownClass(cls):
212 query.platform = cls.orig_platform
213
214 def test_path_ok_blank(self):
215 dialog = self.Dummy_HelpSource(' ')
216 self.assertEqual(dialog.path_ok(), None)
217 self.assertIn('no help file', dialog.path_error['text'])
218
219 def test_path_ok_bad(self):
220 dialog = self.Dummy_HelpSource(__file__ + 'bad-bad-bad')
221 self.assertEqual(dialog.path_ok(), None)
222 self.assertIn('not exist', dialog.path_error['text'])
223
224 def test_path_ok_web(self):
225 dialog = self.Dummy_HelpSource('')
226 Equal = self.assertEqual
227 for url in 'www.py.org', 'http://py.org':
228 with self.subTest():
229 dialog.path.set(url)
230 self.assertEqual(dialog.path_ok(), url)
231 self.assertEqual(dialog.path_error['text'], '')
232
233 def test_path_ok_file(self):
234 dialog = self.Dummy_HelpSource('')
235 for platform, prefix in ('darwin', 'file://'), ('other', ''):
236 with self.subTest():
237 query.platform = platform
238 dialog.path.set(__file__)
239 self.assertEqual(dialog.path_ok(), prefix + __file__)
240 self.assertEqual(dialog.path_error['text'], '')
241
242
243 class ESC[4;38;5;81mHelpsourceEntryokTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
244 "Test entry_ok method of HelpSource subclass of Query."
245
246 class ESC[4;38;5;81mDummy_HelpSource:
247 entry_ok = query.HelpSource.entry_ok
248 entry_error = {}
249 path_error = {}
250 def item_ok(self):
251 return self.name
252 def path_ok(self):
253 return self.path
254
255 def test_entry_ok_helpsource(self):
256 dialog = self.Dummy_HelpSource()
257 for name, path, result in ((None, None, None),
258 (None, 'doc.txt', None),
259 ('doc', None, None),
260 ('doc', 'doc.txt', ('doc', 'doc.txt'))):
261 with self.subTest():
262 dialog.name, dialog.path = name, path
263 self.assertEqual(dialog.entry_ok(), result)
264
265
266 # 2 CustomRun test classes each test one method.
267
268 class ESC[4;38;5;81mCustomRunCLIargsokTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
269 "Test cli_ok method of the CustomRun subclass of Query."
270
271 class ESC[4;38;5;81mDummy_CustomRun:
272 cli_args_ok = query.CustomRun.cli_args_ok
273 def __init__(self, dummy_entry):
274 self.entry = Var(value=dummy_entry)
275 self.entry_error = {'text': ''}
276 def showerror(self, message):
277 self.entry_error['text'] = message
278
279 def test_blank_args(self):
280 dialog = self.Dummy_CustomRun(' ')
281 self.assertEqual(dialog.cli_args_ok(), [])
282
283 def test_invalid_args(self):
284 dialog = self.Dummy_CustomRun("'no-closing-quote")
285 self.assertEqual(dialog.cli_args_ok(), None)
286 self.assertIn('No closing', dialog.entry_error['text'])
287
288 def test_good_args(self):
289 args = ['-n', '10', '--verbose', '-p', '/path', '--name']
290 dialog = self.Dummy_CustomRun(' '.join(args) + ' "my name"')
291 self.assertEqual(dialog.cli_args_ok(), args + ["my name"])
292 self.assertEqual(dialog.entry_error['text'], '')
293
294
295 class ESC[4;38;5;81mCustomRunEntryokTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
296 "Test entry_ok method of the CustomRun subclass of Query."
297
298 class ESC[4;38;5;81mDummy_CustomRun:
299 entry_ok = query.CustomRun.entry_ok
300 entry_error = {}
301 restartvar = Var()
302 def cli_args_ok(self):
303 return self.cli_args
304
305 def test_entry_ok_customrun(self):
306 dialog = self.Dummy_CustomRun()
307 for restart in {True, False}:
308 dialog.restartvar.set(restart)
309 for cli_args, result in ((None, None),
310 (['my arg'], (['my arg'], restart))):
311 with self.subTest(restart=restart, cli_args=cli_args):
312 dialog.cli_args = cli_args
313 self.assertEqual(dialog.entry_ok(), result)
314
315
316 # GUI TESTS
317
318 class ESC[4;38;5;81mQueryGuiTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
319
320 @classmethod
321 def setUpClass(cls):
322 requires('gui')
323 cls.root = root = Tk()
324 cls.root.withdraw()
325 cls.dialog = query.Query(root, 'TEST', 'test', _utest=True)
326 cls.dialog.destroy = mock.Mock()
327
328 @classmethod
329 def tearDownClass(cls):
330 del cls.dialog.destroy
331 del cls.dialog
332 cls.root.destroy()
333 del cls.root
334
335 def setUp(self):
336 self.dialog.entry.delete(0, 'end')
337 self.dialog.result = None
338 self.dialog.destroy.reset_mock()
339
340 def test_click_ok(self):
341 dialog = self.dialog
342 dialog.entry.insert(0, 'abc')
343 dialog.button_ok.invoke()
344 self.assertEqual(dialog.result, 'abc')
345 self.assertTrue(dialog.destroy.called)
346
347 def test_click_blank(self):
348 dialog = self.dialog
349 dialog.button_ok.invoke()
350 self.assertEqual(dialog.result, None)
351 self.assertFalse(dialog.destroy.called)
352
353 def test_click_cancel(self):
354 dialog = self.dialog
355 dialog.entry.insert(0, 'abc')
356 dialog.button_cancel.invoke()
357 self.assertEqual(dialog.result, None)
358 self.assertTrue(dialog.destroy.called)
359
360
361 class ESC[4;38;5;81mSectionnameGuiTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
362
363 @classmethod
364 def setUpClass(cls):
365 requires('gui')
366
367 def test_click_section_name(self):
368 root = Tk()
369 root.withdraw()
370 dialog = query.SectionName(root, 'T', 't', {'abc'}, _utest=True)
371 Equal = self.assertEqual
372 self.assertEqual(dialog.used_names, {'abc'})
373 dialog.entry.insert(0, 'okay')
374 dialog.button_ok.invoke()
375 self.assertEqual(dialog.result, 'okay')
376 root.destroy()
377
378
379 class ESC[4;38;5;81mModulenameGuiTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
380
381 @classmethod
382 def setUpClass(cls):
383 requires('gui')
384
385 def test_click_module_name(self):
386 root = Tk()
387 root.withdraw()
388 dialog = query.ModuleName(root, 'T', 't', 'idlelib', _utest=True)
389 self.assertEqual(dialog.text0, 'idlelib')
390 self.assertEqual(dialog.entry.get(), 'idlelib')
391 dialog.button_ok.invoke()
392 self.assertTrue(dialog.result.endswith('__init__.py'))
393 root.destroy()
394
395
396 class ESC[4;38;5;81mGotoGuiTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
397
398 @classmethod
399 def setUpClass(cls):
400 requires('gui')
401
402 def test_click_module_name(self):
403 root = Tk()
404 root.withdraw()
405 dialog = query.Goto(root, 'T', 't', _utest=True)
406 dialog.entry.insert(0, '22')
407 dialog.button_ok.invoke()
408 self.assertEqual(dialog.result, 22)
409 root.destroy()
410
411
412 class ESC[4;38;5;81mHelpsourceGuiTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
413
414 @classmethod
415 def setUpClass(cls):
416 requires('gui')
417
418 def test_click_help_source(self):
419 root = Tk()
420 root.withdraw()
421 dialog = query.HelpSource(root, 'T', menuitem='__test__',
422 filepath=__file__, _utest=True)
423 Equal = self.assertEqual
424 Equal(dialog.entry.get(), '__test__')
425 Equal(dialog.path.get(), __file__)
426 dialog.button_ok.invoke()
427 prefix = "file://" if sys.platform == 'darwin' else ''
428 Equal(dialog.result, ('__test__', prefix + __file__))
429 root.destroy()
430
431
432 class ESC[4;38;5;81mCustomRunGuiTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
433
434 @classmethod
435 def setUpClass(cls):
436 requires('gui')
437
438 def test_click_args(self):
439 root = Tk()
440 root.withdraw()
441 dialog = query.CustomRun(root, 'Title',
442 cli_args=['a', 'b=1'], _utest=True)
443 self.assertEqual(dialog.entry.get(), 'a b=1')
444 dialog.entry.insert(END, ' c')
445 dialog.button_ok.invoke()
446 self.assertEqual(dialog.result, (['a', 'b=1', 'c'], True))
447 root.destroy()
448
449
450 if __name__ == '__main__':
451 unittest.main(verbosity=2, exit=False)