gh-66819: More IDLE htest updates(2) (#112642)

Examine and update spec -- callable pairs.
Revise run method.
This commit is contained in:
Terry Jan Reedy 2023-12-03 04:28:37 -05:00 committed by GitHub
parent a9574c68f0
commit 3855b45874
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 70 additions and 69 deletions

View File

@ -254,5 +254,6 @@ if __name__ == "__main__":
if len(sys.argv) == 1: # If pass file on command line, unittest fails.
from unittest import main
main('idlelib.idle_test.test_browser', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_module_browser)

View File

@ -120,7 +120,7 @@ def make_objecttreeitem(labeltext, object, setfunction=None):
return c(labeltext, object, setfunction)
def _object_browser(parent): # htest #
def _debug_object_browser(parent): # htest #
import sys
from tkinter import Toplevel
top = Toplevel(parent)
@ -140,4 +140,4 @@ if __name__ == '__main__':
main('idlelib.idle_test.test_debugobj', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_object_browser)
run(_debug_object_browser)

View File

@ -8,14 +8,15 @@ the master window to end testing.
In a tested module, let X be a global name bound to a callable (class or
function) whose .__name__ attribute is also X (the usual situation). The
first parameter of X must be 'parent'. When called, the parent argument
will be the root window. X must create a child Toplevel(parent) window
(or subclass thereof). The Toplevel may be a test widget or dialog, in
which case the callable is the corresponding class. Or the Toplevel may
contain the widget to be tested or set up a context in which a test
widget is invoked. In this latter case, the callable is a wrapper
function that sets up the Toplevel and other objects. Wrapper function
names, such as _editor_window', should start with '_' and be lowercase.
first parameter of X must be 'parent' or 'master'. When called, the
first argument will be the root window. X must create a child
Toplevel(parent/master) (or subclass thereof). The Toplevel may be a
test widget or dialog, in which case the callable is the corresponding
class. Or the Toplevel may contain the widget to be tested or set up a
context in which a test widget is invoked. In this latter case, the
callable is a wrapper function that sets up the Toplevel and other
objects. Wrapper function names, such as _editor_window', should start
with '_' and be lowercase.
End the module with
@ -117,12 +118,20 @@ CustomRun_spec = {
'file': 'query',
'kwds': {'title': 'Customize query.py Run',
'_htest': True},
'msg': "Enter with <Return> or [Run]. Print valid entry to Shell\n"
'msg': "Enter with <Return> or [OK]. Print valid entry to Shell\n"
"Arguments are parsed into a list\n"
"Mode is currently restart True or False\n"
"Close dialog with valid entry, <Escape>, [Cancel], [X]"
}
_debug_object_browser_spec = {
'file': 'debugobj',
'kwds': {},
'msg': "Double click on items up to the lowest level.\n"
"Attributes of the objects and related information "
"will be displayed side-by-side at each level."
}
# TODO Improve message
_dyn_option_menu_spec = {
'file': 'dynoption',
@ -178,7 +187,7 @@ HelpSource_spec = {
"Any url ('www...', 'http...') is accepted.\n"
"Test Browse with and without path, as cannot unittest.\n"
"[Ok] or <Return> prints valid entry to shell\n"
"[Cancel] or <Escape> prints None to shell"
"<Escape>, [Cancel], or [X] prints None to shell"
}
_io_binding_spec = {
@ -199,17 +208,17 @@ _linenumbers_drag_scrolling_spec = {
'kwds': {},
'msg': textwrap.dedent("""\
1. Click on the line numbers and drag down below the edge of the
window, moving the mouse a bit and then leaving it there for a while.
The text and line numbers should gradually scroll down, with the
selection updated continuously.
window, moving the mouse a bit and then leaving it there for a
while. The text and line numbers should gradually scroll down,
with the selection updated continuously.
2. With the lines still selected, click on a line number above the
selected lines. Only the line whose number was clicked should be
selected.
2. With the lines still selected, click on a line number above
or below the selected lines. Only the line whose number was
clicked should be selected.
3. Repeat step #1, dragging to above the window. The text and line
numbers should gradually scroll up, with the selection updated
continuously.
3. Repeat step #1, dragging to above the window. The text and
line numbers should gradually scroll up, with the selection
updated continuously.
4. Repeat step #2, clicking a line number below the selection."""),
}
@ -217,42 +226,33 @@ _linenumbers_drag_scrolling_spec = {
_multi_call_spec = {
'file': 'multicall',
'kwds': {},
'msg': "The following actions should trigger a print to console or IDLE"
" Shell.\nEntering and leaving the text area, key entry, "
"<Control-Key>,\n<Alt-Key-a>, <Control-Key-a>, "
"<Alt-Control-Key-a>, \n<Control-Button-1>, <Alt-Button-1> and "
"focusing out of the window\nare sequences to be tested."
'msg': "The following should trigger a print to console or IDLE Shell.\n"
"Entering and leaving the text area, key entry, <Control-Key>,\n"
"<Alt-Key-a>, <Control-Key-a>, <Alt-Control-Key-a>, \n"
"<Control-Button-1>, <Alt-Button-1> and focusing elsewhere."
}
_module_browser_spec = {
'file': 'browser',
'kwds': {},
'msg': "Inspect names of module, class(with superclass if "
"applicable), methods and functions.\nToggle nested items.\n"
"Double clicking on items prints a traceback for an exception "
"that is ignored."
'msg': textwrap.dedent("""
"Inspect names of module, class(with superclass if applicable),
"methods and functions. Toggle nested items. Double clicking
"on items prints a traceback for an exception that is ignored.""")
}
_multistatus_bar_spec = {
'file': 'statusbar',
'kwds': {},
'msg': "Ensure presence of multi-status bar below text area.\n"
"Click 'Update Status' to change the multi-status text"
"Click 'Update Status' to change the status text"
}
_object_browser_spec = {
'file': 'debugobj',
'kwds': {},
'msg': "Double click on items up to the lowest level.\n"
"Attributes of the objects and related information "
"will be displayed side-by-side at each level."
}
_path_browser_spec = {
PathBrowser_spec = {
'file': 'pathbrowser',
'kwds': {},
'kwds': {'_htest': True},
'msg': "Test for correct display of all paths in sys.path.\n"
"Toggle nested items up to the lowest level.\n"
"Toggle nested items out to the lowest level.\n"
"Double clicking on an item prints a traceback\n"
"for an exception that is ignored."
}
@ -367,11 +367,12 @@ _widget_redirector_spec = {
}
def run(*tests):
"Run callables in tests."
root = tk.Tk()
root.title('IDLE htest')
root.resizable(0, 0)
# a scrollable Label like constant width text widget.
# A scrollable Label-like constant width text widget.
frameLabel = tk.Frame(root, padx=10)
frameLabel.pack()
text = tk.Text(frameLabel, wrap='word')
@ -381,45 +382,44 @@ def run(*tests):
scrollbar.pack(side='right', fill='y', expand=False)
text.pack(side='left', fill='both', expand=True)
test_list = [] # List of tuples of the form (spec, callable widget)
test_list = [] # Make list of (spec, callable) tuples.
if tests:
for test in tests:
test_spec = globals()[test.__name__ + '_spec']
test_spec['name'] = test.__name__
test_list.append((test_spec, test))
else:
for k, d in globals().items():
if k.endswith('_spec'):
test_name = k[:-5]
test_spec = d
for key, dic in globals().items():
if key.endswith('_spec'):
test_name = key[:-5]
test_spec = dic
test_spec['name'] = test_name
mod = import_module('idlelib.' + test_spec['file'])
test = getattr(mod, test_name)
test_list.append((test_spec, test))
test_list.reverse() # So can pop in proper order in next_test.
test_name = tk.StringVar(root)
callable_object = None
test_kwds = None
def next_test():
nonlocal test_name, callable_object, test_kwds
if len(test_list) == 1:
next_button.pack_forget()
test_spec, callable_object = test_list.pop()
test_kwds = test_spec['kwds']
test_kwds['parent'] = root
test_name.set('Test ' + test_spec['name'])
text.configure(state='normal') # enable text editing
text.delete('1.0','end')
text.insert("1.0",test_spec['msg'])
text.configure(state='disabled') # preserve read-only property
text['state'] = 'normal' # Enable text replacement.
text.delete('1.0', 'end')
text.insert("1.0", test_spec['msg'])
text['state'] = 'disabled' # Restore read-only property.
def run_test(_=None):
widget = callable_object(**test_kwds)
widget = callable_object(root, **test_kwds)
try:
print(widget.result)
print(widget.result) # Only true for query classes(?).
except AttributeError:
pass

View File

@ -396,10 +396,11 @@ class IOBinding:
def _io_binding(parent): # htest #
from tkinter import Toplevel, Text
root = Toplevel(parent)
root.title("Test IOBinding")
top = Toplevel(parent)
top.title("Test IOBinding")
x, y = map(int, parent.geometry().split('+')[1:])
root.geometry("+%d+%d" % (x, y + 175))
top.geometry("+%d+%d" % (x, y + 175))
class MyEditWin:
def __init__(self, text):
self.text = text
@ -423,7 +424,7 @@ def _io_binding(parent): # htest #
def savecopy(self, event):
self.text.event_generate("<<save-copy-of-window-as-file>>")
text = Text(root)
text = Text(top)
text.pack()
text.focus_set()
editwin = MyEditWin(text)

View File

@ -421,6 +421,8 @@ def _multi_call(parent): # htest #
top.geometry("+%d+%d" % (x, y + 175))
text = MultiCallCreator(tkinter.Text)(top)
text.pack()
text.focus_set()
def bindseq(seq, n=[0]):
def handler(event):
print(seq)

View File

@ -99,13 +99,9 @@ class DirBrowserTreeItem(TreeItem):
return sorted
def _path_browser(parent): # htest #
PathBrowser(parent, _htest=True)
parent.mainloop()
if __name__ == "__main__":
from unittest import main
main('idlelib.idle_test.test_pathbrowser', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_path_browser)
run(PathBrowser)

View File

@ -368,7 +368,7 @@ class CustomRun(Query):
sticky='we')
def cli_args_ok(self):
"Validity check and parsing for command line arguments."
"Return command line arg list or None if error."
cli_string = self.entry.get().strip()
try:
cli_args = shlex.split(cli_string, posix=True)

View File

@ -516,13 +516,13 @@ class ShellSidebar(BaseSideBar):
def _linenumbers_drag_scrolling(parent): # htest #
from idlelib.idle_test.test_sidebar import Dummy_editwin
toplevel = tk.Toplevel(parent)
text_frame = tk.Frame(toplevel)
top = tk.Toplevel(parent)
text_frame = tk.Frame(top)
text_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
text_frame.rowconfigure(1, weight=1)
text_frame.columnconfigure(1, weight=1)
font = idleConf.GetFont(toplevel, 'main', 'EditorWindow')
font = idleConf.GetFont(top, 'main', 'EditorWindow')
text = tk.Text(text_frame, width=80, height=24, wrap=tk.NONE, font=font)
text.grid(row=1, column=1, sticky=tk.NSEW)

View File

@ -26,6 +26,7 @@ def _multistatus_bar(parent): # htest #
x, y = map(int, parent.geometry().split('+')[1:])
top.geometry("+%d+%d" %(x, y + 175))
top.title("Test multistatus bar")
frame = Frame(top)
text = Text(frame, height=5, width=40)
text.pack()