summaryrefslogtreecommitdiffstats
path: root/Lib/idlelib/idle_test/test_squeezer.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/idlelib/idle_test/test_squeezer.py')
-rw-r--r--Lib/idlelib/idle_test/test_squeezer.py311
1 files changed, 134 insertions, 177 deletions
diff --git a/Lib/idlelib/idle_test/test_squeezer.py b/Lib/idlelib/idle_test/test_squeezer.py
index da2c2dd..7c28a10 100644
--- a/Lib/idlelib/idle_test/test_squeezer.py
+++ b/Lib/idlelib/idle_test/test_squeezer.py
@@ -1,3 +1,5 @@
+"Test squeezer, coverage 95%"
+
from collections import namedtuple
from textwrap import dedent
from tkinter import Text, Tk
@@ -33,10 +35,10 @@ def get_test_tk_root(test_instance):
class CountLinesTest(unittest.TestCase):
"""Tests for the count_lines_with_wrapping function."""
- def check(self, expected, text, linewidth, tabwidth):
+ def check(self, expected, text, linewidth):
return self.assertEqual(
expected,
- count_lines_with_wrapping(text, linewidth, tabwidth),
+ count_lines_with_wrapping(text, linewidth),
)
def test_count_empty(self):
@@ -55,37 +57,14 @@ class CountLinesTest(unittest.TestCase):
"""Test with several lines of text."""
self.assertEqual(count_lines_with_wrapping("1\n2\n3\n"), 3)
- def test_tab_width(self):
- """Test with various tab widths and line widths."""
- self.check(expected=1, text='\t' * 1, linewidth=8, tabwidth=4)
- self.check(expected=1, text='\t' * 2, linewidth=8, tabwidth=4)
- self.check(expected=2, text='\t' * 3, linewidth=8, tabwidth=4)
- self.check(expected=2, text='\t' * 4, linewidth=8, tabwidth=4)
- self.check(expected=3, text='\t' * 5, linewidth=8, tabwidth=4)
-
- # test longer lines and various tab widths
- self.check(expected=4, text='\t' * 10, linewidth=12, tabwidth=4)
- self.check(expected=10, text='\t' * 10, linewidth=12, tabwidth=8)
- self.check(expected=2, text='\t' * 4, linewidth=10, tabwidth=3)
-
- # test tabwidth=1
- self.check(expected=2, text='\t' * 9, linewidth=5, tabwidth=1)
- self.check(expected=2, text='\t' * 10, linewidth=5, tabwidth=1)
- self.check(expected=3, text='\t' * 11, linewidth=5, tabwidth=1)
-
- # test for off-by-one errors
- self.check(expected=2, text='\t' * 6, linewidth=12, tabwidth=4)
- self.check(expected=3, text='\t' * 6, linewidth=11, tabwidth=4)
- self.check(expected=2, text='\t' * 6, linewidth=13, tabwidth=4)
-
def test_empty_lines(self):
- self.check(expected=1, text='\n', linewidth=80, tabwidth=8)
- self.check(expected=2, text='\n\n', linewidth=80, tabwidth=8)
- self.check(expected=10, text='\n' * 10, linewidth=80, tabwidth=8)
+ self.check(expected=1, text='\n', linewidth=80)
+ self.check(expected=2, text='\n\n', linewidth=80)
+ self.check(expected=10, text='\n' * 10, linewidth=80)
def test_long_line(self):
- self.check(expected=3, text='a' * 200, linewidth=80, tabwidth=8)
- self.check(expected=3, text='a' * 200 + '\n', linewidth=80, tabwidth=8)
+ self.check(expected=3, text='a' * 200, linewidth=80)
+ self.check(expected=3, text='a' * 200 + '\n', linewidth=80)
def test_several_lines_different_lengths(self):
text = dedent("""\
@@ -94,82 +73,78 @@ class CountLinesTest(unittest.TestCase):
7 chars
13 characters""")
- self.check(expected=5, text=text, linewidth=80, tabwidth=8)
- self.check(expected=5, text=text + '\n', linewidth=80, tabwidth=8)
- self.check(expected=6, text=text, linewidth=40, tabwidth=8)
- self.check(expected=7, text=text, linewidth=20, tabwidth=8)
- self.check(expected=11, text=text, linewidth=10, tabwidth=8)
+ self.check(expected=5, text=text, linewidth=80)
+ self.check(expected=5, text=text + '\n', linewidth=80)
+ self.check(expected=6, text=text, linewidth=40)
+ self.check(expected=7, text=text, linewidth=20)
+ self.check(expected=11, text=text, linewidth=10)
class SqueezerTest(unittest.TestCase):
"""Tests for the Squeezer class."""
- def make_mock_editor_window(self):
+ def tearDown(self):
+ # Clean up the Squeezer class's reference to its instance,
+ # to avoid side-effects from one test case upon another.
+ if Squeezer._instance_weakref is not None:
+ Squeezer._instance_weakref = None
+
+ def make_mock_editor_window(self, with_text_widget=False):
"""Create a mock EditorWindow instance."""
editwin = NonCallableMagicMock()
# isinstance(editwin, PyShell) must be true for Squeezer to enable
- # auto-squeezing; in practice this will always be true
+ # auto-squeezing; in practice this will always be true.
editwin.__class__ = PyShell
+
+ if with_text_widget:
+ editwin.root = get_test_tk_root(self)
+ text_widget = self.make_text_widget(root=editwin.root)
+ editwin.text = editwin.per.bottom = text_widget
+
return editwin
def make_squeezer_instance(self, editor_window=None):
"""Create an actual Squeezer instance with a mock EditorWindow."""
if editor_window is None:
editor_window = self.make_mock_editor_window()
- return Squeezer(editor_window)
+ squeezer = Squeezer(editor_window)
+ squeezer.get_line_width = Mock(return_value=80)
+ return squeezer
+
+ def make_text_widget(self, root=None):
+ if root is None:
+ root = get_test_tk_root(self)
+ text_widget = Text(root)
+ text_widget["font"] = ('Courier', 10)
+ text_widget.mark_set("iomark", "1.0")
+ return text_widget
+
+ def set_idleconf_option_with_cleanup(self, configType, section, option, value):
+ prev_val = idleConf.GetOption(configType, section, option)
+ idleConf.SetOption(configType, section, option, value)
+ self.addCleanup(idleConf.SetOption,
+ configType, section, option, prev_val)
def test_count_lines(self):
- """Test Squeezer.count_lines() with various inputs.
-
- This checks that Squeezer.count_lines() calls the
- count_lines_with_wrapping() function with the appropriate parameters.
- """
- for tabwidth, linewidth in [(4, 80), (1, 79), (8, 80), (3, 120)]:
- self._test_count_lines_helper(linewidth=linewidth,
- tabwidth=tabwidth)
-
- def _prepare_mock_editwin_for_count_lines(self, editwin,
- linewidth, tabwidth):
- """Prepare a mock EditorWindow object for Squeezer.count_lines."""
- CHAR_WIDTH = 10
- BORDER_WIDTH = 2
- PADDING_WIDTH = 1
-
- # Prepare all the required functionality on the mock EditorWindow object
- # so that the calculations in Squeezer.count_lines() can run.
- editwin.get_tk_tabwidth.return_value = tabwidth
- editwin.text.winfo_width.return_value = \
- linewidth * CHAR_WIDTH + 2 * (BORDER_WIDTH + PADDING_WIDTH)
- text_opts = {
- 'border': BORDER_WIDTH,
- 'padx': PADDING_WIDTH,
- 'font': None,
- }
- editwin.text.cget = lambda opt: text_opts[opt]
-
- # monkey-path tkinter.font.Font with a mock object, so that
- # Font.measure('0') returns CHAR_WIDTH
- mock_font = Mock()
- def measure(char):
- if char == '0':
- return CHAR_WIDTH
- raise ValueError("measure should only be called on '0'!")
- mock_font.return_value.measure = measure
- patcher = patch('idlelib.squeezer.Font', mock_font)
- patcher.start()
- self.addCleanup(patcher.stop)
-
- def _test_count_lines_helper(self, linewidth, tabwidth):
- """Helper for test_count_lines."""
+ """Test Squeezer.count_lines() with various inputs."""
editwin = self.make_mock_editor_window()
- self._prepare_mock_editwin_for_count_lines(editwin, linewidth, tabwidth)
squeezer = self.make_squeezer_instance(editwin)
- mock_count_lines = Mock(return_value=SENTINEL_VALUE)
- text = 'TEXT'
- with patch('idlelib.squeezer.count_lines_with_wrapping',
- mock_count_lines):
- self.assertIs(squeezer.count_lines(text), SENTINEL_VALUE)
- mock_count_lines.assert_called_with(text, linewidth, tabwidth)
+ for text_code, line_width, expected in [
+ (r"'\n'", 80, 1),
+ (r"'\n' * 3", 80, 3),
+ (r"'a' * 40 + '\n'", 80, 1),
+ (r"'a' * 80 + '\n'", 80, 1),
+ (r"'a' * 200 + '\n'", 80, 3),
+ (r"'aa\t' * 20", 80, 2),
+ (r"'aa\t' * 21", 80, 3),
+ (r"'aa\t' * 20", 40, 4),
+ ]:
+ with self.subTest(text_code=text_code,
+ line_width=line_width,
+ expected=expected):
+ text = eval(text_code)
+ squeezer.get_line_width.return_value = line_width
+ self.assertEqual(squeezer.count_lines(text), expected)
def test_init(self):
"""Test the creation of Squeezer instances."""
@@ -207,8 +182,6 @@ class SqueezerTest(unittest.TestCase):
def test_write_stdout(self):
"""Test Squeezer's overriding of the EditorWindow's write() method."""
editwin = self.make_mock_editor_window()
- self._prepare_mock_editwin_for_count_lines(editwin,
- linewidth=80, tabwidth=8)
for text in ['', 'TEXT']:
editwin.write = orig_write = Mock(return_value=SENTINEL_VALUE)
@@ -232,12 +205,8 @@ class SqueezerTest(unittest.TestCase):
def test_auto_squeeze(self):
"""Test that the auto-squeezing creates an ExpandingButton properly."""
- root = get_test_tk_root(self)
- text_widget = Text(root)
- text_widget.mark_set("iomark", "1.0")
-
- editwin = self.make_mock_editor_window()
- editwin.text = text_widget
+ editwin = self.make_mock_editor_window(with_text_widget=True)
+ text_widget = editwin.text
squeezer = self.make_squeezer_instance(editwin)
squeezer.auto_squeeze_min_lines = 5
squeezer.count_lines = Mock(return_value=6)
@@ -248,58 +217,48 @@ class SqueezerTest(unittest.TestCase):
def test_squeeze_current_text_event(self):
"""Test the squeeze_current_text event."""
- root = get_test_tk_root(self)
-
- # squeezing text should work for both stdout and stderr
+ # Squeezing text should work for both stdout and stderr.
for tag_name in ["stdout", "stderr"]:
- text_widget = Text(root)
- text_widget.mark_set("iomark", "1.0")
-
- editwin = self.make_mock_editor_window()
- editwin.text = editwin.per.bottom = text_widget
+ editwin = self.make_mock_editor_window(with_text_widget=True)
+ text_widget = editwin.text
squeezer = self.make_squeezer_instance(editwin)
squeezer.count_lines = Mock(return_value=6)
- # prepare some text in the Text widget
+ # Prepare some text in the Text widget.
text_widget.insert("1.0", "SOME\nTEXT\n", tag_name)
text_widget.mark_set("insert", "1.0")
self.assertEqual(text_widget.get('1.0', 'end'), 'SOME\nTEXT\n\n')
self.assertEqual(len(squeezer.expandingbuttons), 0)
- # test squeezing the current text
+ # Test squeezing the current text.
retval = squeezer.squeeze_current_text_event(event=Mock())
self.assertEqual(retval, "break")
self.assertEqual(text_widget.get('1.0', 'end'), '\n\n')
self.assertEqual(len(squeezer.expandingbuttons), 1)
self.assertEqual(squeezer.expandingbuttons[0].s, 'SOME\nTEXT')
- # test that expanding the squeezed text works and afterwards the
- # Text widget contains the original text
+ # Test that expanding the squeezed text works and afterwards
+ # the Text widget contains the original text.
squeezer.expandingbuttons[0].expand(event=Mock())
self.assertEqual(text_widget.get('1.0', 'end'), 'SOME\nTEXT\n\n')
self.assertEqual(len(squeezer.expandingbuttons), 0)
def test_squeeze_current_text_event_no_allowed_tags(self):
"""Test that the event doesn't squeeze text without a relevant tag."""
- root = get_test_tk_root(self)
-
- text_widget = Text(root)
- text_widget.mark_set("iomark", "1.0")
-
- editwin = self.make_mock_editor_window()
- editwin.text = editwin.per.bottom = text_widget
+ editwin = self.make_mock_editor_window(with_text_widget=True)
+ text_widget = editwin.text
squeezer = self.make_squeezer_instance(editwin)
squeezer.count_lines = Mock(return_value=6)
- # prepare some text in the Text widget
+ # Prepare some text in the Text widget.
text_widget.insert("1.0", "SOME\nTEXT\n", "TAG")
text_widget.mark_set("insert", "1.0")
self.assertEqual(text_widget.get('1.0', 'end'), 'SOME\nTEXT\n\n')
self.assertEqual(len(squeezer.expandingbuttons), 0)
- # test squeezing the current text
+ # Test squeezing the current text.
retval = squeezer.squeeze_current_text_event(event=Mock())
self.assertEqual(retval, "break")
self.assertEqual(text_widget.get('1.0', 'end'), 'SOME\nTEXT\n\n')
@@ -307,23 +266,18 @@ class SqueezerTest(unittest.TestCase):
def test_squeeze_text_before_existing_squeezed_text(self):
"""Test squeezing text before existing squeezed text."""
- root = get_test_tk_root(self)
-
- text_widget = Text(root)
- text_widget.mark_set("iomark", "1.0")
-
- editwin = self.make_mock_editor_window()
- editwin.text = editwin.per.bottom = text_widget
+ editwin = self.make_mock_editor_window(with_text_widget=True)
+ text_widget = editwin.text
squeezer = self.make_squeezer_instance(editwin)
squeezer.count_lines = Mock(return_value=6)
- # prepare some text in the Text widget and squeeze it
+ # Prepare some text in the Text widget and squeeze it.
text_widget.insert("1.0", "SOME\nTEXT\n", "stdout")
text_widget.mark_set("insert", "1.0")
squeezer.squeeze_current_text_event(event=Mock())
self.assertEqual(len(squeezer.expandingbuttons), 1)
- # test squeezing the current text
+ # Test squeezing the current text.
text_widget.insert("1.0", "MORE\nSTUFF\n", "stdout")
text_widget.mark_set("insert", "1.0")
retval = squeezer.squeeze_current_text_event(event=Mock())
@@ -336,27 +290,30 @@ class SqueezerTest(unittest.TestCase):
squeezer.expandingbuttons[1],
))
- GetOptionSignature = namedtuple('GetOptionSignature',
- 'configType section option default type warn_on_default raw')
- @classmethod
- def _make_sig(cls, configType, section, option, default=sentinel.NOT_GIVEN,
- type=sentinel.NOT_GIVEN,
- warn_on_default=sentinel.NOT_GIVEN,
- raw=sentinel.NOT_GIVEN):
- return cls.GetOptionSignature(configType, section, option, default,
- type, warn_on_default, raw)
-
- @classmethod
- def get_GetOption_signature(cls, mock_call_obj):
- args, kwargs = mock_call_obj[-2:]
- return cls._make_sig(*args, **kwargs)
-
def test_reload(self):
"""Test the reload() class-method."""
- self.assertIsInstance(Squeezer.auto_squeeze_min_lines, int)
- idleConf.SetOption('main', 'PyShell', 'auto-squeeze-min-lines', '42')
+ editwin = self.make_mock_editor_window(with_text_widget=True)
+ text_widget = editwin.text
+ squeezer = self.make_squeezer_instance(editwin)
+
+ orig_zero_char_width = squeezer.zero_char_width
+ orig_auto_squeeze_min_lines = squeezer.auto_squeeze_min_lines
+
+ # Increase both font size and auto-squeeze-min-lines.
+ text_widget["font"] = ('Courier', 20)
+ new_auto_squeeze_min_lines = orig_auto_squeeze_min_lines + 10
+ self.set_idleconf_option_with_cleanup(
+ 'main', 'PyShell', 'auto-squeeze-min-lines',
+ str(new_auto_squeeze_min_lines))
+
+ Squeezer.reload()
+ self.assertGreater(squeezer.zero_char_width, orig_zero_char_width)
+ self.assertEqual(squeezer.auto_squeeze_min_lines,
+ new_auto_squeeze_min_lines)
+
+ def test_reload_no_squeezer_instances(self):
+ """Test that Squeezer.reload() runs without any instances existing."""
Squeezer.reload()
- self.assertEqual(Squeezer.auto_squeeze_min_lines, 42)
class ExpandingButtonTest(unittest.TestCase):
@@ -369,7 +326,7 @@ class ExpandingButtonTest(unittest.TestCase):
squeezer = Mock()
squeezer.editwin.text = Text(root)
- # Set default values for the configuration settings
+ # Set default values for the configuration settings.
squeezer.auto_squeeze_min_lines = 50
return squeezer
@@ -382,23 +339,23 @@ class ExpandingButtonTest(unittest.TestCase):
expandingbutton = ExpandingButton('TEXT', 'TAGS', 50, squeezer)
self.assertEqual(expandingbutton.s, 'TEXT')
- # check that the underlying tkinter.Button is properly configured
+ # Check that the underlying tkinter.Button is properly configured.
self.assertEqual(expandingbutton.master, text_widget)
self.assertTrue('50 lines' in expandingbutton.cget('text'))
- # check that the text widget still contains no text
+ # Check that the text widget still contains no text.
self.assertEqual(text_widget.get('1.0', 'end'), '\n')
- # check that the mouse events are bound
+ # Check that the mouse events are bound.
self.assertIn('<Double-Button-1>', expandingbutton.bind())
right_button_code = '<Button-%s>' % ('2' if macosx.isAquaTk() else '3')
self.assertIn(right_button_code, expandingbutton.bind())
- # check that ToolTip was called once, with appropriate values
+ # Check that ToolTip was called once, with appropriate values.
self.assertEqual(MockHovertip.call_count, 1)
MockHovertip.assert_called_with(expandingbutton, ANY, hover_delay=ANY)
- # check that 'right-click' appears in the tooltip text
+ # Check that 'right-click' appears in the tooltip text.
tooltip_text = MockHovertip.call_args[0][1]
self.assertIn('right-click', tooltip_text.lower())
@@ -407,29 +364,30 @@ class ExpandingButtonTest(unittest.TestCase):
squeezer = self.make_mock_squeezer()
expandingbutton = ExpandingButton('TEXT', 'TAGS', 50, squeezer)
- # insert the button into the text widget
- # (this is normally done by the Squeezer class)
+ # Insert the button into the text widget
+ # (this is normally done by the Squeezer class).
text_widget = expandingbutton.text
text_widget.window_create("1.0", window=expandingbutton)
- # set base_text to the text widget, so that changes are actually made
- # to it (by ExpandingButton) and we can inspect these changes afterwards
+ # Set base_text to the text widget, so that changes are actually
+ # made to it (by ExpandingButton) and we can inspect these
+ # changes afterwards.
expandingbutton.base_text = expandingbutton.text
# trigger the expand event
retval = expandingbutton.expand(event=Mock())
self.assertEqual(retval, None)
- # check that the text was inserted into the text widget
+ # Check that the text was inserted into the text widget.
self.assertEqual(text_widget.get('1.0', 'end'), 'TEXT\n')
- # check that the 'TAGS' tag was set on the inserted text
+ # Check that the 'TAGS' tag was set on the inserted text.
text_end_index = text_widget.index('end-1c')
self.assertEqual(text_widget.get('1.0', text_end_index), 'TEXT')
self.assertEqual(text_widget.tag_nextrange('TAGS', '1.0'),
('1.0', text_end_index))
- # check that the button removed itself from squeezer.expandingbuttons
+ # Check that the button removed itself from squeezer.expandingbuttons.
self.assertEqual(squeezer.expandingbuttons.remove.call_count, 1)
squeezer.expandingbuttons.remove.assert_called_with(expandingbutton)
@@ -441,55 +399,54 @@ class ExpandingButtonTest(unittest.TestCase):
expandingbutton.set_is_dangerous()
self.assertTrue(expandingbutton.is_dangerous)
- # insert the button into the text widget
- # (this is normally done by the Squeezer class)
+ # Insert the button into the text widget
+ # (this is normally done by the Squeezer class).
text_widget = expandingbutton.text
text_widget.window_create("1.0", window=expandingbutton)
- # set base_text to the text widget, so that changes are actually made
- # to it (by ExpandingButton) and we can inspect these changes afterwards
+ # Set base_text to the text widget, so that changes are actually
+ # made to it (by ExpandingButton) and we can inspect these
+ # changes afterwards.
expandingbutton.base_text = expandingbutton.text
- # patch the message box module to always return False
+ # Patch the message box module to always return False.
with patch('idlelib.squeezer.tkMessageBox') as mock_msgbox:
mock_msgbox.askokcancel.return_value = False
mock_msgbox.askyesno.return_value = False
-
- # trigger the expand event
+ # Trigger the expand event.
retval = expandingbutton.expand(event=Mock())
- # check that the event chain was broken and no text was inserted
+ # Check that the event chain was broken and no text was inserted.
self.assertEqual(retval, 'break')
self.assertEqual(expandingbutton.text.get('1.0', 'end-1c'), '')
- # patch the message box module to always return True
+ # Patch the message box module to always return True.
with patch('idlelib.squeezer.tkMessageBox') as mock_msgbox:
mock_msgbox.askokcancel.return_value = True
mock_msgbox.askyesno.return_value = True
-
- # trigger the expand event
+ # Trigger the expand event.
retval = expandingbutton.expand(event=Mock())
- # check that the event chain wasn't broken and the text was inserted
+ # Check that the event chain wasn't broken and the text was inserted.
self.assertEqual(retval, None)
self.assertEqual(expandingbutton.text.get('1.0', 'end-1c'), text)
def test_copy(self):
"""Test the copy event."""
- # testing with the actual clipboard proved problematic, so this test
- # replaces the clipboard manipulation functions with mocks and checks
- # that they are called appropriately
+ # Testing with the actual clipboard proved problematic, so this
+ # test replaces the clipboard manipulation functions with mocks
+ # and checks that they are called appropriately.
squeezer = self.make_mock_squeezer()
expandingbutton = ExpandingButton('TEXT', 'TAGS', 50, squeezer)
expandingbutton.clipboard_clear = Mock()
expandingbutton.clipboard_append = Mock()
- # trigger the copy event
+ # Trigger the copy event.
retval = expandingbutton.copy(event=Mock())
self.assertEqual(retval, None)
- # check that the expanding button called clipboard_clear() and
- # clipboard_append('TEXT') once each
+ # Vheck that the expanding button called clipboard_clear() and
+ # clipboard_append('TEXT') once each.
self.assertEqual(expandingbutton.clipboard_clear.call_count, 1)
self.assertEqual(expandingbutton.clipboard_append.call_count, 1)
expandingbutton.clipboard_append.assert_called_with('TEXT')
@@ -502,13 +459,13 @@ class ExpandingButtonTest(unittest.TestCase):
with patch('idlelib.squeezer.view_text', autospec=view_text)\
as mock_view_text:
- # trigger the view event
+ # Trigger the view event.
expandingbutton.view(event=Mock())
- # check that the expanding button called view_text
+ # Check that the expanding button called view_text.
self.assertEqual(mock_view_text.call_count, 1)
- # check that the proper text was passed
+ # Check that the proper text was passed.
self.assertEqual(mock_view_text.call_args[0][2], 'TEXT')
def test_rmenu(self):