ยปCore Development>Code coverage>Lib/idlelib/idle_test/htest.py

Python code coverage for Lib/idlelib/idle_test/htest.py

#countcontent
1n/a'''Run human tests of Idle's window, dialog, and popup widgets.
2n/a
3n/arun(*tests)
4n/aCreate a master Tk window. Within that, run each callable in tests
5n/aafter finding the matching test spec in this file. If tests is empty,
6n/arun an htest for each spec dict in this file after finding the matching
7n/acallable in the module named in the spec. Close the window to skip or
8n/aend the test.
9n/a
10n/aIn a tested module, let X be a global name bound to a callable (class
11n/aor function) whose .__name__ attrubute is also X (the usual situation).
12n/aThe first parameter of X must be 'parent'. When called, the parent
13n/aargument will be the root window. X must create a child Toplevel
14n/awindow (or subclass thereof). The Toplevel may be a test widget or
15n/adialog, in which case the callable is the corresonding class. Or the
16n/aToplevel may contain the widget to be tested or set up a context in
17n/awhich a test widget is invoked. In this latter case, the callable is a
18n/awrapper function that sets up the Toplevel and other objects. Wrapper
19n/afunction names, such as _editor_window', should start with '_'.
20n/a
21n/a
22n/aEnd the module with
23n/a
24n/aif __name__ == '__main__':
25n/a <unittest, if there is one>
26n/a from idlelib.idle_test.htest import run
27n/a run(X)
28n/a
29n/aTo have wrapper functions and test invocation code ignored by coveragepy
30n/areports, put '# htest #' on the def statement header line.
31n/a
32n/adef _wrapper(parent): # htest #
33n/a
34n/aAlso make sure that the 'if __name__' line matches the above. Then have
35n/amake sure that .coveragerc includes the following.
36n/a
37n/a[report]
38n/aexclude_lines =
39n/a .*# htest #
40n/a if __name__ == .__main__.:
41n/a
42n/a(The "." instead of "'" is intentional and necessary.)
43n/a
44n/a
45n/aTo run any X, this file must contain a matching instance of the
46n/afollowing template, with X.__name__ prepended to '_spec'.
47n/aWhen all tests are run, the prefix is use to get X.
48n/a
49n/a_spec = {
50n/a 'file': '',
51n/a 'kwds': {'title': ''},
52n/a 'msg': ""
53n/a }
54n/a
55n/afile (no .py): run() imports file.py.
56n/akwds: augmented with {'parent':root} and passed to X as **kwds.
57n/atitle: an example kwd; some widgets need this, delete if not.
58n/amsg: master window hints about testing the widget.
59n/a
60n/a
61n/aModules and classes not being tested at the moment:
62n/apyshell.PyShellEditorWindow
63n/adebugger.Debugger
64n/aautocomplete_w.AutoCompleteWindow
65n/aoutwin.OutputWindow (indirectly being tested with grep test)
66n/a'''
67n/a
68n/afrom importlib import import_module
69n/aimport tkinter as tk
70n/afrom tkinter.ttk import Scrollbar
71n/atk.NoDefaultRoot()
72n/a
73n/aAboutDialog_spec = {
74n/a 'file': 'help_about',
75n/a 'kwds': {'title': 'help_about test',
76n/a '_htest': True,
77n/a },
78n/a 'msg': "Test every button. Ensure Python, TK and IDLE versions "
79n/a "are correctly displayed.\n [Close] to exit.",
80n/a }
81n/a
82n/a_calltip_window_spec = {
83n/a 'file': 'calltip_w',
84n/a 'kwds': {},
85n/a 'msg': "Typing '(' should display a calltip.\n"
86n/a "Typing ') should hide the calltip.\n"
87n/a }
88n/a
89n/a_class_browser_spec = {
90n/a 'file': 'browser',
91n/a 'kwds': {},
92n/a 'msg': "Inspect names of module, class(with superclass if "
93n/a "applicable), methods and functions.\nToggle nested items.\n"
94n/a "Double clicking on items prints a traceback for an exception "
95n/a "that is ignored."
96n/a }
97n/a
98n/a_color_delegator_spec = {
99n/a 'file': 'colorizer',
100n/a 'kwds': {},
101n/a 'msg': "The text is sample Python code.\n"
102n/a "Ensure components like comments, keywords, builtins,\n"
103n/a "string, definitions, and break are correctly colored.\n"
104n/a "The default color scheme is in idlelib/config-highlight.def"
105n/a }
106n/a
107n/aConfigDialog_spec = {
108n/a 'file': 'configdialog',
109n/a 'kwds': {'title': 'ConfigDialogTest',
110n/a '_htest': True,},
111n/a 'msg': "IDLE preferences dialog.\n"
112n/a "In the 'Fonts/Tabs' tab, changing font face, should update the "
113n/a "font face of the text in the area below it.\nIn the "
114n/a "'Highlighting' tab, try different color schemes. Clicking "
115n/a "items in the sample program should update the choices above it."
116n/a "\nIn the 'Keys', 'General' and 'Extensions' tabs, test settings"
117n/a "of interest."
118n/a "\n[Ok] to close the dialog.[Apply] to apply the settings and "
119n/a "and [Cancel] to revert all changes.\nRe-run the test to ensure "
120n/a "changes made have persisted."
121n/a }
122n/a
123n/a# TODO Improve message
124n/a_dyn_option_menu_spec = {
125n/a 'file': 'dynoption',
126n/a 'kwds': {},
127n/a 'msg': "Select one of the many options in the 'old option set'.\n"
128n/a "Click the button to change the option set.\n"
129n/a "Select one of the many options in the 'new option set'."
130n/a }
131n/a
132n/a# TODO edit wrapper
133n/a_editor_window_spec = {
134n/a 'file': 'editor',
135n/a 'kwds': {},
136n/a 'msg': "Test editor functions of interest.\n"
137n/a "Best to close editor first."
138n/a }
139n/a
140n/a# Update once issue21519 is resolved.
141n/aGetKeysDialog_spec = {
142n/a 'file': 'config_key',
143n/a 'kwds': {'title': 'Test keybindings',
144n/a 'action': 'find-again',
145n/a 'currentKeySequences': [''] ,
146n/a '_htest': True,
147n/a },
148n/a 'msg': "Test for different key modifier sequences.\n"
149n/a "<nothing> is invalid.\n"
150n/a "No modifier key is invalid.\n"
151n/a "Shift key with [a-z],[0-9], function key, move key, tab, space"
152n/a "is invalid.\nNo validity checking if advanced key binding "
153n/a "entry is used."
154n/a }
155n/a
156n/a_grep_dialog_spec = {
157n/a 'file': 'grep',
158n/a 'kwds': {},
159n/a 'msg': "Click the 'Show GrepDialog' button.\n"
160n/a "Test the various 'Find-in-files' functions.\n"
161n/a "The results should be displayed in a new '*Output*' window.\n"
162n/a "'Right-click'->'Goto file/line' anywhere in the search results "
163n/a "should open that file \nin a new EditorWindow."
164n/a }
165n/a
166n/aHelpSource_spec = {
167n/a 'file': 'query',
168n/a 'kwds': {'title': 'Help name and source',
169n/a 'menuitem': 'test',
170n/a 'filepath': __file__,
171n/a 'used_names': {'abc'},
172n/a '_htest': True},
173n/a 'msg': "Enter menu item name and help file path\n"
174n/a "'', > than 30 chars, and 'abc' are invalid menu item names.\n"
175n/a "'' and file does not exist are invalid path items.\n"
176n/a "Any url ('www...', 'http...') is accepted.\n"
177n/a "Test Browse with and without path, as cannot unittest.\n"
178n/a "[Ok] or <Return> prints valid entry to shell\n"
179n/a "[Cancel] or <Escape> prints None to shell"
180n/a }
181n/a
182n/a_io_binding_spec = {
183n/a 'file': 'iomenu',
184n/a 'kwds': {},
185n/a 'msg': "Test the following bindings.\n"
186n/a "<Control-o> to open file from dialog.\n"
187n/a "Edit the file.\n"
188n/a "<Control-p> to print the file.\n"
189n/a "<Control-s> to save the file.\n"
190n/a "<Alt-s> to save-as another file.\n"
191n/a "<Control-c> to save-copy-as another file.\n"
192n/a "Check that changes were saved by opening the file elsewhere."
193n/a }
194n/a
195n/a_multi_call_spec = {
196n/a 'file': 'multicall',
197n/a 'kwds': {},
198n/a 'msg': "The following actions should trigger a print to console or IDLE"
199n/a " Shell.\nEntering and leaving the text area, key entry, "
200n/a "<Control-Key>,\n<Alt-Key-a>, <Control-Key-a>, "
201n/a "<Alt-Control-Key-a>, \n<Control-Button-1>, <Alt-Button-1> and "
202n/a "focusing out of the window\nare sequences to be tested."
203n/a }
204n/a
205n/a_multistatus_bar_spec = {
206n/a 'file': 'statusbar',
207n/a 'kwds': {},
208n/a 'msg': "Ensure presence of multi-status bar below text area.\n"
209n/a "Click 'Update Status' to change the multi-status text"
210n/a }
211n/a
212n/a_object_browser_spec = {
213n/a 'file': 'debugobj',
214n/a 'kwds': {},
215n/a 'msg': "Double click on items upto the lowest level.\n"
216n/a "Attributes of the objects and related information "
217n/a "will be displayed side-by-side at each level."
218n/a }
219n/a
220n/a_path_browser_spec = {
221n/a 'file': 'pathbrowser',
222n/a 'kwds': {},
223n/a 'msg': "Test for correct display of all paths in sys.path.\n"
224n/a "Toggle nested items upto the lowest level.\n"
225n/a "Double clicking on an item prints a traceback\n"
226n/a "for an exception that is ignored."
227n/a }
228n/a
229n/a_percolator_spec = {
230n/a 'file': 'percolator',
231n/a 'kwds': {},
232n/a 'msg': "There are two tracers which can be toggled using a checkbox.\n"
233n/a "Toggling a tracer 'on' by checking it should print tracer"
234n/a "output to the console or to the IDLE shell.\n"
235n/a "If both the tracers are 'on', the output from the tracer which "
236n/a "was switched 'on' later, should be printed first\n"
237n/a "Test for actions like text entry, and removal."
238n/a }
239n/a
240n/aQuery_spec = {
241n/a 'file': 'query',
242n/a 'kwds': {'title': 'Query',
243n/a 'message': 'Enter something',
244n/a 'text0': 'Go',
245n/a '_htest': True},
246n/a 'msg': "Enter with <Return> or [Ok]. Print valid entry to Shell\n"
247n/a "Blank line, after stripping, is ignored\n"
248n/a "Close dialog with valid entry, <Escape>, [Cancel], [X]"
249n/a }
250n/a
251n/a
252n/a_replace_dialog_spec = {
253n/a 'file': 'replace',
254n/a 'kwds': {},
255n/a 'msg': "Click the 'Replace' button.\n"
256n/a "Test various replace options in the 'Replace dialog'.\n"
257n/a "Click [Close] or [X] to close the 'Replace Dialog'."
258n/a }
259n/a
260n/a_search_dialog_spec = {
261n/a 'file': 'search',
262n/a 'kwds': {},
263n/a 'msg': "Click the 'Search' button.\n"
264n/a "Test various search options in the 'Search dialog'.\n"
265n/a "Click [Close] or [X] to close the 'Search Dialog'."
266n/a }
267n/a
268n/a_searchbase_spec = {
269n/a 'file': 'searchbase',
270n/a 'kwds': {},
271n/a 'msg': "Check the appearance of the base search dialog\n"
272n/a "Its only action is to close."
273n/a }
274n/a
275n/a_scrolled_list_spec = {
276n/a 'file': 'scrolledlist',
277n/a 'kwds': {},
278n/a 'msg': "You should see a scrollable list of items\n"
279n/a "Selecting (clicking) or double clicking an item "
280n/a "prints the name to the console or Idle shell.\n"
281n/a "Right clicking an item will display a popup."
282n/a }
283n/a
284n/ashow_idlehelp_spec = {
285n/a 'file': 'help',
286n/a 'kwds': {},
287n/a 'msg': "If the help text displays, this works.\n"
288n/a "Text is selectable. Window is scrollable."
289n/a }
290n/a
291n/a_stack_viewer_spec = {
292n/a 'file': 'stackviewer',
293n/a 'kwds': {},
294n/a 'msg': "A stacktrace for a NameError exception.\n"
295n/a "Expand 'idlelib ...' and '<locals>'.\n"
296n/a "Check that exc_value, exc_tb, and exc_type are correct.\n"
297n/a }
298n/a
299n/a_tabbed_pages_spec = {
300n/a 'file': 'tabbedpages',
301n/a 'kwds': {},
302n/a 'msg': "Toggle between the two tabs 'foo' and 'bar'\n"
303n/a "Add a tab by entering a suitable name for it.\n"
304n/a "Remove an existing tab by entering its name.\n"
305n/a "Remove all existing tabs.\n"
306n/a "<nothing> is an invalid add page and remove page name.\n"
307n/a }
308n/a
309n/aTextViewer_spec = {
310n/a 'file': 'textview',
311n/a 'kwds': {'title': 'Test textview',
312n/a 'text':'The quick brown fox jumps over the lazy dog.\n'*35,
313n/a '_htest': True},
314n/a 'msg': "Test for read-only property of text.\n"
315n/a "Text is selectable. Window is scrollable.",
316n/a }
317n/a
318n/a_tooltip_spec = {
319n/a 'file': 'tooltip',
320n/a 'kwds': {},
321n/a 'msg': "Place mouse cursor over both the buttons\n"
322n/a "A tooltip should appear with some text."
323n/a }
324n/a
325n/a_tree_widget_spec = {
326n/a 'file': 'tree',
327n/a 'kwds': {},
328n/a 'msg': "The canvas is scrollable.\n"
329n/a "Click on folders upto to the lowest level."
330n/a }
331n/a
332n/a_undo_delegator_spec = {
333n/a 'file': 'undo',
334n/a 'kwds': {},
335n/a 'msg': "Click [Undo] to undo any action.\n"
336n/a "Click [Redo] to redo any action.\n"
337n/a "Click [Dump] to dump the current state "
338n/a "by printing to the console or the IDLE shell.\n"
339n/a }
340n/a
341n/a_widget_redirector_spec = {
342n/a 'file': 'redirector',
343n/a 'kwds': {},
344n/a 'msg': "Every text insert should be printed to the console."
345n/a "or the IDLE shell."
346n/a }
347n/a
348n/adef run(*tests):
349n/a root = tk.Tk()
350n/a root.title('IDLE htest')
351n/a root.resizable(0, 0)
352n/a
353n/a # a scrollable Label like constant width text widget.
354n/a frameLabel = tk.Frame(root, padx=10)
355n/a frameLabel.pack()
356n/a text = tk.Text(frameLabel, wrap='word')
357n/a text.configure(bg=root.cget('bg'), relief='flat', height=4, width=70)
358n/a scrollbar = Scrollbar(frameLabel, command=text.yview)
359n/a text.config(yscrollcommand=scrollbar.set)
360n/a scrollbar.pack(side='right', fill='y', expand=False)
361n/a text.pack(side='left', fill='both', expand=True)
362n/a
363n/a test_list = [] # List of tuples of the form (spec, callable widget)
364n/a if tests:
365n/a for test in tests:
366n/a test_spec = globals()[test.__name__ + '_spec']
367n/a test_spec['name'] = test.__name__
368n/a test_list.append((test_spec, test))
369n/a else:
370n/a for k, d in globals().items():
371n/a if k.endswith('_spec'):
372n/a test_name = k[:-5]
373n/a test_spec = d
374n/a test_spec['name'] = test_name
375n/a mod = import_module('idlelib.' + test_spec['file'])
376n/a test = getattr(mod, test_name)
377n/a test_list.append((test_spec, test))
378n/a
379n/a test_name = tk.StringVar(root)
380n/a callable_object = None
381n/a test_kwds = None
382n/a
383n/a def next_test():
384n/a
385n/a nonlocal test_name, callable_object, test_kwds
386n/a if len(test_list) == 1:
387n/a next_button.pack_forget()
388n/a test_spec, callable_object = test_list.pop()
389n/a test_kwds = test_spec['kwds']
390n/a test_kwds['parent'] = root
391n/a test_name.set('Test ' + test_spec['name'])
392n/a
393n/a text.configure(state='normal') # enable text editing
394n/a text.delete('1.0','end')
395n/a text.insert("1.0",test_spec['msg'])
396n/a text.configure(state='disabled') # preserve read-only property
397n/a
398n/a def run_test(_=None):
399n/a widget = callable_object(**test_kwds)
400n/a try:
401n/a print(widget.result)
402n/a except AttributeError:
403n/a pass
404n/a
405n/a def close(_=None):
406n/a root.destroy()
407n/a
408n/a button = tk.Button(root, textvariable=test_name,
409n/a default='active', command=run_test)
410n/a next_button = tk.Button(root, text="Next", command=next_test)
411n/a button.pack()
412n/a next_button.pack()
413n/a next_button.focus_set()
414n/a root.bind('<Key-Return>', run_test)
415n/a root.bind('<Key-Escape>', close)
416n/a
417n/a next_test()
418n/a root.mainloop()
419n/a
420n/aif __name__ == '__main__':
421n/a run()