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