bpo-35689: IDLE: Add docstrings and unittests for colorizer.py (GH-11472)
(cherry picked from commit ee0f927bd8
)
Co-authored-by: Cheryl Sabella <cheryl.sabella@gmail.com>
This commit is contained in:
parent
3129432845
commit
99e9c36b29
|
@ -3,6 +3,8 @@ Released on 2019-??-??
|
|||
======================================
|
||||
|
||||
|
||||
bpo-35689: Add docstrings and tests for colorizer.
|
||||
|
||||
bpo-35833: Revise IDLE doc for control codes sent to Shell.
|
||||
Add a code example block.
|
||||
|
||||
|
|
|
@ -53,6 +53,21 @@ def color_config(text):
|
|||
|
||||
|
||||
class ColorDelegator(Delegator):
|
||||
"""Delegator for syntax highlighting (text coloring).
|
||||
|
||||
Class variables:
|
||||
after_id: Identifier for scheduled after event.
|
||||
allow_colorizing: Boolean toggle for applying colorizing.
|
||||
colorizing: Boolean flag when colorizing is in process.
|
||||
stop_colorizing: Boolean flag to end an active colorizing
|
||||
process.
|
||||
close_when_done: Widget to destroy after colorizing process
|
||||
completes (doesn't seem to be used by IDLE).
|
||||
|
||||
Instance variables:
|
||||
delegate: Delegator below this one in the stack, meaning the
|
||||
one this one delegates to.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
Delegator.__init__(self)
|
||||
|
@ -61,6 +76,16 @@ class ColorDelegator(Delegator):
|
|||
self.LoadTagDefs()
|
||||
|
||||
def setdelegate(self, delegate):
|
||||
"""Set the delegate for this instance.
|
||||
|
||||
A delegate is an instance of a Delegator class and each
|
||||
delegate points to the next delegator in the stack. This
|
||||
allows multiple delegators to be chained together for a
|
||||
widget. The bottom delegate for a colorizer is a Text
|
||||
widget.
|
||||
|
||||
If there is a delegate, also start the colorizing process.
|
||||
"""
|
||||
if self.delegate is not None:
|
||||
self.unbind("<<toggle-auto-coloring>>")
|
||||
Delegator.setdelegate(self, delegate)
|
||||
|
@ -69,17 +94,18 @@ class ColorDelegator(Delegator):
|
|||
self.bind("<<toggle-auto-coloring>>", self.toggle_colorize_event)
|
||||
self.notify_range("1.0", "end")
|
||||
else:
|
||||
# No delegate - stop any colorizing
|
||||
# No delegate - stop any colorizing.
|
||||
self.stop_colorizing = True
|
||||
self.allow_colorizing = False
|
||||
|
||||
def config_colors(self):
|
||||
"Configure text widget tags with colors from tagdefs."
|
||||
for tag, cnf in self.tagdefs.items():
|
||||
if cnf:
|
||||
self.tag_configure(tag, **cnf)
|
||||
self.tag_raise('sel')
|
||||
|
||||
def LoadTagDefs(self):
|
||||
"Create dictionary of tag names to text colors."
|
||||
theme = idleConf.CurrentTheme()
|
||||
self.tagdefs = {
|
||||
"COMMENT": idleConf.GetHighlight(theme, "comment"),
|
||||
|
@ -97,20 +123,24 @@ class ColorDelegator(Delegator):
|
|||
if DEBUG: print('tagdefs',self.tagdefs)
|
||||
|
||||
def insert(self, index, chars, tags=None):
|
||||
"Insert chars into widget at index and mark for colorizing."
|
||||
index = self.index(index)
|
||||
self.delegate.insert(index, chars, tags)
|
||||
self.notify_range(index, index + "+%dc" % len(chars))
|
||||
|
||||
def delete(self, index1, index2=None):
|
||||
"Delete chars between indexes and mark for colorizing."
|
||||
index1 = self.index(index1)
|
||||
self.delegate.delete(index1, index2)
|
||||
self.notify_range(index1)
|
||||
|
||||
after_id = None
|
||||
allow_colorizing = True
|
||||
stop_colorizing = False
|
||||
colorizing = False
|
||||
|
||||
def notify_range(self, index1, index2=None):
|
||||
"Mark text changes for processing and restart colorizing, if active."
|
||||
self.tag_add("TODO", index1, index2)
|
||||
if self.after_id:
|
||||
if DEBUG: print("colorizing already scheduled")
|
||||
|
@ -121,8 +151,9 @@ class ColorDelegator(Delegator):
|
|||
if self.allow_colorizing:
|
||||
if DEBUG: print("schedule colorizing")
|
||||
self.after_id = self.after(1, self.recolorize)
|
||||
return
|
||||
|
||||
close_when_done = None # Window to be closed when done colorizing
|
||||
close_when_done = None # Window to be closed when done colorizing.
|
||||
|
||||
def close(self, close_when_done=None):
|
||||
if self.after_id:
|
||||
|
@ -138,7 +169,14 @@ class ColorDelegator(Delegator):
|
|||
else:
|
||||
self.close_when_done = close_when_done
|
||||
|
||||
def toggle_colorize_event(self, event):
|
||||
def toggle_colorize_event(self, event=None):
|
||||
"""Toggle colorizing on and off.
|
||||
|
||||
When toggling off, if colorizing is scheduled or is in
|
||||
process, it will be cancelled and/or stopped.
|
||||
|
||||
When toggling on, colorizing will be scheduled.
|
||||
"""
|
||||
if self.after_id:
|
||||
after_id = self.after_id
|
||||
self.after_id = None
|
||||
|
@ -156,6 +194,17 @@ class ColorDelegator(Delegator):
|
|||
return "break"
|
||||
|
||||
def recolorize(self):
|
||||
"""Timer event (every 1ms) to colorize text.
|
||||
|
||||
Colorizing is only attempted when the text widget exists,
|
||||
when colorizing is toggled on, and when the colorizing
|
||||
process is not already running.
|
||||
|
||||
After colorizing is complete, some cleanup is done to
|
||||
make sure that all the text has been colorized and to close
|
||||
the window if the close event had been called while the
|
||||
process was running.
|
||||
"""
|
||||
self.after_id = None
|
||||
if not self.delegate:
|
||||
if DEBUG: print("no delegate")
|
||||
|
@ -185,6 +234,7 @@ class ColorDelegator(Delegator):
|
|||
top.destroy()
|
||||
|
||||
def recolorize_main(self):
|
||||
"Evaluate text and apply colorizing tags."
|
||||
next = "1.0"
|
||||
while True:
|
||||
item = self.tag_nextrange("TODO", next)
|
||||
|
@ -250,6 +300,7 @@ class ColorDelegator(Delegator):
|
|||
return
|
||||
|
||||
def removecolors(self):
|
||||
"Remove all colorizing tags."
|
||||
for tag in self.tagdefs:
|
||||
self.tag_remove(tag, "1.0", "end")
|
||||
|
||||
|
@ -273,7 +324,7 @@ def _color_delegator(parent): # htest #
|
|||
"'x', '''x''', \"x\", \"\"\"x\"\"\"\n"
|
||||
"r'x', u'x', R'x', U'x', f'x', F'x'\n"
|
||||
"fr'x', Fr'x', fR'x', FR'x', rf'x', rF'x', Rf'x', RF'x'\n"
|
||||
"b'x',B'x', br'x',Br'x',bR'x',BR'x', rb'x'.rB'x',Rb'x',RB'x'\n"
|
||||
"b'x',B'x', br'x',Br'x',bR'x',BR'x', rb'x', rB'x',Rb'x',RB'x'\n"
|
||||
"# Invalid combinations of legal characters should be half colored.\n"
|
||||
"ur'x', ru'x', uf'x', fu'x', UR'x', ufr'x', rfu'x', xf'x', fx'x'\n"
|
||||
)
|
||||
|
|
|
@ -1,36 +1,103 @@
|
|||
"Test colorizer, coverage 25%."
|
||||
"Test colorizer, coverage 93%."
|
||||
|
||||
from idlelib import colorizer
|
||||
from test.support import requires
|
||||
from tkinter import Tk, Text
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
from functools import partial
|
||||
from tkinter import Tk, Text
|
||||
from idlelib import config
|
||||
from idlelib.percolator import Percolator
|
||||
|
||||
|
||||
usercfg = colorizer.idleConf.userCfg
|
||||
testcfg = {
|
||||
'main': config.IdleUserConfParser(''),
|
||||
'highlight': config.IdleUserConfParser(''),
|
||||
'keys': config.IdleUserConfParser(''),
|
||||
'extensions': config.IdleUserConfParser(''),
|
||||
}
|
||||
|
||||
source = (
|
||||
"if True: int ('1') # keyword, builtin, string, comment\n"
|
||||
"elif False: print(0) # 'string' in comment\n"
|
||||
"else: float(None) # if in comment\n"
|
||||
"if iF + If + IF: 'keyword matching must respect case'\n"
|
||||
"if'': x or'' # valid string-keyword no-space combinations\n"
|
||||
"async def f(): await g()\n"
|
||||
"'x', '''x''', \"x\", \"\"\"x\"\"\"\n"
|
||||
)
|
||||
|
||||
|
||||
def setUpModule():
|
||||
colorizer.idleConf.userCfg = testcfg
|
||||
|
||||
|
||||
def tearDownModule():
|
||||
colorizer.idleConf.userCfg = usercfg
|
||||
|
||||
|
||||
class FunctionTest(unittest.TestCase):
|
||||
|
||||
def test_any(self):
|
||||
self.assertTrue(colorizer.any('test', ('a', 'b')))
|
||||
self.assertEqual(colorizer.any('test', ('a', 'b', 'cd')),
|
||||
'(?P<test>a|b|cd)')
|
||||
|
||||
def test_make_pat(self):
|
||||
# Tested in more detail by testing prog.
|
||||
self.assertTrue(colorizer.make_pat())
|
||||
|
||||
def test_prog(self):
|
||||
prog = colorizer.prog
|
||||
eq = self.assertEqual
|
||||
line = 'def f():\n print("hello")\n'
|
||||
m = prog.search(line)
|
||||
eq(m.groupdict()['KEYWORD'], 'def')
|
||||
m = prog.search(line, m.end())
|
||||
eq(m.groupdict()['SYNC'], '\n')
|
||||
m = prog.search(line, m.end())
|
||||
eq(m.groupdict()['BUILTIN'], 'print')
|
||||
m = prog.search(line, m.end())
|
||||
eq(m.groupdict()['STRING'], '"hello"')
|
||||
m = prog.search(line, m.end())
|
||||
eq(m.groupdict()['SYNC'], '\n')
|
||||
|
||||
def test_idprog(self):
|
||||
idprog = colorizer.idprog
|
||||
m = idprog.match('nospace')
|
||||
self.assertIsNone(m)
|
||||
m = idprog.match(' space')
|
||||
self.assertEqual(m.group(0), ' space')
|
||||
|
||||
|
||||
class ColorConfigTest(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
requires('gui')
|
||||
cls.root = Tk()
|
||||
cls.text = Text(cls.root)
|
||||
root = cls.root = Tk()
|
||||
root.withdraw()
|
||||
cls.text = Text(root)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
del cls.text
|
||||
cls.root.update_idletasks()
|
||||
cls.root.destroy()
|
||||
del cls.root
|
||||
|
||||
def test_colorizer(self):
|
||||
colorizer.color_config(self.text)
|
||||
def test_color_config(self):
|
||||
text = self.text
|
||||
eq = self.assertEqual
|
||||
colorizer.color_config(text)
|
||||
# Uses IDLE Classic theme as default.
|
||||
eq(text['background'], '#ffffff')
|
||||
eq(text['foreground'], '#000000')
|
||||
eq(text['selectbackground'], 'gray')
|
||||
eq(text['selectforeground'], '#000000')
|
||||
eq(text['insertbackground'], 'black')
|
||||
eq(text['inactiveselectbackground'], 'gray')
|
||||
|
||||
|
||||
class ColorDelegatorTest(unittest.TestCase):
|
||||
|
@ -38,15 +105,286 @@ class ColorDelegatorTest(unittest.TestCase):
|
|||
@classmethod
|
||||
def setUpClass(cls):
|
||||
requires('gui')
|
||||
cls.root = Tk()
|
||||
root = cls.root = Tk()
|
||||
root.withdraw()
|
||||
text = cls.text = Text(root)
|
||||
cls.percolator = Percolator(text)
|
||||
# Delegator stack = [Delagator(text)]
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
cls.percolator.redir.close()
|
||||
del cls.percolator, cls.text
|
||||
cls.root.update_idletasks()
|
||||
cls.root.destroy()
|
||||
del cls.root
|
||||
|
||||
def test_colorizer(self):
|
||||
colorizer.ColorDelegator()
|
||||
def setUp(self):
|
||||
self.color = colorizer.ColorDelegator()
|
||||
self.percolator.insertfilter(self.color)
|
||||
# Calls color.setdelagate(Delagator(text)).
|
||||
|
||||
def tearDown(self):
|
||||
self.color.close()
|
||||
self.percolator.removefilter(self.color)
|
||||
self.text.delete('1.0', 'end')
|
||||
self.color.resetcache()
|
||||
del self.color
|
||||
|
||||
def test_init(self):
|
||||
color = self.color
|
||||
self.assertIsInstance(color, colorizer.ColorDelegator)
|
||||
# The following are class variables.
|
||||
self.assertTrue(color.allow_colorizing)
|
||||
self.assertFalse(color.colorizing)
|
||||
|
||||
def test_setdelegate(self):
|
||||
# Called in setUp.
|
||||
color = self.color
|
||||
self.assertIsInstance(color.delegate, colorizer.Delegator)
|
||||
# It is too late to mock notify_range, so test side effect.
|
||||
self.assertEqual(self.root.tk.call(
|
||||
'after', 'info', color.after_id)[1], 'timer')
|
||||
|
||||
def test_LoadTagDefs(self):
|
||||
highlight = partial(config.idleConf.GetHighlight, theme='IDLE Classic')
|
||||
for tag, colors in self.color.tagdefs.items():
|
||||
with self.subTest(tag=tag):
|
||||
self.assertIn('background', colors)
|
||||
self.assertIn('foreground', colors)
|
||||
if tag not in ('SYNC', 'TODO'):
|
||||
self.assertEqual(colors, highlight(element=tag.lower()))
|
||||
|
||||
def test_config_colors(self):
|
||||
text = self.text
|
||||
highlight = partial(config.idleConf.GetHighlight, theme='IDLE Classic')
|
||||
for tag in self.color.tagdefs:
|
||||
for plane in ('background', 'foreground'):
|
||||
with self.subTest(tag=tag, plane=plane):
|
||||
if tag in ('SYNC', 'TODO'):
|
||||
self.assertEqual(text.tag_cget(tag, plane), '')
|
||||
else:
|
||||
self.assertEqual(text.tag_cget(tag, plane),
|
||||
highlight(element=tag.lower())[plane])
|
||||
# 'sel' is marked as the highest priority.
|
||||
self.assertEqual(text.tag_names()[-1], 'sel')
|
||||
|
||||
@mock.patch.object(colorizer.ColorDelegator, 'notify_range')
|
||||
def test_insert(self, mock_notify):
|
||||
text = self.text
|
||||
# Initial text.
|
||||
text.insert('insert', 'foo')
|
||||
self.assertEqual(text.get('1.0', 'end'), 'foo\n')
|
||||
mock_notify.assert_called_with('1.0', '1.0+3c')
|
||||
# Additional text.
|
||||
text.insert('insert', 'barbaz')
|
||||
self.assertEqual(text.get('1.0', 'end'), 'foobarbaz\n')
|
||||
mock_notify.assert_called_with('1.3', '1.3+6c')
|
||||
|
||||
@mock.patch.object(colorizer.ColorDelegator, 'notify_range')
|
||||
def test_delete(self, mock_notify):
|
||||
text = self.text
|
||||
# Initialize text.
|
||||
text.insert('insert', 'abcdefghi')
|
||||
self.assertEqual(text.get('1.0', 'end'), 'abcdefghi\n')
|
||||
# Delete single character.
|
||||
text.delete('1.7')
|
||||
self.assertEqual(text.get('1.0', 'end'), 'abcdefgi\n')
|
||||
mock_notify.assert_called_with('1.7')
|
||||
# Delete multiple characters.
|
||||
text.delete('1.3', '1.6')
|
||||
self.assertEqual(text.get('1.0', 'end'), 'abcgi\n')
|
||||
mock_notify.assert_called_with('1.3')
|
||||
|
||||
def test_notify_range(self):
|
||||
text = self.text
|
||||
color = self.color
|
||||
eq = self.assertEqual
|
||||
|
||||
# Colorizing already scheduled.
|
||||
save_id = color.after_id
|
||||
eq(self.root.tk.call('after', 'info', save_id)[1], 'timer')
|
||||
self.assertFalse(color.colorizing)
|
||||
self.assertFalse(color.stop_colorizing)
|
||||
self.assertTrue(color.allow_colorizing)
|
||||
|
||||
# Coloring scheduled and colorizing in progress.
|
||||
color.colorizing = True
|
||||
color.notify_range('1.0', 'end')
|
||||
self.assertFalse(color.stop_colorizing)
|
||||
eq(color.after_id, save_id)
|
||||
|
||||
# No colorizing scheduled and colorizing in progress.
|
||||
text.after_cancel(save_id)
|
||||
color.after_id = None
|
||||
color.notify_range('1.0', '1.0+3c')
|
||||
self.assertTrue(color.stop_colorizing)
|
||||
self.assertIsNotNone(color.after_id)
|
||||
eq(self.root.tk.call('after', 'info', color.after_id)[1], 'timer')
|
||||
# New event scheduled.
|
||||
self.assertNotEqual(color.after_id, save_id)
|
||||
|
||||
# No colorizing scheduled and colorizing off.
|
||||
text.after_cancel(color.after_id)
|
||||
color.after_id = None
|
||||
color.allow_colorizing = False
|
||||
color.notify_range('1.4', '1.4+10c')
|
||||
# Nothing scheduled when colorizing is off.
|
||||
self.assertIsNone(color.after_id)
|
||||
|
||||
def test_toggle_colorize_event(self):
|
||||
color = self.color
|
||||
eq = self.assertEqual
|
||||
|
||||
# Starts with colorizing allowed and scheduled.
|
||||
self.assertFalse(color.colorizing)
|
||||
self.assertFalse(color.stop_colorizing)
|
||||
self.assertTrue(color.allow_colorizing)
|
||||
eq(self.root.tk.call('after', 'info', color.after_id)[1], 'timer')
|
||||
|
||||
# Toggle colorizing off.
|
||||
color.toggle_colorize_event()
|
||||
self.assertIsNone(color.after_id)
|
||||
self.assertFalse(color.colorizing)
|
||||
self.assertFalse(color.stop_colorizing)
|
||||
self.assertFalse(color.allow_colorizing)
|
||||
|
||||
# Toggle on while colorizing in progress (doesn't add timer).
|
||||
color.colorizing = True
|
||||
color.toggle_colorize_event()
|
||||
self.assertIsNone(color.after_id)
|
||||
self.assertTrue(color.colorizing)
|
||||
self.assertFalse(color.stop_colorizing)
|
||||
self.assertTrue(color.allow_colorizing)
|
||||
|
||||
# Toggle off while colorizing in progress.
|
||||
color.toggle_colorize_event()
|
||||
self.assertIsNone(color.after_id)
|
||||
self.assertTrue(color.colorizing)
|
||||
self.assertTrue(color.stop_colorizing)
|
||||
self.assertFalse(color.allow_colorizing)
|
||||
|
||||
# Toggle on while colorizing not in progress.
|
||||
color.colorizing = False
|
||||
color.toggle_colorize_event()
|
||||
eq(self.root.tk.call('after', 'info', color.after_id)[1], 'timer')
|
||||
self.assertFalse(color.colorizing)
|
||||
self.assertTrue(color.stop_colorizing)
|
||||
self.assertTrue(color.allow_colorizing)
|
||||
|
||||
@mock.patch.object(colorizer.ColorDelegator, 'recolorize_main')
|
||||
def test_recolorize(self, mock_recmain):
|
||||
text = self.text
|
||||
color = self.color
|
||||
eq = self.assertEqual
|
||||
# Call recolorize manually and not scheduled.
|
||||
text.after_cancel(color.after_id)
|
||||
|
||||
# No delegate.
|
||||
save_delegate = color.delegate
|
||||
color.delegate = None
|
||||
color.recolorize()
|
||||
mock_recmain.assert_not_called()
|
||||
color.delegate = save_delegate
|
||||
|
||||
# Toggle off colorizing.
|
||||
color.allow_colorizing = False
|
||||
color.recolorize()
|
||||
mock_recmain.assert_not_called()
|
||||
color.allow_colorizing = True
|
||||
|
||||
# Colorizing in progress.
|
||||
color.colorizing = True
|
||||
color.recolorize()
|
||||
mock_recmain.assert_not_called()
|
||||
color.colorizing = False
|
||||
|
||||
# Colorizing is done, but not completed, so rescheduled.
|
||||
color.recolorize()
|
||||
self.assertFalse(color.stop_colorizing)
|
||||
self.assertFalse(color.colorizing)
|
||||
mock_recmain.assert_called()
|
||||
eq(mock_recmain.call_count, 1)
|
||||
# Rescheduled when TODO tag still exists.
|
||||
eq(self.root.tk.call('after', 'info', color.after_id)[1], 'timer')
|
||||
|
||||
# No changes to text, so no scheduling added.
|
||||
text.tag_remove('TODO', '1.0', 'end')
|
||||
color.recolorize()
|
||||
self.assertFalse(color.stop_colorizing)
|
||||
self.assertFalse(color.colorizing)
|
||||
mock_recmain.assert_called()
|
||||
eq(mock_recmain.call_count, 2)
|
||||
self.assertIsNone(color.after_id)
|
||||
|
||||
@mock.patch.object(colorizer.ColorDelegator, 'notify_range')
|
||||
def test_recolorize_main(self, mock_notify):
|
||||
text = self.text
|
||||
color = self.color
|
||||
eq = self.assertEqual
|
||||
|
||||
text.insert('insert', source)
|
||||
expected = (('1.0', ('KEYWORD',)), ('1.2', ()), ('1.3', ('KEYWORD',)),
|
||||
('1.7', ()), ('1.9', ('BUILTIN',)), ('1.14', ('STRING',)),
|
||||
('1.19', ('COMMENT',)),
|
||||
('2.1', ('KEYWORD',)), ('2.18', ()), ('2.25', ('COMMENT',)),
|
||||
('3.6', ('BUILTIN',)), ('3.12', ('KEYWORD',)), ('3.21', ('COMMENT',)),
|
||||
('4.0', ('KEYWORD',)), ('4.3', ()), ('4.6', ()),
|
||||
('5.2', ('STRING',)), ('5.8', ('KEYWORD',)), ('5.10', ('STRING',)),
|
||||
('6.0', ('KEYWORD',)), ('6.10', ('DEFINITION',)), ('6.11', ()),
|
||||
('7.0', ('STRING',)), ('7.4', ()), ('7.5', ('STRING',)),
|
||||
('7.12', ()), ('7.14', ('STRING',)),
|
||||
# SYNC at the end of every line.
|
||||
('1.55', ('SYNC',)), ('2.50', ('SYNC',)), ('3.34', ('SYNC',)),
|
||||
)
|
||||
|
||||
# Nothing marked to do therefore no tags in text.
|
||||
text.tag_remove('TODO', '1.0', 'end')
|
||||
color.recolorize_main()
|
||||
for tag in text.tag_names():
|
||||
with self.subTest(tag=tag):
|
||||
eq(text.tag_ranges(tag), ())
|
||||
|
||||
# Source marked for processing.
|
||||
text.tag_add('TODO', '1.0', 'end')
|
||||
# Check some indexes.
|
||||
color.recolorize_main()
|
||||
for index, expected_tags in expected:
|
||||
with self.subTest(index=index):
|
||||
eq(text.tag_names(index), expected_tags)
|
||||
|
||||
# Check for some tags for ranges.
|
||||
eq(text.tag_nextrange('TODO', '1.0'), ())
|
||||
eq(text.tag_nextrange('KEYWORD', '1.0'), ('1.0', '1.2'))
|
||||
eq(text.tag_nextrange('COMMENT', '2.0'), ('2.22', '2.43'))
|
||||
eq(text.tag_nextrange('SYNC', '2.0'), ('2.43', '3.0'))
|
||||
eq(text.tag_nextrange('STRING', '2.0'), ('4.17', '4.53'))
|
||||
eq(text.tag_nextrange('STRING', '7.0'), ('7.0', '7.3'))
|
||||
eq(text.tag_nextrange('STRING', '7.3'), ('7.5', '7.12'))
|
||||
eq(text.tag_nextrange('STRING', '7.12'), ('7.14', '7.17'))
|
||||
eq(text.tag_nextrange('STRING', '7.17'), ('7.19', '7.26'))
|
||||
eq(text.tag_nextrange('SYNC', '7.0'), ('7.26', '9.0'))
|
||||
|
||||
@mock.patch.object(colorizer.ColorDelegator, 'recolorize')
|
||||
@mock.patch.object(colorizer.ColorDelegator, 'notify_range')
|
||||
def test_removecolors(self, mock_notify, mock_recolorize):
|
||||
text = self.text
|
||||
color = self.color
|
||||
text.insert('insert', source)
|
||||
|
||||
color.recolorize_main()
|
||||
# recolorize_main doesn't add these tags.
|
||||
text.tag_add("ERROR", "1.0")
|
||||
text.tag_add("TODO", "1.0")
|
||||
text.tag_add("hit", "1.0")
|
||||
for tag in color.tagdefs:
|
||||
with self.subTest(tag=tag):
|
||||
self.assertNotEqual(text.tag_ranges(tag), ())
|
||||
|
||||
color.removecolors()
|
||||
for tag in color.tagdefs:
|
||||
with self.subTest(tag=tag):
|
||||
self.assertEqual(text.tag_ranges(tag), ())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Add docstrings and unittests for colorizer.py.
|
Loading…
Reference in New Issue