[3.12] gh-66819: More IDLE htest updates(2) (GH-112642) (#112643)

Examine and update spec -- callable pairs.
Revise run method.
(cherry picked from commit 3855b45874)

Co-authored-by: Terry Jan Reedy <tjreedy@udel.edu>
This commit is contained in:
Miss Islington (bot) 2023-12-03 17:34:08 +01:00 committed by GitHub
parent f5965c2385
commit ee3ef7f196
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. if len(sys.argv) == 1: # If pass file on command line, unittest fails.
from unittest import main from unittest import main
main('idlelib.idle_test.test_browser', verbosity=2, exit=False) main('idlelib.idle_test.test_browser', verbosity=2, exit=False)
from idlelib.idle_test.htest import run from idlelib.idle_test.htest import run
run(_module_browser) run(_module_browser)

View file

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

View file

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

View file

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

View file

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

View file

@ -368,7 +368,7 @@ class CustomRun(Query):
sticky='we') sticky='we')
def cli_args_ok(self): 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() cli_string = self.entry.get().strip()
try: try:
cli_args = shlex.split(cli_string, posix=True) cli_args = shlex.split(cli_string, posix=True)

View file

@ -517,13 +517,13 @@ class ShellSidebar(BaseSideBar):
def _linenumbers_drag_scrolling(parent): # htest # def _linenumbers_drag_scrolling(parent): # htest #
from idlelib.idle_test.test_sidebar import Dummy_editwin from idlelib.idle_test.test_sidebar import Dummy_editwin
toplevel = tk.Toplevel(parent) top = tk.Toplevel(parent)
text_frame = tk.Frame(toplevel) text_frame = tk.Frame(top)
text_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) text_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
text_frame.rowconfigure(1, weight=1) text_frame.rowconfigure(1, weight=1)
text_frame.columnconfigure(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 = tk.Text(text_frame, width=80, height=24, wrap=tk.NONE, font=font)
text.grid(row=1, column=1, sticky=tk.NSEW) 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:]) x, y = map(int, parent.geometry().split('+')[1:])
top.geometry("+%d+%d" %(x, y + 175)) top.geometry("+%d+%d" %(x, y + 175))
top.title("Test multistatus bar") top.title("Test multistatus bar")
frame = Frame(top) frame = Frame(top)
text = Text(frame, height=5, width=40) text = Text(frame, height=5, width=40)
text.pack() text.pack()