blob: 3e24518a0f7008211745381b161af0cda3c0c9d7 [file] [log] [blame]
Terry Jan Reedy69361592014-05-15 20:50:10 -04001'''Run human tests of Idle's window, dialog, and popup widgets.
Terry Jan Reedy06313b72014-05-11 23:32:32 -04002
Terry Jan Reedy078b8a82014-06-01 00:30:34 -04003run(*tests)
Terry Jan Reedycd567362014-10-17 01:31:35 -04004Create a master Tk window. Within that, run each callable in tests
5after finding the matching test spec in this file. If tests is empty,
6run an htest for each spec dict in this file after finding the matching
7callable in the module named in the spec. Close the window to skip or
8end the test.
Terry Jan Reedy06313b72014-05-11 23:32:32 -04009
Terry Jan Reedycd567362014-10-17 01:31:35 -040010In a tested module, let X be a global name bound to a callable (class
11or function) whose .__name__ attrubute is also X (the usual situation).
12The first parameter of X must be 'parent'. When called, the parent
13argument will be the root window. X must create a child Toplevel
14window (or subclass thereof). The Toplevel may be a test widget or
15dialog, in which case the callable is the corresonding class. Or the
16Toplevel may contain the widget to be tested or set up a context in
17which a test widget is invoked. In this latter case, the callable is a
18wrapper function that sets up the Toplevel and other objects. Wrapper
19function names, such as _editor_window', should start with '_'.
20
21
Terry Jan Reedy078b8a82014-06-01 00:30:34 -040022End the module with
Terry Jan Reedy69361592014-05-15 20:50:10 -040023
Terry Jan Reedy06313b72014-05-11 23:32:32 -040024if __name__ == '__main__':
25 <unittest, if there is one>
26 from idlelib.idle_test.htest import run
27 run(X)
Terry Jan Reedy06313b72014-05-11 23:32:32 -040028
Terry Jan Reedycd567362014-10-17 01:31:35 -040029To have wrapper functions and test invocation code ignored by coveragepy
30reports, put '# htest #' on the def statement header line.
Terry Jan Reedy69361592014-05-15 20:50:10 -040031
Terry Jan Reedycd567362014-10-17 01:31:35 -040032def _wrapper(parent): # htest #
33
34Also make sure that the 'if __name__' line matches the above. Then have
35make sure that .coveragerc includes the following.
36
37[report]
38exclude_lines =
39 .*# htest #
40 if __name__ == .__main__.:
41
42(The "." instead of "'" is intentional and necessary.)
43
44
45To run any X, this file must contain a matching instance of the
46following template, with X.__name__ prepended to '_spec'.
47When all tests are run, the prefix is use to get X.
Terry Jan Reedy69361592014-05-15 20:50:10 -040048
Terry Jan Reedy06313b72014-05-11 23:32:32 -040049_spec = {
50 'file': '',
51 'kwds': {'title': ''},
52 'msg': ""
53 }
Terry Jan Reedy69361592014-05-15 20:50:10 -040054
Terry Jan Reedycd567362014-10-17 01:31:35 -040055file (no .py): run() imports file.py.
56kwds: augmented with {'parent':root} and passed to X as **kwds.
57title: an example kwd; some widgets need this, delete if not.
58msg: master window hints about testing the widget.
Terry Jan Reedy078b8a82014-06-01 00:30:34 -040059
Terry Jan Reedycd567362014-10-17 01:31:35 -040060
61Modules and classes not being tested at the moment:
Terry Jan Reedy078b8a82014-06-01 00:30:34 -040062PyShell.PyShellEditorWindow
63Debugger.Debugger
64AutoCompleteWindow.AutoCompleteWindow
65OutputWindow.OutputWindow (indirectly being tested with grep test)
Terry Jan Reedy06313b72014-05-11 23:32:32 -040066'''
Terry Jan Reedycd567362014-10-17 01:31:35 -040067
Terry Jan Reedy06313b72014-05-11 23:32:32 -040068from importlib import import_module
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -040069from idlelib.macosxSupport import _initializeTkVariantTests
Terry Jan Reedy06313b72014-05-11 23:32:32 -040070import tkinter as tk
71
Terry Jan Reedy06313b72014-05-11 23:32:32 -040072AboutDialog_spec = {
73 'file': 'aboutDialog',
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -040074 'kwds': {'title': 'aboutDialog test',
75 '_htest': True,
76 },
77 'msg': "Test every button. Ensure Python, TK and IDLE versions "
78 "are correctly displayed.\n [Close] to exit.",
Terry Jan Reedy078b8a82014-06-01 00:30:34 -040079 }
Terry Jan Reedy06313b72014-05-11 23:32:32 -040080
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -040081_calltip_window_spec = {
82 'file': 'CallTipWindow',
Terry Jan Reedyab4fd442014-05-19 00:12:10 -040083 'kwds': {},
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -040084 'msg': "Typing '(' should display a calltip.\n"
85 "Typing ') should hide the calltip.\n"
Terry Jan Reedyab4fd442014-05-19 00:12:10 -040086 }
87
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -040088_class_browser_spec = {
89 'file': 'ClassBrowser',
90 'kwds': {},
91 'msg': "Inspect names of module, class(with superclass if "
Terry Jan Reedya2fc99e2014-05-25 18:44:05 -040092 "applicable), methods and functions.\nToggle nested items.\n"
Terry Jan Reedy0a4d13e2014-05-27 03:30:54 -040093 "Double clicking on items prints a traceback for an exception "
94 "that is ignored."
95 }
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -040096
97_color_delegator_spec = {
98 'file': 'ColorDelegator',
99 'kwds': {},
100 'msg': "The text is sample Python code.\n"
101 "Ensure components like comments, keywords, builtins,\n"
102 "string, definitions, and break are correctly colored.\n"
103 "The default color scheme is in idlelib/config-highlight.def"
104 }
105
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -0400106ConfigDialog_spec = {
107 'file': 'configDialog',
Terry Jan Reedycd567362014-10-17 01:31:35 -0400108 'kwds': {'title': 'ConfigDialogTest',
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -0400109 '_htest': True,},
110 'msg': "IDLE preferences dialog.\n"
111 "In the 'Fonts/Tabs' tab, changing font face, should update the "
112 "font face of the text in the area below it.\nIn the "
113 "'Highlighting' tab, try different color schemes. Clicking "
114 "items in the sample program should update the choices above it."
Terry Jan Reedy93f35422015-10-13 22:03:51 -0400115 "\nIn the 'Keys', 'General' and 'Extensions' tabs, test settings"
116 "of interest."
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -0400117 "\n[Ok] to close the dialog.[Apply] to apply the settings and "
118 "and [Cancel] to revert all changes.\nRe-run the test to ensure "
119 "changes made have persisted."
120 }
121
Terry Jan Reedycd567362014-10-17 01:31:35 -0400122# TODO Improve message
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400123_dyn_option_menu_spec = {
124 'file': 'dynOptionMenuWidget',
125 'kwds': {},
126 'msg': "Select one of the many options in the 'old option set'.\n"
127 "Click the button to change the option set.\n"
128 "Select one of the many options in the 'new option set'."
129 }
130
Terry Jan Reedycd567362014-10-17 01:31:35 -0400131# TODO edit wrapper
Terry Jan Reedya2fc99e2014-05-25 18:44:05 -0400132_editor_window_spec = {
133 'file': 'EditorWindow',
134 'kwds': {},
Terry Jan Reedycd567362014-10-17 01:31:35 -0400135 'msg': "Test editor functions of interest.\n"
136 "Best to close editor first."
Terry Jan Reedya2fc99e2014-05-25 18:44:05 -0400137 }
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400138
Terry Jan Reedy06313b72014-05-11 23:32:32 -0400139GetCfgSectionNameDialog_spec = {
140 'file': 'configSectionNameDialog',
141 'kwds': {'title':'Get Name',
Terry Jan Reedyab4fd442014-05-19 00:12:10 -0400142 'message':'Enter something',
143 'used_names': {'abc'},
144 '_htest': True},
Terry Jan Reedy06313b72014-05-11 23:32:32 -0400145 'msg': "After the text entered with [Ok] is stripped, <nothing>, "
Terry Jan Reedyab4fd442014-05-19 00:12:10 -0400146 "'abc', or more that 30 chars are errors.\n"
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400147 "Close 'Get Name' with a valid entry (printed to Shell), "
148 "[Cancel], or [X]",
149 }
Terry Jan Reedya2fc99e2014-05-25 18:44:05 -0400150
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400151GetHelpSourceDialog_spec = {
152 'file': 'configHelpSourceEdit',
153 'kwds': {'title': 'Get helpsource',
154 '_htest': True},
155 'msg': "Enter menu item name and help file path\n "
156 "<nothing> and more than 30 chars are invalid menu item names.\n"
157 "<nothing>, file does not exist are invalid path items.\n"
158 "Test for incomplete web address for help file path.\n"
159 "A valid entry will be printed to shell with [0k].\n"
160 "[Cancel] will print None to shell",
Terry Jan Reedyab4fd442014-05-19 00:12:10 -0400161 }
162
Terry Jan Reedya2fc99e2014-05-25 18:44:05 -0400163# Update once issue21519 is resolved.
164GetKeysDialog_spec = {
165 'file': 'keybindingDialog',
166 'kwds': {'title': 'Test keybindings',
167 'action': 'find-again',
168 'currentKeySequences': [''] ,
169 '_htest': True,
170 },
171 'msg': "Test for different key modifier sequences.\n"
172 "<nothing> is invalid.\n"
173 "No modifier key is invalid.\n"
174 "Shift key with [a-z],[0-9], function key, move key, tab, space"
Berker Peksagf23530f2014-10-19 18:04:38 +0300175 "is invalid.\nNo validity checking if advanced key binding "
Terry Jan Reedya2fc99e2014-05-25 18:44:05 -0400176 "entry is used."
177 }
178
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -0400179_grep_dialog_spec = {
180 'file': 'GrepDialog',
181 'kwds': {},
182 'msg': "Click the 'Show GrepDialog' button.\n"
183 "Test the various 'Find-in-files' functions.\n"
184 "The results should be displayed in a new '*Output*' window.\n"
185 "'Right-click'->'Goto file/line' anywhere in the search results "
186 "should open that file \nin a new EditorWindow."
187 }
188
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400189_io_binding_spec = {
190 'file': 'IOBinding',
191 'kwds': {},
Terry Jan Reedybbdc0652015-10-30 02:47:06 -0400192 'msg': "Test the following bindings.\n"
193 "<Control-o> to open file from dialog.\n"
194 "Edit the file.\n"
195 "<Control-s> to save the file.\n"
196 "Check that changes were saved by opening the file elsewhere."
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400197 }
198
199_multi_call_spec = {
200 'file': 'MultiCall',
201 'kwds': {},
Terry Jan Reedya2fc99e2014-05-25 18:44:05 -0400202 'msg': "The following actions should trigger a print to console or IDLE"
203 " Shell.\nEntering and leaving the text area, key entry, "
204 "<Control-Key>,\n<Alt-Key-a>, <Control-Key-a>, "
205 "<Alt-Control-Key-a>, \n<Control-Button-1>, <Alt-Button-1> and "
206 "focusing out of the window\nare sequences to be tested."
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400207 }
208
209_multistatus_bar_spec = {
210 'file': 'MultiStatusBar',
211 'kwds': {},
212 'msg': "Ensure presence of multi-status bar below text area.\n"
213 "Click 'Update Status' to change the multi-status text"
214 }
215
216_object_browser_spec = {
217 'file': 'ObjectBrowser',
218 'kwds': {},
219 'msg': "Double click on items upto the lowest level.\n"
220 "Attributes of the objects and related information "
221 "will be displayed side-by-side at each level."
222 }
223
224_path_browser_spec = {
225 'file': 'PathBrowser',
226 'kwds': {},
Terry Jan Reedya2fc99e2014-05-25 18:44:05 -0400227 'msg': "Test for correct display of all paths in sys.path.\n"
228 "Toggle nested items upto the lowest level.\n"
229 "Double clicking on an item prints a traceback\n"
230 "for an exception that is ignored."
231 }
232
233_percolator_spec = {
234 'file': 'Percolator',
235 'kwds': {},
236 'msg': "There are two tracers which can be toggled using a checkbox.\n"
237 "Toggling a tracer 'on' by checking it should print tracer"
238 "output to the console or to the IDLE shell.\n"
239 "If both the tracers are 'on', the output from the tracer which "
240 "was switched 'on' later, should be printed first\n"
241 "Test for actions like text entry, and removal."
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400242 }
243
Terry Jan Reedy0a4d13e2014-05-27 03:30:54 -0400244_replace_dialog_spec = {
245 'file': 'ReplaceDialog',
246 'kwds': {},
247 'msg': "Click the 'Replace' button.\n"
248 "Test various replace options in the 'Replace dialog'.\n"
Terry Jan Reedy078b8a82014-06-01 00:30:34 -0400249 "Click [Close] or [X] to close the 'Replace Dialog'."
Terry Jan Reedy0a4d13e2014-05-27 03:30:54 -0400250 }
251
252_search_dialog_spec = {
253 'file': 'SearchDialog',
254 'kwds': {},
255 'msg': "Click the 'Search' button.\n"
256 "Test various search options in the 'Search dialog'.\n"
Terry Jan Reedy078b8a82014-06-01 00:30:34 -0400257 "Click [Close] or [X] to close the 'Search Dialog'."
Terry Jan Reedy0a4d13e2014-05-27 03:30:54 -0400258 }
259
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400260_scrolled_list_spec = {
261 'file': 'ScrolledList',
262 'kwds': {},
263 'msg': "You should see a scrollable list of items\n"
Terry Jan Reedya2fc99e2014-05-25 18:44:05 -0400264 "Selecting (clicking) or double clicking an item "
265 "prints the name to the console or Idle shell.\n"
266 "Right clicking an item will display a popup."
267 }
268
Terry Jan Reedy5d46ab12015-09-20 19:57:13 -0400269show_idlehelp_spec = {
270 'file': 'help',
271 'kwds': {},
272 'msg': "If the help text displays, this works.\n"
273 "Text is selectable. Window is scrollable."
274 }
275
Terry Jan Reedya2fc99e2014-05-25 18:44:05 -0400276_stack_viewer_spec = {
277 'file': 'StackViewer',
278 'kwds': {},
279 'msg': "A stacktrace for a NameError exception.\n"
280 "Expand 'idlelib ...' and '<locals>'.\n"
281 "Check that exc_value, exc_tb, and exc_type are correct.\n"
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400282 }
283
284_tabbed_pages_spec = {
285 'file': 'tabbedpages',
286 'kwds': {},
287 'msg': "Toggle between the two tabs 'foo' and 'bar'\n"
288 "Add a tab by entering a suitable name for it.\n"
289 "Remove an existing tab by entering its name.\n"
290 "Remove all existing tabs.\n"
291 "<nothing> is an invalid add page and remove page name.\n"
292 }
293
294TextViewer_spec = {
295 'file': 'textView',
296 'kwds': {'title': 'Test textView',
297 'text':'The quick brown fox jumps over the lazy dog.\n'*35,
298 '_htest': True},
299 'msg': "Test for read-only property of text.\n"
300 "Text is selectable. Window is scrollable.",
301 }
302
303_tooltip_spec = {
304 'file': 'ToolTip',
305 'kwds': {},
306 'msg': "Place mouse cursor over both the buttons\n"
307 "A tooltip should appear with some text."
308 }
309
310_tree_widget_spec = {
311 'file': 'TreeWidget',
312 'kwds': {},
Terry Jan Reedy0a4d13e2014-05-27 03:30:54 -0400313 'msg': "The canvas is scrollable.\n"
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400314 "Click on folders upto to the lowest level."
315 }
316
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -0400317_undo_delegator_spec = {
318 'file': 'UndoDelegator',
319 'kwds': {},
320 'msg': "Click [Undo] to undo any action.\n"
321 "Click [Redo] to redo any action.\n"
322 "Click [Dump] to dump the current state "
323 "by printing to the console or the IDLE shell.\n"
324 }
325
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400326_widget_redirector_spec = {
327 'file': 'WidgetRedirector',
328 'kwds': {},
Terry Jan Reedya2fc99e2014-05-25 18:44:05 -0400329 'msg': "Every text insert should be printed to the console."
330 "or the IDLE shell."
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400331 }
332
Terry Jan Reedya2fc99e2014-05-25 18:44:05 -0400333def run(*tests):
Terry Jan Reedy06313b72014-05-11 23:32:32 -0400334 root = tk.Tk()
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -0400335 root.title('IDLE htest')
336 root.resizable(0, 0)
337 _initializeTkVariantTests(root)
338
339 # a scrollable Label like constant width text widget.
340 frameLabel = tk.Frame(root, padx=10)
341 frameLabel.pack()
342 text = tk.Text(frameLabel, wrap='word')
343 text.configure(bg=root.cget('bg'), relief='flat', height=4, width=70)
344 scrollbar = tk.Scrollbar(frameLabel, command=text.yview)
345 text.config(yscrollcommand=scrollbar.set)
346 scrollbar.pack(side='right', fill='y', expand=False)
347 text.pack(side='left', fill='both', expand=True)
348
Terry Jan Reedya2fc99e2014-05-25 18:44:05 -0400349 test_list = [] # List of tuples of the form (spec, callable widget)
350 if tests:
351 for test in tests:
352 test_spec = globals()[test.__name__ + '_spec']
353 test_spec['name'] = test.__name__
354 test_list.append((test_spec, test))
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400355 else:
356 for k, d in globals().items():
357 if k.endswith('_spec'):
358 test_name = k[:-5]
359 test_spec = d
360 test_spec['name'] = test_name
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400361 mod = import_module('idlelib.' + test_spec['file'])
362 test = getattr(mod, test_name)
Terry Jan Reedya2fc99e2014-05-25 18:44:05 -0400363 test_list.append((test_spec, test))
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400364
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400365 test_name = tk.StringVar('')
366 callable_object = None
367 test_kwds = None
368
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400369 def next():
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -0400370
371 nonlocal test_name, callable_object, test_kwds
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400372 if len(test_list) == 1:
373 next_button.pack_forget()
Terry Jan Reedya2fc99e2014-05-25 18:44:05 -0400374 test_spec, callable_object = test_list.pop()
375 test_kwds = test_spec['kwds']
376 test_kwds['parent'] = root
Terry Jan Reedya2fc99e2014-05-25 18:44:05 -0400377 test_name.set('Test ' + test_spec['name'])
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400378
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -0400379 text.configure(state='normal') # enable text editing
380 text.delete('1.0','end')
381 text.insert("1.0",test_spec['msg'])
382 text.configure(state='disabled') # preserve read-only property
Terry Jan Reedy69361592014-05-15 20:50:10 -0400383
384 def run_test():
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400385 widget = callable_object(**test_kwds)
Terry Jan Reedy06313b72014-05-11 23:32:32 -0400386 try:
387 print(widget.result)
388 except AttributeError:
389 pass
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400390
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400391 button = tk.Button(root, textvariable=test_name, command=run_test)
392 button.pack()
393 next_button = tk.Button(root, text="Next", command=next)
394 next_button.pack()
395
396 next()
397
Terry Jan Reedy06313b72014-05-11 23:32:32 -0400398 root.mainloop()
399
Terry Jan Reedy06313b72014-05-11 23:32:32 -0400400if __name__ == '__main__':
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400401 run()