bpo-33855: Still more edits and minimal tests for IDLE (GH-7784)

Part 3 of 3, continuing PR #7689. This covers 14 idlelib modules and their tests,
rpc to zoomheight except for run (already done) and tooltip (being done separately).
This commit is contained in:
Terry Jan Reedy 2018-06-19 19:12:52 -04:00 committed by GitHub
parent 00f9edb98d
commit 4d92158f4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 358 additions and 97 deletions

View File

@ -92,5 +92,5 @@ class AutoExpand:
if __name__ == '__main__':
import unittest
unittest.main('idlelib.idle_test.test_autoexpand', verbosity=2)
from unittest import main
main('idlelib.idle_test.test_autoexpand', verbosity=2)

View File

@ -233,6 +233,8 @@ class CodeContext:
CodeContext.reload()
if __name__ == "__main__": # pragma: no cover
import unittest
unittest.main('idlelib.idle_test.test_codecontext', verbosity=2, exit=False)
if __name__ == "__main__":
from unittest import main
main('idlelib.idle_test.test_codecontext', verbosity=2, exit=False)
# Add htest.

View File

@ -925,7 +925,7 @@ def _dump(): # htest # (not really, but ignore in coverage)
print('\nlines = ', line, ', crc = ', crc, sep='')
if __name__ == '__main__':
import unittest
unittest.main('idlelib.idle_test.test_config',
verbosity=2, exit=False)
#_dump()
from unittest import main
main('idlelib.idle_test.test_config', verbosity=2, exit=False)
# Run revised _dump() as htest?

View File

