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