1 """Test idlelib.query. 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 Coverage: 94% (100% for Query and SectionName). 13 6 of 8 missing are ModuleName exceptions I don't know how to trigger. 14 """ 15 from test.support import requires 16 import sys 17 from tkinter import Tk 18 import unittest 19 from unittest import mock 20 from idlelib.idle_test.mock_tk import Var 21 from idlelib import query 22 23 24 # NON-GUI TESTS 25 26 class QueryTest(unittest.TestCase): 27 "Test Query base class." 28 29 class Dummy_Query: 30 # Test the following Query methods. 31 entry_ok = query.Query.entry_ok 32 ok = query.Query.ok 33 cancel = query.Query.cancel 34 # Add attributes and initialization needed for tests. 35 entry = Var() 36 entry_error = {} 37 def __init__(self, dummy_entry): 38 self.entry.set(dummy_entry) 39 self.entry_error['text'] = '' 40 self.result = None 41 self.destroyed = False 42 def showerror(self, message): 43 self.entry_error['text'] = message 44 def destroy(self): 45 self.destroyed = True 46 47 def test_entry_ok_blank(self): 48 dialog = self.Dummy_Query(' ') 49 self.assertEqual(dialog.entry_ok(), None) 50 self.assertEqual((dialog.result, dialog.destroyed), (None, False)) 51 self.assertIn('blank line', dialog.entry_error['text']) 52 53 def test_entry_ok_good(self): 54 dialog = self.Dummy_Query(' good ') 55 Equal = self.assertEqual 56 Equal(dialog.entry_ok(), 'good') 57 Equal((dialog.result, dialog.destroyed), (None, False)) 58 Equal(dialog.entry_error['text'], '') 59 60 def test_ok_blank(self): 61 dialog = self.Dummy_Query('') 62 dialog.entry.focus_set = mock.Mock() 63 self.assertEqual(dialog.ok(), None) 64 self.assertTrue(dialog.entry.focus_set.called) 65 del dialog.entry.focus_set 66 self.assertEqual((dialog.result, dialog.destroyed), (None, False)) 67 68 def test_ok_good(self): 69 dialog = self.Dummy_Query('good') 70 self.assertEqual(dialog.ok(), None) 71 self.assertEqual((dialog.result, dialog.destroyed), ('good', True)) 72 73 def test_cancel(self): 74 dialog = self.Dummy_Query('does not matter') 75 self.assertEqual(dialog.cancel(), None) 76 self.assertEqual((dialog.result, dialog.destroyed), (None, True)) 77 78 79 class SectionNameTest(unittest.TestCase): 80 "Test SectionName subclass of Query." 81 82 class Dummy_SectionName: 83 entry_ok = query.SectionName.entry_ok # Function being tested. 84 used_names = ['used'] 85 entry = Var() 86 entry_error = {} 87 def __init__(self, dummy_entry): 88 self.entry.set(dummy_entry) 89 self.entry_error['text'] = '' 90 def showerror(self, message): 91 self.entry_error['text'] = message 92 93 def test_blank_section_name(self): 94 dialog = self.Dummy_SectionName(' ') 95 self.assertEqual(dialog.entry_ok(), None) 96 self.assertIn('no name', dialog.entry_error['text']) 97 98 def test_used_section_name(self): 99 dialog = self.Dummy_SectionName('used') 100 self.assertEqual(dialog.entry_ok(), None) 101 self.assertIn('use', dialog.entry_error['text']) 102 103 def test_long_section_name(self): 104 dialog = self.Dummy_SectionName('good'*8) 105 self.assertEqual(dialog.entry_ok(), None) 106 self.assertIn('longer than 30', dialog.entry_error['text']) 107 108 def test_good_section_name(self): 109 dialog = self.Dummy_SectionName(' good ') 110 self.assertEqual(dialog.entry_ok(), 'good') 111 self.assertEqual(dialog.entry_error['text'], '') 112 113 114 class ModuleNameTest(unittest.TestCase): 115 "Test ModuleName subclass of Query." 116 117 class Dummy_ModuleName: 118 entry_ok = query.ModuleName.entry_ok # Function being tested. 119 text0 = '' 120 entry = Var() 121 entry_error = {} 122 def __init__(self, dummy_entry): 123 self.entry.set(dummy_entry) 124 self.entry_error['text'] = '' 125 def showerror(self, message): 126 self.entry_error['text'] = message 127 128 def test_blank_module_name(self): 129 dialog = self.Dummy_ModuleName(' ') 130 self.assertEqual(dialog.entry_ok(), None) 131 self.assertIn('no name', dialog.entry_error['text']) 132 133 def test_bogus_module_name(self): 134 dialog = self.Dummy_ModuleName('__name_xyz123_should_not_exist__') 135 self.assertEqual(dialog.entry_ok(), None) 136 self.assertIn('not found', dialog.entry_error['text']) 137 138 def test_c_source_name(self): 139 dialog = self.Dummy_ModuleName('itertools') 140 self.assertEqual(dialog.entry_ok(), None) 141 self.assertIn('source-based', dialog.entry_error['text']) 142 143 def test_good_module_name(self): 144 dialog = self.Dummy_ModuleName('idlelib') 145 self.assertTrue(dialog.entry_ok().endswith('__init__.py')) 146 self.assertEqual(dialog.entry_error['text'], '') 147 148 149 # 3 HelpSource test classes each test one function. 150 151 orig_platform = query.platform 152 153 class HelpsourceBrowsefileTest(unittest.TestCase): 154 "Test browse_file method of ModuleName subclass of Query." 155 156 class Dummy_HelpSource: 157 browse_file = query.HelpSource.browse_file 158 pathvar = Var() 159 160 def test_file_replaces_path(self): 161 dialog = self.Dummy_HelpSource() 162 # Path is widget entry, either '' or something. 163 # Func return is file dialog return, either '' or something. 164 # Func return should override widget entry. 165 # We need all 4 combination to test all (most) code paths. 166 for path, func, result in ( 167 ('', lambda a,b,c:'', ''), 168 ('', lambda a,b,c: __file__, __file__), 169 ('htest', lambda a,b,c:'', 'htest'), 170 ('htest', lambda a,b,c: __file__, __file__)): 171 with self.subTest(): 172 dialog.pathvar.set(path) 173 dialog.askfilename = func 174 dialog.browse_file() 175 self.assertEqual(dialog.pathvar.get(), result) 176 177 178 class HelpsourcePathokTest(unittest.TestCase): 179 "Test path_ok method of HelpSource subclass of Query." 180 181 class Dummy_HelpSource: 182 path_ok = query.HelpSource.path_ok 183 path = Var() 184 path_error = {} 185 def __init__(self, dummy_path): 186 self.path.set(dummy_path) 187 self.path_error['text'] = '' 188 def showerror(self, message, widget=None): 189 self.path_error['text'] = message 190 191 @classmethod 192 def tearDownClass(cls): 193 query.platform = orig_platform 194 195 def test_path_ok_blank(self): 196 dialog = self.Dummy_HelpSource(' ') 197 self.assertEqual(dialog.path_ok(), None) 198 self.assertIn('no help file', dialog.path_error['text']) 199 200 def test_path_ok_bad(self): 201 dialog = self.Dummy_HelpSource(__file__ + 'bad-bad-bad') 202 self.assertEqual(dialog.path_ok(), None) 203 self.assertIn('not exist', dialog.path_error['text']) 204 205 def test_path_ok_web(self): 206 dialog = self.Dummy_HelpSource('') 207 Equal = self.assertEqual 208 for url in 'www.py.org', 'http://py.org': 209 with self.subTest(): 210 dialog.path.set(url) 211 self.assertEqual(dialog.path_ok(), url) 212 self.assertEqual(dialog.path_error['text'], '') 213 214 def test_path_ok_file(self): 215 dialog = self.Dummy_HelpSource('') 216 for platform, prefix in ('darwin', 'file://'), ('other', ''): 217 with self.subTest(): 218 query.platform = platform 219 dialog.path.set(__file__) 220 self.assertEqual(dialog.path_ok(), prefix + __file__) 221 self.assertEqual(dialog.path_error['text'], '') 222 223 224 class HelpsourceEntryokTest(unittest.TestCase): 225 "Test entry_ok method of HelpSource subclass of Query." 226 227 class Dummy_HelpSource: 228 entry_ok = query.HelpSource.entry_ok 229 entry_error = {} 230 path_error = {} 231 def item_ok(self): 232 return self.name 233 def path_ok(self): 234 return self.path 235 236 def test_entry_ok_helpsource(self): 237 dialog = self.Dummy_HelpSource() 238 for name, path, result in ((None, None, None), 239 (None, 'doc.txt', None), 240 ('doc', None, None), 241 ('doc', 'doc.txt', ('doc', 'doc.txt'))): 242 with self.subTest(): 243 dialog.name, dialog.path = name, path 244 self.assertEqual(dialog.entry_ok(), result) 245 246 247 # GUI TESTS 248 249 class QueryGuiTest(unittest.TestCase): 250 251 @classmethod 252 def setUpClass(cls): 253 requires('gui') 254 cls.root = root = Tk() 255 cls.root.withdraw() 256 cls.dialog = query.Query(root, 'TEST', 'test', _utest=True) 257 cls.dialog.destroy = mock.Mock() 258 259 @classmethod 260 def tearDownClass(cls): 261 del cls.dialog 262 cls.root.destroy() 263 del cls.root 264 265 def setUp(self): 266 self.dialog.entry.delete(0, 'end') 267 self.dialog.result = None 268 self.dialog.destroy.reset_mock() 269 270 def test_click_ok(self): 271 dialog = self.dialog 272 dialog.entry.insert(0, 'abc') 273 dialog.button_ok.invoke() 274 self.assertEqual(dialog.result, 'abc') 275 self.assertTrue(dialog.destroy.called) 276 277 def test_click_blank(self): 278 dialog = self.dialog 279 dialog.button_ok.invoke() 280 self.assertEqual(dialog.result, None) 281 self.assertFalse(dialog.destroy.called) 282 283 def test_click_cancel(self): 284 dialog = self.dialog 285 dialog.entry.insert(0, 'abc') 286 dialog.button_cancel.invoke() 287 self.assertEqual(dialog.result, None) 288 self.assertTrue(dialog.destroy.called) 289 290 291 class SectionnameGuiTest(unittest.TestCase): 292 293 @classmethod 294 def setUpClass(cls): 295 requires('gui') 296 297 def test_click_section_name(self): 298 root = Tk() 299 root.withdraw() 300 dialog = query.SectionName(root, 'T', 't', {'abc'}, _utest=True) 301 Equal = self.assertEqual 302 self.assertEqual(dialog.used_names, {'abc'}) 303 dialog.entry.insert(0, 'okay') 304 dialog.button_ok.invoke() 305 self.assertEqual(dialog.result, 'okay') 306 del dialog 307 root.destroy() 308 del root 309 310 311 class ModulenameGuiTest(unittest.TestCase): 312 313 @classmethod 314 def setUpClass(cls): 315 requires('gui') 316 317 def test_click_module_name(self): 318 root = Tk() 319 root.withdraw() 320 dialog = query.ModuleName(root, 'T', 't', 'idlelib', _utest=True) 321 self.assertEqual(dialog.text0, 'idlelib') 322 self.assertEqual(dialog.entry.get(), 'idlelib') 323 dialog.button_ok.invoke() 324 self.assertTrue(dialog.result.endswith('__init__.py')) 325 del dialog 326 root.destroy() 327 del root 328 329 330 class HelpsourceGuiTest(unittest.TestCase): 331 332 @classmethod 333 def setUpClass(cls): 334 requires('gui') 335 336 def test_click_help_source(self): 337 root = Tk() 338 root.withdraw() 339 dialog = query.HelpSource(root, 'T', menuitem='__test__', 340 filepath=__file__, _utest=True) 341 Equal = self.assertEqual 342 Equal(dialog.entry.get(), '__test__') 343 Equal(dialog.path.get(), __file__) 344 dialog.button_ok.invoke() 345 prefix = "file://" if sys.platform == 'darwin' else '' 346 Equal(dialog.result, ('__test__', prefix + __file__)) 347 del dialog 348 root.destroy() 349 del root 350 351 352 if __name__ == '__main__': 353 unittest.main(verbosity=2, exit=False) 354