summaryrefslogtreecommitdiffstats
path: root/Lib/idlelib/idle_test/test_codecontext.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/idlelib/idle_test/test_codecontext.py')
-rw-r--r--Lib/idlelib/idle_test/test_codecontext.py447
1 files changed, 0 insertions, 447 deletions
diff --git a/Lib/idlelib/idle_test/test_codecontext.py b/Lib/idlelib/idle_test/test_codecontext.py
deleted file mode 100644
index 3ec49e9..0000000
--- a/Lib/idlelib/idle_test/test_codecontext.py
+++ /dev/null
@@ -1,447 +0,0 @@
-"Test codecontext, coverage 100%"
-
-from idlelib import codecontext
-import unittest
-import unittest.mock
-from test.support import requires
-from tkinter import NSEW, Tk, Frame, Text, TclError
-
-from unittest import mock
-import re
-from idlelib import config
-
-
-usercfg = codecontext.idleConf.userCfg
-testcfg = {
- 'main': config.IdleUserConfParser(''),
- 'highlight': config.IdleUserConfParser(''),
- 'keys': config.IdleUserConfParser(''),
- 'extensions': config.IdleUserConfParser(''),
-}
-code_sample = """\
-
-class C1():
- # Class comment.
- def __init__(self, a, b):
- self.a = a
- self.b = b
- def compare(self):
- if a > b:
- return a
- elif a < b:
- return b
- else:
- return None
-"""
-
-
-class DummyEditwin:
- def __init__(self, root, frame, text):
- self.root = root
- self.top = root
- self.text_frame = frame
- self.text = text
- self.label = ''
-
- def getlineno(self, index):
- return int(float(self.text.index(index)))
-
- def update_menu_label(self, **kwargs):
- self.label = kwargs['label']
-
-
-class CodeContextTest(unittest.TestCase):
-
- @classmethod
- def setUpClass(cls):
- requires('gui')
- root = cls.root = Tk()
- root.withdraw()
- frame = cls.frame = Frame(root)
- text = cls.text = Text(frame)
- text.insert('1.0', code_sample)
- # Need to pack for creation of code context text widget.
- frame.pack(side='left', fill='both', expand=1)
- text.grid(row=1, column=1, sticky=NSEW)
- cls.editor = DummyEditwin(root, frame, text)
- codecontext.idleConf.userCfg = testcfg
-
- @classmethod
- def tearDownClass(cls):
- codecontext.idleConf.userCfg = usercfg
- cls.editor.text.delete('1.0', 'end')
- del cls.editor, cls.frame, cls.text
- cls.root.update_idletasks()
- cls.root.destroy()
- del cls.root
-
- def setUp(self):
- self.text.yview(0)
- self.text['font'] = 'TkFixedFont'
- self.cc = codecontext.CodeContext(self.editor)
-
- self.highlight_cfg = {"background": '#abcdef',
- "foreground": '#123456'}
- orig_idleConf_GetHighlight = codecontext.idleConf.GetHighlight
- def mock_idleconf_GetHighlight(theme, element):
- if element == 'context':
- return self.highlight_cfg
- return orig_idleConf_GetHighlight(theme, element)
- GetHighlight_patcher = unittest.mock.patch.object(
- codecontext.idleConf, 'GetHighlight', mock_idleconf_GetHighlight)
- GetHighlight_patcher.start()
- self.addCleanup(GetHighlight_patcher.stop)
-
- self.font_override = 'TkFixedFont'
- def mock_idleconf_GetFont(root, configType, section):
- return self.font_override
- GetFont_patcher = unittest.mock.patch.object(
- codecontext.idleConf, 'GetFont', mock_idleconf_GetFont)
- GetFont_patcher.start()
- self.addCleanup(GetFont_patcher.stop)
-
- def tearDown(self):
- if self.cc.context:
- self.cc.context.destroy()
- # Explicitly call __del__ to remove scheduled scripts.
- self.cc.__del__()
- del self.cc.context, self.cc
-
- def test_init(self):
- eq = self.assertEqual
- ed = self.editor
- cc = self.cc
-
- eq(cc.editwin, ed)
- eq(cc.text, ed.text)
- eq(cc.text['font'], ed.text['font'])
- self.assertIsNone(cc.context)
- eq(cc.info, [(0, -1, '', False)])
- eq(cc.topvisible, 1)
- self.assertIsNone(self.cc.t1)
-
- def test_del(self):
- self.cc.__del__()
-
- def test_del_with_timer(self):
- timer = self.cc.t1 = self.text.after(10000, lambda: None)
- self.cc.__del__()
- with self.assertRaises(TclError) as cm:
- self.root.tk.call('after', 'info', timer)
- self.assertIn("doesn't exist", str(cm.exception))
-
- def test_reload(self):
- codecontext.CodeContext.reload()
- self.assertEqual(self.cc.context_depth, 15)
-
- def test_toggle_code_context_event(self):
- eq = self.assertEqual
- cc = self.cc
- toggle = cc.toggle_code_context_event
-
- # Make sure code context is off.
- if cc.context:
- toggle()
-
- # Toggle on.
- toggle()
- self.assertIsNotNone(cc.context)
- eq(cc.context['font'], self.text['font'])
- eq(cc.context['fg'], self.highlight_cfg['foreground'])
- eq(cc.context['bg'], self.highlight_cfg['background'])
- eq(cc.context.get('1.0', 'end-1c'), '')
- eq(cc.editwin.label, 'Hide Code Context')
- eq(self.root.tk.call('after', 'info', self.cc.t1)[1], 'timer')
-
- # Toggle off.
- toggle()
- self.assertIsNone(cc.context)
- eq(cc.editwin.label, 'Show Code Context')
- self.assertIsNone(self.cc.t1)
-
- # Scroll down and toggle back on.
- line11_context = '\n'.join(x[2] for x in cc.get_context(11)[0])
- cc.text.yview(11)
- toggle()
- eq(cc.context.get('1.0', 'end-1c'), line11_context)
-
- # Toggle off and on again.
- toggle()
- toggle()
- eq(cc.context.get('1.0', 'end-1c'), line11_context)
-
- def test_get_context(self):
- eq = self.assertEqual
- gc = self.cc.get_context
-
- # stopline must be greater than 0.
- with self.assertRaises(AssertionError):
- gc(1, stopline=0)
-
- eq(gc(3), ([(2, 0, 'class C1():', 'class')], 0))
-
- # Don't return comment.
- eq(gc(4), ([(2, 0, 'class C1():', 'class')], 0))
-
- # Two indentation levels and no comment.
- eq(gc(5), ([(2, 0, 'class C1():', 'class'),
- (4, 4, ' def __init__(self, a, b):', 'def')], 0))
-
- # Only one 'def' is returned, not both at the same indent level.
- eq(gc(10), ([(2, 0, 'class C1():', 'class'),
- (7, 4, ' def compare(self):', 'def'),
- (8, 8, ' if a > b:', 'if')], 0))
-
- # With 'elif', also show the 'if' even though it's at the same level.
- eq(gc(11), ([(2, 0, 'class C1():', 'class'),
- (7, 4, ' def compare(self):', 'def'),
- (8, 8, ' if a > b:', 'if'),
- (10, 8, ' elif a < b:', 'elif')], 0))
-
- # Set stop_line to not go back to first line in source code.
- # Return includes stop_line.
- eq(gc(11, stopline=2), ([(2, 0, 'class C1():', 'class'),
- (7, 4, ' def compare(self):', 'def'),
- (8, 8, ' if a > b:', 'if'),
- (10, 8, ' elif a < b:', 'elif')], 0))
- eq(gc(11, stopline=3), ([(7, 4, ' def compare(self):', 'def'),
- (8, 8, ' if a > b:', 'if'),
- (10, 8, ' elif a < b:', 'elif')], 4))
- eq(gc(11, stopline=8), ([(8, 8, ' if a > b:', 'if'),
- (10, 8, ' elif a < b:', 'elif')], 8))
-
- # Set stop_indent to test indent level to stop at.
- eq(gc(11, stopindent=4), ([(7, 4, ' def compare(self):', 'def'),
- (8, 8, ' if a > b:', 'if'),
- (10, 8, ' elif a < b:', 'elif')], 4))
- # Check that the 'if' is included.
- eq(gc(11, stopindent=8), ([(8, 8, ' if a > b:', 'if'),
- (10, 8, ' elif a < b:', 'elif')], 8))
-
- def test_update_code_context(self):
- eq = self.assertEqual
- cc = self.cc
- # Ensure code context is active.
- if not cc.context:
- cc.toggle_code_context_event()
-
- # Invoke update_code_context without scrolling - nothing happens.
- self.assertIsNone(cc.update_code_context())
- eq(cc.info, [(0, -1, '', False)])
- eq(cc.topvisible, 1)
-
- # Scroll down to line 1.
- cc.text.yview(1)
- cc.update_code_context()
- eq(cc.info, [(0, -1, '', False)])
- eq(cc.topvisible, 2)
- eq(cc.context.get('1.0', 'end-1c'), '')
-
- # Scroll down to line 2.
- cc.text.yview(2)
- cc.update_code_context()
- eq(cc.info, [(0, -1, '', False), (2, 0, 'class C1():', 'class')])
- eq(cc.topvisible, 3)
- eq(cc.context.get('1.0', 'end-1c'), 'class C1():')
-
- # Scroll down to line 3. Since it's a comment, nothing changes.
- cc.text.yview(3)
- cc.update_code_context()
- eq(cc.info, [(0, -1, '', False), (2, 0, 'class C1():', 'class')])
- eq(cc.topvisible, 4)
- eq(cc.context.get('1.0', 'end-1c'), 'class C1():')
-
- # Scroll down to line 4.
- cc.text.yview(4)
- cc.update_code_context()
- eq(cc.info, [(0, -1, '', False),
- (2, 0, 'class C1():', 'class'),
- (4, 4, ' def __init__(self, a, b):', 'def')])
- eq(cc.topvisible, 5)
- eq(cc.context.get('1.0', 'end-1c'), 'class C1():\n'
- ' def __init__(self, a, b):')
-
- # Scroll down to line 11. Last 'def' is removed.
- cc.text.yview(11)
- cc.update_code_context()
- eq(cc.info, [(0, -1, '', False),
- (2, 0, 'class C1():', 'class'),
- (7, 4, ' def compare(self):', 'def'),
- (8, 8, ' if a > b:', 'if'),
- (10, 8, ' elif a < b:', 'elif')])
- eq(cc.topvisible, 12)
- eq(cc.context.get('1.0', 'end-1c'), 'class C1():\n'
- ' def compare(self):\n'
- ' if a > b:\n'
- ' elif a < b:')
-
- # No scroll. No update, even though context_depth changed.
- cc.update_code_context()
- cc.context_depth = 1
- eq(cc.info, [(0, -1, '', False),
- (2, 0, 'class C1():', 'class'),
- (7, 4, ' def compare(self):', 'def'),
- (8, 8, ' if a > b:', 'if'),
- (10, 8, ' elif a < b:', 'elif')])
- eq(cc.topvisible, 12)
- eq(cc.context.get('1.0', 'end-1c'), 'class C1():\n'
- ' def compare(self):\n'
- ' if a > b:\n'
- ' elif a < b:')
-
- # Scroll up.
- cc.text.yview(5)
- cc.update_code_context()
- eq(cc.info, [(0, -1, '', False),
- (2, 0, 'class C1():', 'class'),
- (4, 4, ' def __init__(self, a, b):', 'def')])
- eq(cc.topvisible, 6)
- # context_depth is 1.
- eq(cc.context.get('1.0', 'end-1c'), ' def __init__(self, a, b):')
-
- def test_jumptoline(self):
- eq = self.assertEqual
- cc = self.cc
- jump = cc.jumptoline
-
- if not cc.context:
- cc.toggle_code_context_event()
-
- # Empty context.
- cc.text.yview('2.0')
- cc.update_code_context()
- eq(cc.topvisible, 2)
- cc.context.mark_set('insert', '1.5')
- jump()
- eq(cc.topvisible, 1)
-
- # 4 lines of context showing.
- cc.text.yview('12.0')
- cc.update_code_context()
- eq(cc.topvisible, 12)
- cc.context.mark_set('insert', '3.0')
- jump()
- eq(cc.topvisible, 8)
-
- # More context lines than limit.
- cc.context_depth = 2
- cc.text.yview('12.0')
- cc.update_code_context()
- eq(cc.topvisible, 12)
- cc.context.mark_set('insert', '1.0')
- jump()
- eq(cc.topvisible, 8)
-
- @mock.patch.object(codecontext.CodeContext, 'update_code_context')
- def test_timer_event(self, mock_update):
- # Ensure code context is not active.
- if self.cc.context:
- self.cc.toggle_code_context_event()
- self.cc.timer_event()
- mock_update.assert_not_called()
-
- # Activate code context.
- self.cc.toggle_code_context_event()
- self.cc.timer_event()
- mock_update.assert_called()
-
- def test_font(self):
- eq = self.assertEqual
- cc = self.cc
-
- orig_font = cc.text['font']
- test_font = 'TkTextFont'
- self.assertNotEqual(orig_font, test_font)
-
- # Ensure code context is not active.
- if cc.context is not None:
- cc.toggle_code_context_event()
-
- self.font_override = test_font
- # Nothing breaks or changes with inactive code context.
- cc.update_font()
-
- # Activate code context, previous font change is immediately effective.
- cc.toggle_code_context_event()
- eq(cc.context['font'], test_font)
-
- # Call the font update, change is picked up.
- self.font_override = orig_font
- cc.update_font()
- eq(cc.context['font'], orig_font)
-
- def test_highlight_colors(self):
- eq = self.assertEqual
- cc = self.cc
-
- orig_colors = dict(self.highlight_cfg)
- test_colors = {'background': '#222222', 'foreground': '#ffff00'}
-
- def assert_colors_are_equal(colors):
- eq(cc.context['background'], colors['background'])
- eq(cc.context['foreground'], colors['foreground'])
-
- # Ensure code context is not active.
- if cc.context:
- cc.toggle_code_context_event()
-
- self.highlight_cfg = test_colors
- # Nothing breaks with inactive code context.
- cc.update_highlight_colors()
-
- # Activate code context, previous colors change is immediately effective.
- cc.toggle_code_context_event()
- assert_colors_are_equal(test_colors)
-
- # Call colors update with no change to the configured colors.
- cc.update_highlight_colors()
- assert_colors_are_equal(test_colors)
-
- # Call the colors update with code context active, change is picked up.
- self.highlight_cfg = orig_colors
- cc.update_highlight_colors()
- assert_colors_are_equal(orig_colors)
-
-
-class HelperFunctionText(unittest.TestCase):
-
- def test_get_spaces_firstword(self):
- get = codecontext.get_spaces_firstword
- test_lines = (
- (' first word', (' ', 'first')),
- ('\tfirst word', ('\t', 'first')),
- (' \u19D4\u19D2: ', (' ', '\u19D4\u19D2')),
- ('no spaces', ('', 'no')),
- ('', ('', '')),
- ('# TEST COMMENT', ('', '')),
- (' (continuation)', (' ', ''))
- )
- for line, expected_output in test_lines:
- self.assertEqual(get(line), expected_output)
-
- # Send the pattern in the call.
- self.assertEqual(get(' (continuation)',
- c=re.compile(r'^(\s*)([^\s]*)')),
- (' ', '(continuation)'))
-
- def test_get_line_info(self):
- eq = self.assertEqual
- gli = codecontext.get_line_info
- lines = code_sample.splitlines()
-
- # Line 1 is not a BLOCKOPENER.
- eq(gli(lines[0]), (codecontext.INFINITY, '', False))
- # Line 2 is a BLOCKOPENER without an indent.
- eq(gli(lines[1]), (0, 'class C1():', 'class'))
- # Line 3 is not a BLOCKOPENER and does not return the indent level.
- eq(gli(lines[2]), (codecontext.INFINITY, ' # Class comment.', False))
- # Line 4 is a BLOCKOPENER and is indented.
- eq(gli(lines[3]), (4, ' def __init__(self, a, b):', 'def'))
- # Line 8 is a different BLOCKOPENER and is indented.
- eq(gli(lines[7]), (8, ' if a > b:', 'if'))
- # Test tab.
- eq(gli('\tif a == b:'), (1, '\tif a == b:', 'if'))
-
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)