From: Terry Jan Reedy Date: Thu, 1 Sep 2016 01:09:02 +0000 (-0400) Subject: Issue #27922: IDLE tests no longer flash tk widgets (Merge 3.5). X-Git-Tag: v3.6.0b1~505 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5f30f7935701cb0c62f498753ad79f19f24f10a1;p=python Issue #27922: IDLE tests no longer flash tk widgets (Merge 3.5). --- 5f30f7935701cb0c62f498753ad79f19f24f10a1 diff --cc Lib/idlelib/idle_test/test_config_key.py index 59d8e817e3,0000000000..ee3f2c835c mode 100644,000000..100644 --- a/Lib/idlelib/idle_test/test_config_key.py +++ b/Lib/idlelib/idle_test/test_config_key.py @@@ -1,32 -1,0 +1,33 @@@ +''' Test idlelib.config_key. + +Coverage: 56% from creating and closing dialog. +''' +from idlelib import config_key +from test.support import requires +requires('gui') +import unittest +from tkinter import Tk, Text + + +class GetKeysTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.root = Tk() ++ cls.root.withdraw() + + @classmethod + def tearDownClass(cls): + cls.root.update() # Stop "can't run event command" warning. + cls.root.destroy() + del cls.root + + + def test_init(self): + dia = config_key.GetKeysDialog( + self.root, 'test', '<>', [''], _utest=True) + dia.Cancel() + + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --cc Lib/idlelib/idle_test/test_configdialog.py index 736b098d2a,5c09790c64..70bd14e851 --- a/Lib/idlelib/idle_test/test_configdialog.py +++ b/Lib/idlelib/idle_test/test_configdialog.py @@@ -14,6 -15,8 +14,7 @@@ class ConfigDialogTest(unittest.TestCas @classmethod def setUpClass(cls): cls.root = Tk() + cls.root.withdraw() - macosx._initializeTkVariantTests(cls.root) @classmethod def tearDownClass(cls): diff --cc Lib/idlelib/idle_test/test_editmenu.py index 654f060225,a258e29e0f..17eb25c4b4 --- a/Lib/idlelib/idle_test/test_editmenu.py +++ b/Lib/idlelib/idle_test/test_editmenu.py @@@ -17,10 -16,10 +17,11 @@@ class PasteTest(unittest.TestCase) @classmethod def setUpClass(cls): cls.root = root = tk.Tk() - root.withdraw() - PyShell.fix_x11_paste(root) ++ cls.root.withdraw() + pyshell.fix_x11_paste(root) cls.text = tk.Text(root) cls.entry = tk.Entry(root) + cls.tentry = ttk.Entry(root) cls.spin = tk.Spinbox(root) root.clipboard_clear() root.clipboard_append('two') diff --cc Lib/idlelib/idle_test/test_macosx.py index 3c6161c518,0000000000..fae75d8a49 mode 100644,000000..100644 --- a/Lib/idlelib/idle_test/test_macosx.py +++ b/Lib/idlelib/idle_test/test_macosx.py @@@ -1,101 -1,0 +1,103 @@@ +'''Test idlelib.macosx.py. + +Coverage: 71% on Windows. +''' +from idlelib import macosx +from test.support import requires +import sys +import tkinter as tk +import unittest +import unittest.mock as mock +from idlelib.filelist import FileList + +mactypes = {'carbon', 'cocoa', 'xquartz'} +nontypes = {'other'} +alltypes = mactypes | nontypes + + +class InitTktypeTest(unittest.TestCase): + "Test _init_tk_type." + + @classmethod + def setUpClass(cls): + requires('gui') + cls.root = tk.Tk() ++ cls.root.withdraw() + cls.orig_platform = macosx.platform + + @classmethod + def tearDownClass(cls): + cls.root.update_idletasks() + cls.root.destroy() + del cls.root + macosx.platform = cls.orig_platform + + def test_init_sets_tktype(self): + "Test that _init_tk_type sets _tk_type according to platform." + for platform, types in ('darwin', alltypes), ('other', nontypes): + with self.subTest(platform=platform): + macosx.platform = platform + macosx._tk_type == None + macosx._init_tk_type() + self.assertIn(macosx._tk_type, types) + + +class IsTypeTkTest(unittest.TestCase): + "Test each of the four isTypeTk predecates." + isfuncs = ((macosx.isAquaTk, ('carbon', 'cocoa')), + (macosx.isCarbonTk, ('carbon')), + (macosx.isCocoaTk, ('cocoa')), + (macosx.isXQuartz, ('xquartz')), + ) + + @mock.patch('idlelib.macosx._init_tk_type') + def test_is_calls_init(self, mockinit): + "Test that each isTypeTk calls _init_tk_type when _tk_type is None." + macosx._tk_type = None + for func, whentrue in self.isfuncs: + with self.subTest(func=func): + func() + self.assertTrue(mockinit.called) + mockinit.reset_mock() + + def test_isfuncs(self): + "Test that each isTypeTk return correct bool." + for func, whentrue in self.isfuncs: + for tktype in alltypes: + with self.subTest(func=func, whentrue=whentrue, tktype=tktype): + macosx._tk_type = tktype + (self.assertTrue if tktype in whentrue else self.assertFalse)\ + (func()) + + +class SetupTest(unittest.TestCase): + "Test setupApp." + + @classmethod + def setUpClass(cls): + requires('gui') + cls.root = tk.Tk() ++ cls.root.withdraw() + + @classmethod + def tearDownClass(cls): + cls.root.update_idletasks() + cls.root.destroy() + del cls.root + + @mock.patch('idlelib.macosx.overrideRootMenu') #27312 + def test_setupapp(self, overrideRootMenu): + "Call setupApp with each possible graphics type." + root = self.root + flist = FileList(root) + for tktype in alltypes: + with self.subTest(tktype=tktype): + macosx._tk_type = tktype + macosx.setupApp(root, flist) + if tktype in ('carbon', 'cocoa'): + self.assertTrue(overrideRootMenu.called) + overrideRootMenu.reset_mock() + + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --cc Lib/idlelib/idle_test/test_query.py index e9ed694dc0,0000000000..66af8eb85b mode 100644,000000..100644 --- a/Lib/idlelib/idle_test/test_query.py +++ b/Lib/idlelib/idle_test/test_query.py @@@ -1,349 -1,0 +1,353 @@@ +"""Test idlelib.query. + +Non-gui tests for Query, SectionName, ModuleName, and HelpSource use +dummy versions that extract the non-gui methods and add other needed +attributes. GUI tests create an instance of each class and simulate +entries and button clicks. Subclass tests only target the new code in +the subclass definition. + +The appearance of the widgets is checked by the Query and +HelpSource htests. These are run by running query.py. + +Coverage: 94% (100% for Query and SectionName). +6 of 8 missing are ModuleName exceptions I don't know how to trigger. +""" +from test.support import requires +import sys +from tkinter import Tk +import unittest +from unittest import mock +from idlelib.idle_test.mock_tk import Var +from idlelib import query + + +# NON-GUI TESTS + +class QueryTest(unittest.TestCase): + "Test Query base class." + + class Dummy_Query: + # Test the following Query methods. + entry_ok = query.Query.entry_ok + ok = query.Query.ok + cancel = query.Query.cancel + # Add attributes and initialization needed for tests. + entry = Var() + entry_error = {} + def __init__(self, dummy_entry): + self.entry.set(dummy_entry) + self.entry_error['text'] = '' + self.result = None + self.destroyed = False + def showerror(self, message): + self.entry_error['text'] = message + def destroy(self): + self.destroyed = True + + def test_entry_ok_blank(self): + dialog = self.Dummy_Query(' ') + self.assertEqual(dialog.entry_ok(), None) + self.assertEqual((dialog.result, dialog.destroyed), (None, False)) + self.assertIn('blank line', dialog.entry_error['text']) + + def test_entry_ok_good(self): + dialog = self.Dummy_Query(' good ') + Equal = self.assertEqual + Equal(dialog.entry_ok(), 'good') + Equal((dialog.result, dialog.destroyed), (None, False)) + Equal(dialog.entry_error['text'], '') + + def test_ok_blank(self): + dialog = self.Dummy_Query('') + dialog.entry.focus_set = mock.Mock() + self.assertEqual(dialog.ok(), None) + self.assertTrue(dialog.entry.focus_set.called) + del dialog.entry.focus_set + self.assertEqual((dialog.result, dialog.destroyed), (None, False)) + + def test_ok_good(self): + dialog = self.Dummy_Query('good') + self.assertEqual(dialog.ok(), None) + self.assertEqual((dialog.result, dialog.destroyed), ('good', True)) + + def test_cancel(self): + dialog = self.Dummy_Query('does not matter') + self.assertEqual(dialog.cancel(), None) + self.assertEqual((dialog.result, dialog.destroyed), (None, True)) + + +class SectionNameTest(unittest.TestCase): + "Test SectionName subclass of Query." + + class Dummy_SectionName: + entry_ok = query.SectionName.entry_ok # Function being tested. + used_names = ['used'] + entry = Var() + entry_error = {} + def __init__(self, dummy_entry): + self.entry.set(dummy_entry) + self.entry_error['text'] = '' + def showerror(self, message): + self.entry_error['text'] = message + + def test_blank_section_name(self): + dialog = self.Dummy_SectionName(' ') + self.assertEqual(dialog.entry_ok(), None) + self.assertIn('no name', dialog.entry_error['text']) + + def test_used_section_name(self): + dialog = self.Dummy_SectionName('used') + self.assertEqual(dialog.entry_ok(), None) + self.assertIn('use', dialog.entry_error['text']) + + def test_long_section_name(self): + dialog = self.Dummy_SectionName('good'*8) + self.assertEqual(dialog.entry_ok(), None) + self.assertIn('longer than 30', dialog.entry_error['text']) + + def test_good_section_name(self): + dialog = self.Dummy_SectionName(' good ') + self.assertEqual(dialog.entry_ok(), 'good') + self.assertEqual(dialog.entry_error['text'], '') + + +class ModuleNameTest(unittest.TestCase): + "Test ModuleName subclass of Query." + + class Dummy_ModuleName: + entry_ok = query.ModuleName.entry_ok # Function being tested. + text0 = '' + entry = Var() + entry_error = {} + def __init__(self, dummy_entry): + self.entry.set(dummy_entry) + self.entry_error['text'] = '' + def showerror(self, message): + self.entry_error['text'] = message + + def test_blank_module_name(self): + dialog = self.Dummy_ModuleName(' ') + self.assertEqual(dialog.entry_ok(), None) + self.assertIn('no name', dialog.entry_error['text']) + + def test_bogus_module_name(self): + dialog = self.Dummy_ModuleName('__name_xyz123_should_not_exist__') + self.assertEqual(dialog.entry_ok(), None) + self.assertIn('not found', dialog.entry_error['text']) + + def test_c_source_name(self): + dialog = self.Dummy_ModuleName('itertools') + self.assertEqual(dialog.entry_ok(), None) + self.assertIn('source-based', dialog.entry_error['text']) + + def test_good_module_name(self): + dialog = self.Dummy_ModuleName('idlelib') + self.assertTrue(dialog.entry_ok().endswith('__init__.py')) + self.assertEqual(dialog.entry_error['text'], '') + + +# 3 HelpSource test classes each test one function. + +orig_platform = query.platform + +class HelpsourceBrowsefileTest(unittest.TestCase): + "Test browse_file method of ModuleName subclass of Query." + + class Dummy_HelpSource: + browse_file = query.HelpSource.browse_file + pathvar = Var() + + def test_file_replaces_path(self): + dialog = self.Dummy_HelpSource() + # Path is widget entry, either '' or something. + # Func return is file dialog return, either '' or something. + # Func return should override widget entry. + # We need all 4 combination to test all (most) code paths. + for path, func, result in ( + ('', lambda a,b,c:'', ''), + ('', lambda a,b,c: __file__, __file__), + ('htest', lambda a,b,c:'', 'htest'), + ('htest', lambda a,b,c: __file__, __file__)): + with self.subTest(): + dialog.pathvar.set(path) + dialog.askfilename = func + dialog.browse_file() + self.assertEqual(dialog.pathvar.get(), result) + + +class HelpsourcePathokTest(unittest.TestCase): + "Test path_ok method of HelpSource subclass of Query." + + class Dummy_HelpSource: + path_ok = query.HelpSource.path_ok + path = Var() + path_error = {} + def __init__(self, dummy_path): + self.path.set(dummy_path) + self.path_error['text'] = '' + def showerror(self, message, widget=None): + self.path_error['text'] = message + + @classmethod + def tearDownClass(cls): + query.platform = orig_platform + + def test_path_ok_blank(self): + dialog = self.Dummy_HelpSource(' ') + self.assertEqual(dialog.path_ok(), None) + self.assertIn('no help file', dialog.path_error['text']) + + def test_path_ok_bad(self): + dialog = self.Dummy_HelpSource(__file__ + 'bad-bad-bad') + self.assertEqual(dialog.path_ok(), None) + self.assertIn('not exist', dialog.path_error['text']) + + def test_path_ok_web(self): + dialog = self.Dummy_HelpSource('') + Equal = self.assertEqual + for url in 'www.py.org', 'http://py.org': + with self.subTest(): + dialog.path.set(url) + self.assertEqual(dialog.path_ok(), url) + self.assertEqual(dialog.path_error['text'], '') + + def test_path_ok_file(self): + dialog = self.Dummy_HelpSource('') + for platform, prefix in ('darwin', 'file://'), ('other', ''): + with self.subTest(): + query.platform = platform + dialog.path.set(__file__) + self.assertEqual(dialog.path_ok(), prefix + __file__) + self.assertEqual(dialog.path_error['text'], '') + + +class HelpsourceEntryokTest(unittest.TestCase): + "Test entry_ok method of HelpSource subclass of Query." + + class Dummy_HelpSource: + entry_ok = query.HelpSource.entry_ok + entry_error = {} + path_error = {} + def item_ok(self): + return self.name + def path_ok(self): + return self.path + + def test_entry_ok_helpsource(self): + dialog = self.Dummy_HelpSource() + for name, path, result in ((None, None, None), + (None, 'doc.txt', None), + ('doc', None, None), + ('doc', 'doc.txt', ('doc', 'doc.txt'))): + with self.subTest(): + dialog.name, dialog.path = name, path + self.assertEqual(dialog.entry_ok(), result) + + +# GUI TESTS + +class QueryGuiTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + requires('gui') + cls.root = root = Tk() ++ cls.root.withdraw() + cls.dialog = query.Query(root, 'TEST', 'test', _utest=True) + cls.dialog.destroy = mock.Mock() + + @classmethod + def tearDownClass(cls): + del cls.dialog + cls.root.destroy() + del cls.root + + def setUp(self): + self.dialog.entry.delete(0, 'end') + self.dialog.result = None + self.dialog.destroy.reset_mock() + + def test_click_ok(self): + dialog = self.dialog + dialog.entry.insert(0, 'abc') + dialog.button_ok.invoke() + self.assertEqual(dialog.result, 'abc') + self.assertTrue(dialog.destroy.called) + + def test_click_blank(self): + dialog = self.dialog + dialog.button_ok.invoke() + self.assertEqual(dialog.result, None) + self.assertFalse(dialog.destroy.called) + + def test_click_cancel(self): + dialog = self.dialog + dialog.entry.insert(0, 'abc') + dialog.button_cancel.invoke() + self.assertEqual(dialog.result, None) + self.assertTrue(dialog.destroy.called) + + +class SectionnameGuiTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + requires('gui') + + def test_click_section_name(self): + root = Tk() ++ root.withdraw() + dialog = query.SectionName(root, 'T', 't', {'abc'}, _utest=True) + Equal = self.assertEqual + self.assertEqual(dialog.used_names, {'abc'}) + dialog.entry.insert(0, 'okay') + dialog.button_ok.invoke() + self.assertEqual(dialog.result, 'okay') + del dialog + root.destroy() + del root + + +class ModulenameGuiTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + requires('gui') + + def test_click_module_name(self): + root = Tk() ++ root.withdraw() + dialog = query.ModuleName(root, 'T', 't', 'idlelib', _utest=True) + self.assertEqual(dialog.text0, 'idlelib') + self.assertEqual(dialog.entry.get(), 'idlelib') + dialog.button_ok.invoke() + self.assertTrue(dialog.result.endswith('__init__.py')) + del dialog + root.destroy() + del root + + +class HelpsourceGuiTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + requires('gui') + + def test_click_help_source(self): + root = Tk() ++ root.withdraw() + dialog = query.HelpSource(root, 'T', menuitem='__test__', + filepath=__file__, _utest=True) + Equal = self.assertEqual + Equal(dialog.entry.get(), '__test__') + Equal(dialog.path.get(), __file__) + dialog.button_ok.invoke() + prefix = "file://" if sys.platform == 'darwin' else '' + Equal(dialog.result, ('__test__', prefix + __file__)) + del dialog + root.destroy() + del root + + +if __name__ == '__main__': + unittest.main(verbosity=2, exit=False) diff --cc Lib/idlelib/idle_test/test_textview.py index c1edcb040c,5d2e60019d..f018f5ef19 --- a/Lib/idlelib/idle_test/test_textview.py +++ b/Lib/idlelib/idle_test/test_textview.py @@@ -59,11 -60,11 +60,11 @@@ class TextViewTest(unittest.TestCase) view.destroy = Func() view.Ok() self.assertTrue(view.destroy.called) - del view.destroy # unmask real function - view.destroy + del view.destroy # Unmask real function. + view.destroy() -class textviewTest(unittest.TestCase): +class ViewFunctionTest(unittest.TestCase): @classmethod def setUpClass(cls): @@@ -72,13 -73,14 +73,14 @@@ @classmethod def tearDownClass(cls): - tv.tkMessageBox = cls.orig_mbox - del cls.orig_mbox + tv.showerror = cls.orig_error + del cls.orig_error def test_view_text(self): - # If modal True, tkinter will error with 'can't invoke "event" command' + # If modal True, get tk error 'can't invoke "event" command'. view = tv.view_text(root, 'Title', 'test text', modal=False) self.assertIsInstance(view, tv.TextViewer) + view.Ok() def test_view_file(self): test_dir = os.path.dirname(__file__) @@@ -88,7 -90,7 +90,7 @@@ self.assertIn('Test', view.textView.get('1.0', '1.end')) view.Ok() - # Mock showerror will be used and view_file will return None - # Mock messagebox will be used and view_file will not return anything ++ # Mock showerror will be used; view_file will return None. testfile = os.path.join(test_dir, '../notthere.py') view = tv.view_file(root, 'Title', testfile, modal=False) self.assertIsNone(view)