• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Test query, coverage 93%).
2
3Non-gui tests for Query, SectionName, ModuleName, and HelpSource use
4dummy versions that extract the non-gui methods and add other needed
5attributes.  GUI tests create an instance of each class and simulate
6entries and button clicks.  Subclass tests only target the new code in
7the subclass definition.
8
9The appearance of the widgets is checked by the Query and
10HelpSource htests.  These are run by running query.py.
11"""
12from idlelib import query
13import unittest
14from test.support import requires
15from tkinter import Tk, END
16
17import sys
18from unittest import mock
19from idlelib.idle_test.mock_tk import Var
20
21
22# NON-GUI TESTS
23
24class QueryTest(unittest.TestCase):
25    "Test Query base class."
26
27    class Dummy_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
75class SectionNameTest(unittest.TestCase):
76    "Test SectionName subclass of Query."
77
78    class Dummy_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
108class ModuleNameTest(unittest.TestCase):
109    "Test ModuleName subclass of Query."
110
111    class Dummy_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
140
141# 3 HelpSource test classes each test one method.
142
143class HelpsourceBrowsefileTest(unittest.TestCase):
144    "Test browse_file method of ModuleName subclass of Query."
145
146    class Dummy_HelpSource:
147        browse_file = query.HelpSource.browse_file
148        pathvar = Var()
149
150    def test_file_replaces_path(self):
151        dialog = self.Dummy_HelpSource()
152        # Path is widget entry, either '' or something.
153        # Func return is file dialog return, either '' or something.
154        # Func return should override widget entry.
155        # We need all 4 combinations to test all (most) code paths.
156        for path, func, result in (
157                ('', lambda a,b,c:'', ''),
158                ('', lambda a,b,c: __file__, __file__),
159                ('htest', lambda a,b,c:'', 'htest'),
160                ('htest', lambda a,b,c: __file__, __file__)):
161            with self.subTest():
162                dialog.pathvar.set(path)
163                dialog.askfilename = func
164                dialog.browse_file()
165                self.assertEqual(dialog.pathvar.get(), result)
166
167
168class HelpsourcePathokTest(unittest.TestCase):
169    "Test path_ok method of HelpSource subclass of Query."
170
171    class Dummy_HelpSource:
172        path_ok = query.HelpSource.path_ok
173        def __init__(self, dummy_path):
174            self.path = Var(value=dummy_path)
175            self.path_error = {'text': ''}
176        def showerror(self, message, widget=None):
177            self.path_error['text'] = message
178
179    orig_platform = query.platform  # Set in test_path_ok_file.
180    @classmethod
181    def tearDownClass(cls):
182        query.platform = cls.orig_platform
183
184    def test_path_ok_blank(self):
185        dialog = self.Dummy_HelpSource(' ')
186        self.assertEqual(dialog.path_ok(), None)
187        self.assertIn('no help file', dialog.path_error['text'])
188
189    def test_path_ok_bad(self):
190        dialog = self.Dummy_HelpSource(__file__ + 'bad-bad-bad')
191        self.assertEqual(dialog.path_ok(), None)
192        self.assertIn('not exist', dialog.path_error['text'])
193
194    def test_path_ok_web(self):
195        dialog = self.Dummy_HelpSource('')
196        Equal = self.assertEqual
197        for url in 'www.py.org', 'http://py.org':
198            with self.subTest():
199                dialog.path.set(url)
200                self.assertEqual(dialog.path_ok(), url)
201                self.assertEqual(dialog.path_error['text'], '')
202
203    def test_path_ok_file(self):
204        dialog = self.Dummy_HelpSource('')
205        for platform, prefix in ('darwin', 'file://'), ('other', ''):
206            with self.subTest():
207                query.platform = platform
208                dialog.path.set(__file__)
209                self.assertEqual(dialog.path_ok(), prefix + __file__)
210                self.assertEqual(dialog.path_error['text'], '')
211
212
213class HelpsourceEntryokTest(unittest.TestCase):
214    "Test entry_ok method of HelpSource subclass of Query."
215
216    class Dummy_HelpSource:
217        entry_ok = query.HelpSource.entry_ok
218        entry_error = {}
219        path_error = {}
220        def item_ok(self):
221            return self.name
222        def path_ok(self):
223            return self.path
224
225    def test_entry_ok_helpsource(self):
226        dialog = self.Dummy_HelpSource()
227        for name, path, result in ((None, None, None),
228                                   (None, 'doc.txt', None),
229                                   ('doc', None, None),
230                                   ('doc', 'doc.txt', ('doc', 'doc.txt'))):
231            with self.subTest():
232                dialog.name, dialog.path = name, path
233                self.assertEqual(dialog.entry_ok(), result)
234
235
236# 2 CustomRun test classes each test one method.
237
238class CustomRunCLIargsokTest(unittest.TestCase):
239    "Test cli_ok method of the CustomRun subclass of Query."
240
241    class Dummy_CustomRun:
242        cli_args_ok = query.CustomRun.cli_args_ok
243        def __init__(self, dummy_entry):
244            self.entry = Var(value=dummy_entry)
245            self.entry_error = {'text': ''}
246        def showerror(self, message):
247            self.entry_error['text'] = message
248
249    def test_blank_args(self):
250        dialog = self.Dummy_CustomRun(' ')
251        self.assertEqual(dialog.cli_args_ok(), [])
252
253    def test_invalid_args(self):
254        dialog = self.Dummy_CustomRun("'no-closing-quote")
255        self.assertEqual(dialog.cli_args_ok(), None)
256        self.assertIn('No closing', dialog.entry_error['text'])
257
258    def test_good_args(self):
259        args = ['-n', '10', '--verbose', '-p', '/path', '--name']
260        dialog = self.Dummy_CustomRun(' '.join(args) + ' "my name"')
261        self.assertEqual(dialog.cli_args_ok(), args + ["my name"])
262        self.assertEqual(dialog.entry_error['text'], '')
263
264
265class CustomRunEntryokTest(unittest.TestCase):
266    "Test entry_ok method of the CustomRun subclass of Query."
267
268    class Dummy_CustomRun:
269        entry_ok = query.CustomRun.entry_ok
270        entry_error = {}
271        restartvar = Var()
272        def cli_args_ok(self):
273            return self.cli_args
274
275    def test_entry_ok_customrun(self):
276        dialog = self.Dummy_CustomRun()
277        for restart in {True, False}:
278            dialog.restartvar.set(restart)
279            for cli_args, result in ((None, None),
280                                     (['my arg'], (['my arg'], restart))):
281                with self.subTest(restart=restart, cli_args=cli_args):
282                    dialog.cli_args = cli_args
283                    self.assertEqual(dialog.entry_ok(), result)
284
285
286# GUI TESTS
287
288class QueryGuiTest(unittest.TestCase):
289
290    @classmethod
291    def setUpClass(cls):
292        requires('gui')
293        cls.root = root = Tk()
294        cls.root.withdraw()
295        cls.dialog = query.Query(root, 'TEST', 'test', _utest=True)
296        cls.dialog.destroy = mock.Mock()
297
298    @classmethod
299    def tearDownClass(cls):
300        del cls.dialog.destroy
301        del cls.dialog
302        cls.root.destroy()
303        del cls.root
304
305    def setUp(self):
306        self.dialog.entry.delete(0, 'end')
307        self.dialog.result = None
308        self.dialog.destroy.reset_mock()
309
310    def test_click_ok(self):
311        dialog = self.dialog
312        dialog.entry.insert(0, 'abc')
313        dialog.button_ok.invoke()
314        self.assertEqual(dialog.result, 'abc')
315        self.assertTrue(dialog.destroy.called)
316
317    def test_click_blank(self):
318        dialog = self.dialog
319        dialog.button_ok.invoke()
320        self.assertEqual(dialog.result, None)
321        self.assertFalse(dialog.destroy.called)
322
323    def test_click_cancel(self):
324        dialog = self.dialog
325        dialog.entry.insert(0, 'abc')
326        dialog.button_cancel.invoke()
327        self.assertEqual(dialog.result, None)
328        self.assertTrue(dialog.destroy.called)
329
330
331class SectionnameGuiTest(unittest.TestCase):
332
333    @classmethod
334    def setUpClass(cls):
335        requires('gui')
336
337    def test_click_section_name(self):
338        root = Tk()
339        root.withdraw()
340        dialog =  query.SectionName(root, 'T', 't', {'abc'}, _utest=True)
341        Equal = self.assertEqual
342        self.assertEqual(dialog.used_names, {'abc'})
343        dialog.entry.insert(0, 'okay')
344        dialog.button_ok.invoke()
345        self.assertEqual(dialog.result, 'okay')
346        root.destroy()
347
348
349class ModulenameGuiTest(unittest.TestCase):
350
351    @classmethod
352    def setUpClass(cls):
353        requires('gui')
354
355    def test_click_module_name(self):
356        root = Tk()
357        root.withdraw()
358        dialog =  query.ModuleName(root, 'T', 't', 'idlelib', _utest=True)
359        self.assertEqual(dialog.text0, 'idlelib')
360        self.assertEqual(dialog.entry.get(), 'idlelib')
361        dialog.button_ok.invoke()
362        self.assertTrue(dialog.result.endswith('__init__.py'))
363        root.destroy()
364
365
366class HelpsourceGuiTest(unittest.TestCase):
367
368    @classmethod
369    def setUpClass(cls):
370        requires('gui')
371
372    def test_click_help_source(self):
373        root = Tk()
374        root.withdraw()
375        dialog =  query.HelpSource(root, 'T', menuitem='__test__',
376                                   filepath=__file__, _utest=True)
377        Equal = self.assertEqual
378        Equal(dialog.entry.get(), '__test__')
379        Equal(dialog.path.get(), __file__)
380        dialog.button_ok.invoke()
381        prefix = "file://" if sys.platform == 'darwin' else ''
382        Equal(dialog.result, ('__test__', prefix + __file__))
383        root.destroy()
384
385
386class CustomRunGuiTest(unittest.TestCase):
387
388    @classmethod
389    def setUpClass(cls):
390        requires('gui')
391
392    def test_click_args(self):
393        root = Tk()
394        root.withdraw()
395        dialog =  query.CustomRun(root, 'Title',
396                                  cli_args=['a', 'b=1'], _utest=True)
397        self.assertEqual(dialog.entry.get(), 'a b=1')
398        dialog.entry.insert(END, ' c')
399        dialog.button_ok.invoke()
400        self.assertEqual(dialog.result, (['a', 'b=1', 'c'], True))
401        root.destroy()
402
403
404if __name__ == '__main__':
405    unittest.main(verbosity=2, exit=False)
406