@ -291,8 +291,8 @@ class GetKeysDialog(Toplevel):
if __name__ == '__main__':
import unittest
unittest.main('idlelib.idle_test.test_config_key', verbosity=2, exit=False)
from unittest import main
main('idlelib.idle_test.test_config_key', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(GetKeysDialog)

View File

@ -2269,8 +2269,8 @@ class VerticalScrolledFrame(Frame):
if __name__ == '__main__':
import unittest
unittest.main('idlelib.idle_test.test_configdialog',
verbosity=2, exit=False)
from unittest import main
main('idlelib.idle_test.test_configdialog', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(ConfigDialog)

View File

@ -2,10 +2,10 @@
from idlelib import codecontext
import unittest
from unittest import mock
from test.support import requires
from tkinter import Tk, Frame, Text, TclError
from unittest import mock
import re
from idlelib import config

View File

@ -0,0 +1,30 @@
"Test rpc, coverage 20%."
from idlelib import rpc
import unittest
import marshal
class CodePicklerTest(unittest.TestCase):
def test_pickle_unpickle(self):
def f(): return a + b + c
func, (cbytes,) = rpc.pickle_code(f.__code__)
self.assertIs(func, rpc.unpickle_code)
self.assertIn(b'test_rpc.py', cbytes)
code = rpc.unpickle_code(cbytes)
self.assertEqual(code.co_names, ('a', 'b', 'c'))
def test_code_pickler(self):
self.assertIn(type((lambda:None).__code__),
rpc.CodePickler.dispatch_table)
def test_dumps(self):
def f(): pass
# The main test here is that pickling code does not raise.
self.assertIn(b'test_rpc.py', rpc.dumps(f.__code__))
if __name__ == '__main__':
unittest.main(verbosity=2)

View File

@ -1,5 +1,7 @@
"Test rstrip, coverage 100%."
from idlelib import rstrip
import unittest
import idlelib.rstrip as rs
from idlelib.idle_test.mock_idle import Editor
class rstripTest(unittest.TestCase):
@ -7,7 +9,7 @@ class rstripTest(unittest.TestCase):
def test_rstrip_line(self):
editor = Editor()
text = editor.text
do_rstrip = rs.RstripExtension(editor).do_rstrip
do_rstrip = rstrip.RstripExtension(editor).do_rstrip
do_rstrip()
self.assertEqual(text.get('1.0', 'insert'), '')
@ -20,12 +22,12 @@ class rstripTest(unittest.TestCase):
def test_rstrip_multiple(self):
editor = Editor()
# Uncomment following to verify that test passes with real widgets.
## from idlelib.editor import EditorWindow as Editor
## from tkinter import Tk
## editor = Editor(root=Tk())
# Comment above, uncomment 3 below to test with real Editor & Text.
#from idlelib.editor import EditorWindow as Editor
#from tkinter import Tk
#editor = Editor(root=Tk())
text = editor.text
do_rstrip = rs.RstripExtension(editor).do_rstrip
do_rstrip = rstrip.RstripExtension(editor).do_rstrip
original = (
"Line with an ending tab \n"
@ -45,5 +47,7 @@ class rstripTest(unittest.TestCase):
do_rstrip()
self.assertEqual(text.get('1.0', 'insert'), stripped)
if __name__ == '__main__':
unittest.main(verbosity=2, exit=False)
unittest.main(verbosity=2)

View File

@ -0,0 +1,33 @@
"Test runscript, coverage 16%."
from idlelib import runscript
import unittest
from test.support import requires
from tkinter import Tk
from idlelib.editor import EditorWindow
class ScriptBindingTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
requires('gui')
cls.root = Tk()
cls.root.withdraw()
@classmethod
def tearDownClass(cls):
cls.root.update_idletasks()
for id in cls.root.tk.call('after', 'info'):
cls.root.after_cancel(id) # Need for EditorWindow.
cls.root.destroy()
del cls.root
def test_init(self):
ew = EditorWindow(root=self.root)
sb = runscript.ScriptBinding(ew)
ew._close()
if __name__ == '__main__':
unittest.main(verbosity=2)

View File

@ -1,11 +1,9 @@
''' Test idlelib.scrolledlist.
"Test scrolledlist, coverage 38%."
Coverage: 39%
'''
from idlelib import scrolledlist
from idlelib.scrolledlist import ScrolledList
import unittest
from test.support import requires
requires('gui')
import unittest
from tkinter import Tk
@ -22,7 +20,7 @@ class ScrolledListTest(unittest.TestCase):
def test_init(self):
scrolledlist.ScrolledList(self.root)
ScrolledList(self.root)
if __name__ == '__main__':

View File

@ -1,25 +1,23 @@
"""Test SearchDialog class in idlelib.search.py"""
"Test search, coverage 69%."
from idlelib import search
import unittest
from test.support import requires
requires('gui')
from tkinter import Tk, Text, BooleanVar
from idlelib import searchengine
# Does not currently test the event handler wrappers.
# A usage test should simulate clicks and check highlighting.
# Tests need to be coordinated with SearchDialogBase tests
# to avoid duplication.
from test.support import requires
requires('gui')
import unittest
import tkinter as tk
from tkinter import BooleanVar
import idlelib.searchengine as se
import idlelib.search as sd
class SearchDialogTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.root = tk.Tk()
cls.root = Tk()
@classmethod
def tearDownClass(cls):
@ -27,10 +25,10 @@ class SearchDialogTest(unittest.TestCase):
del cls.root
def setUp(self):
self.engine = se.SearchEngine(self.root)
self.dialog = sd.SearchDialog(self.root, self.engine)
self.engine = searchengine.SearchEngine(self.root)
self.dialog = search.SearchDialog(self.root, self.engine)
self.dialog.bell = lambda: None
self.text = tk.Text(self.root)
self.text = Text(self.root)
self.text.insert('1.0', 'Hello World!')
def test_find_again(self):

View File

@ -1,8 +1,7 @@
'''tests idlelib.searchbase.
"Test searchbase, coverage 98%."
# The only thing not covered is inconsequential --
# testing skipping of suite when self.needwrapbutton is false.
Coverage: 99%. The only thing not covered is inconsequential --
testing skipping of suite when self.needwrapbutton is false.
'''
import unittest
from test.support import requires
from tkinter import Tk, Frame ##, BooleanVar, StringVar
@ -22,6 +21,7 @@ from idlelib.idle_test.mock_idle import Func
## se.BooleanVar = BooleanVar
## se.StringVar = StringVar
class SearchDialogBaseTest(unittest.TestCase):
@classmethod

View File

@ -1,18 +1,19 @@
'''Test functions and SearchEngine class in idlelib.searchengine.py.'''
"Test searchengine, coverage 99%."
from idlelib import searchengine as se
import unittest
# from test.support import requires
from tkinter import BooleanVar, StringVar, TclError # ,Tk, Text
import tkinter.messagebox as tkMessageBox
from idlelib.idle_test.mock_tk import Var, Mbox
from idlelib.idle_test.mock_tk import Text as mockText
import re
# With mock replacements, the module does not use any gui widgets.
# The use of tk.Text is avoided (for now, until mock Text is improved)
# by patching instances with an index function returning what is needed.
# This works because mock Text.get does not use .index.
import re
import unittest
# from test.support import requires
from tkinter import BooleanVar, StringVar, TclError # ,Tk, Text
import tkinter.messagebox as tkMessageBox
from idlelib import searchengine as se
from idlelib.idle_test.mock_tk import Var, Mbox
from idlelib.idle_test.mock_tk import Text as mockText
# The tkinter imports are used to restore searchengine.
def setUpModule():
# Replace s-e module tkinter imports other than non-gui TclError.
@ -326,4 +327,4 @@ class ForwardBackwardTest(unittest.TestCase):
if __name__ == '__main__':
unittest.main(verbosity=2, exit=2)
unittest.main(verbosity=2)

View File

@ -0,0 +1,36 @@
"Test stackviewer, coverage 19%."
from idlelib import stackviewer
import unittest
from test.support import requires
from tkinter import Tk
class Test(unittest.TestCase):
@classmethod
def setUpClass(cls):
requires('gui')
cls.root = Tk()
cls.root.withdraw()
@classmethod
def tearDownClass(cls):
cls.root.update_idletasks()
## for id in cls.root.tk.call('after', 'info'):
## cls.root.after_cancel(id) # Need for EditorWindow.
cls.root.destroy()
del cls.root
def test_init(self):
try:
zzz
except NameError as e:
ex = e
# Test runners suppress setting of sys.last_xyx, which stackviewer needs.
# Revise stackviewer so following works.
# stackviewer.StackBrowser(self.root, ex=exc)
if __name__ == '__main__':
unittest.main(verbosity=2)

View File

@ -0,0 +1,41 @@
"Test statusbar, coverage 100%."
from idlelib import statusbar
import unittest
from test.support import requires
from tkinter import Tk
class Test(unittest.TestCase):
@classmethod
def setUpClass(cls):
requires('gui')
cls.root = Tk()
cls.root.withdraw()
@classmethod
def tearDownClass(cls):
cls.root.update_idletasks()
cls.root.destroy()
del cls.root
def test_init(self):
bar = statusbar.MultiStatusBar(self.root)
self.assertEqual(bar.labels, {})
def test_set_label(self):
bar = statusbar.MultiStatusBar(self.root)
bar.set_label('left', text='sometext', width=10)
self.assertIn('left', bar.labels)
left = bar.labels['left']
self.assertEqual(left['text'], 'sometext')
self.assertEqual(left['width'], 10)
bar.set_label('left', text='revised text')
self.assertEqual(left['text'], 'revised text')
bar.set_label('right', text='correct text')
self.assertEqual(bar.labels['right']['text'], 'correct text')
if __name__ == '__main__':
unittest.main(verbosity=2)

View File

@ -1,17 +1,15 @@
'''Test idlelib.textview.
"""Test textview, coverage 100%.
Since all methods and functions create (or destroy) a ViewWindow, which
is a widget containing a widget, etcetera, all tests must be gui tests.
Using mock Text would not change this. Other mocks are used to retrieve
information about calls.
Coverage: 100%.
'''
"""
from idlelib import textview as tv
import unittest
from test.support import requires
requires('gui')
import unittest
import os
from tkinter import Tk
from tkinter.ttk import Button
@ -109,7 +107,7 @@ class ViewFunctionTest(unittest.TestCase):
view = tv.view_text(root, 'Title', 'test text', modal=False)
self.assertIsInstance(view, tv.ViewWindow)
self.assertIsInstance(view.viewframe, tv.ViewFrame)
view.ok()
view.viewframe.ok()
def test_view_file(self):
view = tv.view_file(root, 'Title', __file__, 'ascii', modal=False)

View File

@ -1,11 +1,9 @@
''' Test idlelib.tree.
"Test tree. coverage 56%."
Coverage: 56%
'''
from idlelib import tree
import unittest
from test.support import requires
requires('gui')
import unittest
from tkinter import Tk

View File

@ -1,14 +1,13 @@
"""Unittest for UndoDelegator in idlelib.undo.py.
"Test undo, coverage 77%."
# Only test UndoDelegator so far.
Coverage about 80% (retest).
"""
from idlelib.undo import UndoDelegator
import unittest
from test.support import requires
requires('gui')
import unittest
from unittest.mock import Mock
from tkinter import Text, Tk
from idlelib.undo import UndoDelegator
from idlelib.percolator import Percolator
@ -131,5 +130,6 @@ class UndoDelegatorTest(unittest.TestCase):
text.insert('insert', 'foo')
self.assertLessEqual(len(self.delegator.undolist), max_undo)
if __name__ == '__main__':
unittest.main(verbosity=2, exit=False)

View File

@ -5,20 +5,18 @@ This file could be expanded to include traceback overrides
Revise if output destination changes (http://bugs.python.org/issue18318).
Make sure warnings module is left unaltered (http://bugs.python.org/issue18081).
'''
from idlelib import run
from idlelib import pyshell as shell
import unittest
from test.support import captured_stderr
import warnings
# Try to capture default showwarning before Idle modules are imported.
showwarning = warnings.showwarning
# But if we run this file within idle, we are in the middle of the run.main loop
# and default showwarnings has already been replaced.
running_in_idle = 'idle' in showwarning.__name__
from idlelib import run
from idlelib import pyshell as shell
# The following was generated from pyshell.idle_formatwarning
# and checked as matching expectation.
idlemsg = '''
@ -29,6 +27,7 @@ UserWarning: Test
'''
shellmsg = idlemsg + ">>> "
class RunWarnTest(unittest.TestCase):
@unittest.skipIf(running_in_idle, "Does not work when run within Idle.")
@ -46,6 +45,7 @@ class RunWarnTest(unittest.TestCase):
# The following uses .splitlines to erase line-ending differences
self.assertEqual(idlemsg.splitlines(), f.getvalue().splitlines())
class ShellWarnTest(unittest.TestCase):
@unittest.skipIf(running_in_idle, "Does not work when run within Idle.")
@ -70,4 +70,4 @@ class ShellWarnTest(unittest.TestCase):
if __name__ == '__main__':
unittest.main(verbosity=2, exit=False)
unittest.main(verbosity=2)

View File

@ -0,0 +1,45 @@
"Test windows, coverage 47%."
from idlelib import windows
import unittest
from test.support import requires
from tkinter import Tk
class WindowListTest(unittest.TestCase):
def test_init(self):
wl = windows.WindowList()
self.assertEqual(wl.dict, {})
self.assertEqual(wl.callbacks, [])
# Further tests need mock Window.
class ListedToplevelTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
windows.registry = set()
requires('gui')
cls.root = Tk()
cls.root.withdraw()
@classmethod
def tearDownClass(cls):
windows.registry = windows.WindowList()
cls.root.update_idletasks()
## for id in cls.root.tk.call('after', 'info'):
## cls.root.after_cancel(id) # Need for EditorWindow.
cls.root.destroy()
del cls.root
def test_init(self):
win = windows.ListedToplevel(self.root)
self.assertIn(win, windows.registry)
self.assertEqual(win.focused_widget, win)
if __name__ == '__main__':
unittest.main(verbosity=2)

View File

@ -0,0 +1,39 @@
"Test zoomheight, coverage 66%."
# Some code is system dependent.
from idlelib import zoomheight
import unittest
from test.support import requires
from tkinter import Tk, Text
from idlelib.editor import EditorWindow
class Test(unittest.TestCase):
@classmethod
def setUpClass(cls):
requires('gui')
cls.root = Tk()
cls.root.withdraw()
cls.editwin = EditorWindow(root=cls.root)
@classmethod
def tearDownClass(cls):
cls.editwin._close()
cls.root.update_idletasks()
for id in cls.root.tk.call('after', 'info'):
cls.root.after_cancel(id) # Need for EditorWindow.
cls.root.destroy()
del cls.root
def test_init(self):
zoom = zoomheight.ZoomHeight(self.editwin)
self.assertIs(zoom.editwin, self.editwin)
def test_zoom_height_event(self):
zoom = zoomheight.ZoomHeight(self.editwin)
zoom.zoom_height_event()
if __name__ == '__main__':
unittest.main(verbosity=2)

View File

@ -184,5 +184,5 @@ class OnDemandOutputWindow:
self.write = self.owin.write
if __name__ == '__main__':
import unittest
unittest.main('idlelib.idle_test.test_outwin', verbosity=2, exit=False)
from unittest import main
main('idlelib.idle_test.test_outwin', verbosity=2, exit=False)

View File

@ -43,16 +43,20 @@ import traceback
import types
def unpickle_code(ms):
"Return code object from marshal string ms."
co = marshal.loads(ms)
assert isinstance(co, types.CodeType)
return co
def pickle_code(co):
"Return unpickle function and tuple with marshalled co code object."
assert isinstance(co, types.CodeType)
ms = marshal.dumps(co)
return unpickle_code, (ms,)
def dumps(obj, protocol=None):
"Return pickled (or marshalled) string for obj."
# IDLE passes 'None' to select pickle.DEFAULT_PROTOCOL.
f = io.BytesIO()
p = CodePickler(f, protocol)
p.dump(obj)
@ -625,3 +629,8 @@ def displayhook(value):
sys.stdout.write(text)
sys.stdout.write("\n")
builtins._ = value
if __name__ == '__main__':
from unittest import main
main('idlelib.idle_test.test_rpc', verbosity=2,)

View File

@ -25,5 +25,5 @@ class RstripExtension:
undo.undo_block_stop()
if __name__ == "__main__":
import unittest
unittest.main('idlelib.idle_test.test_rstrip', verbosity=2, exit=False)
from unittest import main
main('idlelib.idle_test.test_rstrip', verbosity=2,)

View File

@ -193,3 +193,8 @@ class ScriptBinding:
# XXX This should really be a function of EditorWindow...
tkMessageBox.showerror(title, message, parent=self.editwin.text)
self.editwin.text.focus_set()
if __name__ == "__main__":
from unittest import main
main('idlelib.idle_test.test_runscript', verbosity=2,)

View File

@ -142,6 +142,8 @@ def _scrolled_list(parent): # htest #
scrolled_list.append("Item %02d" % i)
if __name__ == '__main__':
# At the moment, test_scrolledlist merely creates instance, like htest.
from unittest import main
main('idlelib.idle_test.test_scrolledlist', verbosity=2,)
from idlelib.idle_test.htest import run
run(_scrolled_list)

View File

@ -94,9 +94,8 @@ def _search_dialog(parent): # htest #
button.pack()
if __name__ == '__main__':
import unittest
unittest.main('idlelib.idle_test.test_search',
verbosity=2, exit=False)
from unittest import main
main('idlelib.idle_test.test_search', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_search_dialog)

View File

@ -192,9 +192,10 @@ class _searchbase(SearchDialogBase): # htest #
def default_command(self, dummy): pass
if __name__ == '__main__':
import unittest
unittest.main('idlelib.idle_test.test_searchbase', verbosity=2, exit=False)
from unittest import main
main('idlelib.idle_test.test_searchbase', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_searchbase)

View File

@ -231,6 +231,7 @@ def get_line_col(index):
line, col = map(int, index.split(".")) # Fails on invalid index
return line, col
if __name__ == "__main__":
import unittest
unittest.main('idlelib.idle_test.test_searchengine', verbosity=2, exit=False)
from unittest import main
main('idlelib.idle_test.test_searchengine', verbosity=2)

View File

@ -148,5 +148,8 @@ def _stack_viewer(parent): # htest #
del sys.last_traceback
if __name__ == '__main__':
from unittest import main
main('idlelib.idle_test.test_stackviewer', verbosity=2)
from idlelib.idle_test.htest import run
run(_stack_viewer)

View File

@ -42,5 +42,8 @@ def _multistatus_bar(parent): # htest #
frame.pack()
if __name__ == '__main__':
from unittest import main
main('idlelib.idle_test.test_statusbar', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_multistatus_bar)

View File

@ -130,7 +130,8 @@ def view_file(parent, title, filename, encoding, modal=True, _utest=False):
if __name__ == '__main__':
import unittest
unittest.main('idlelib.idle_test.test_textview', verbosity=2, exit=False)
from unittest import main
main('idlelib.idle_test.test_textview', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(ViewWindow)

View File

@ -462,6 +462,8 @@ def _tree_widget(parent): # htest #
node.expand()
if __name__ == '__main__':
# test_tree is currently a copy of this
from unittest import main
main('idlelib.idle_test.test_tree', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_tree_widget)

View File

@ -359,8 +359,8 @@ def _undo_delegator(parent): # htest #
dump.pack(side='left')
if __name__ == "__main__":
import unittest
unittest.main('idlelib.idle_test.test_undo', verbosity=2, exit=False)
from unittest import main
main('idlelib.idle_test.test_undo', verbosity=2, exit=False)
from idlelib.idle_test.htest import run
run(_undo_delegator)

View File

@ -90,3 +90,8 @@ class ListedToplevel(Toplevel):
# This can happen when the window menu was torn off.
# Simply ignore it.
pass
if __name__ == "__main__":
from unittest import main
main('idlelib.idle_test.test_windows', verbosity=2)

View File

@ -11,7 +11,7 @@ class ZoomHeight:
def __init__(self, editwin):
self.editwin = editwin
def zoom_height_event(self, event):
def zoom_height_event(self, event=None):
top = self.editwin.top
zoom_height(top)
return "break"
@ -46,3 +46,10 @@ def zoom_height(top):
else:
newgeom = "%dx%d+%d+%d" % (width, newheight, x, newy)
top.wm_geometry(newgeom)
if __name__ == "__main__":
from unittest import main
main('idlelib.idle_test.test_zoomheight', verbosity=2, exit=False)
# Add htest?