Syntax highlighting
This commit is contained in:
147
tests/hl/syntax_test.py
Normal file
147
tests/hl/syntax_test.py
Normal file
@@ -0,0 +1,147 @@
|
||||
import contextlib
|
||||
import curses
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
from babi.color_manager import ColorManager
|
||||
from babi.highlight import Grammar
|
||||
from babi.highlight import Grammars
|
||||
from babi.hl.syntax import Syntax
|
||||
from babi.theme import Color
|
||||
from babi.theme import Theme
|
||||
|
||||
|
||||
class FakeCurses:
|
||||
def __init__(self, *, n_colors, can_change_color):
|
||||
self._n_colors = n_colors
|
||||
self._can_change_color = can_change_color
|
||||
self.colors = {}
|
||||
self.pairs = {}
|
||||
|
||||
def _curses__can_change_color(self):
|
||||
return self._can_change_color
|
||||
|
||||
def _curses__init_color(self, n, r, g, b):
|
||||
self.colors[n] = (r, g, b)
|
||||
|
||||
def _curses__init_pair(self, n, fg, bg):
|
||||
self.pairs[n] = (fg, bg)
|
||||
|
||||
def _curses__color_pair(self, n):
|
||||
assert n == 0 or n in self.pairs
|
||||
return n << 8
|
||||
|
||||
@classmethod
|
||||
@contextlib.contextmanager
|
||||
def patch(cls, **kwargs):
|
||||
fake = cls(**kwargs)
|
||||
with mock.patch.object(curses, 'COLORS', fake._n_colors, create=True):
|
||||
with mock.patch.multiple(
|
||||
curses,
|
||||
can_change_color=fake._curses__can_change_color,
|
||||
color_pair=fake._curses__color_pair,
|
||||
init_color=fake._curses__init_color,
|
||||
init_pair=fake._curses__init_pair,
|
||||
):
|
||||
yield fake
|
||||
|
||||
|
||||
class FakeScreen:
|
||||
def __init__(self):
|
||||
self.attr = 0
|
||||
|
||||
def bkgd(self, c, attr):
|
||||
assert c == ' '
|
||||
self.attr = attr
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def stdscr():
|
||||
return FakeScreen()
|
||||
|
||||
|
||||
THEME = Theme.from_dct({
|
||||
'colors': {'foreground': '#cccccc', 'background': '#333333'},
|
||||
'tokenColors': [
|
||||
{'scope': 'string', 'settings': {'foreground': '#009900'}},
|
||||
{'scope': 'keyword', 'settings': {'background': '#000000'}},
|
||||
{'scope': 'keyword', 'settings': {'fontStyle': 'bold'}},
|
||||
],
|
||||
})
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def syntax():
|
||||
return Syntax(Grammars([Grammar.blank()]), THEME, ColorManager.make())
|
||||
|
||||
|
||||
def test_init_screen_low_color(stdscr, syntax):
|
||||
with FakeCurses.patch(n_colors=16, can_change_color=False) as fake_curses:
|
||||
syntax._init_screen(stdscr)
|
||||
assert syntax.color_manager.colors == {}
|
||||
assert syntax.color_manager.raw_pairs == {}
|
||||
assert fake_curses.colors == {}
|
||||
assert fake_curses.pairs == {}
|
||||
assert stdscr.attr == 0
|
||||
|
||||
|
||||
def test_init_screen_256_color(stdscr, syntax):
|
||||
with FakeCurses.patch(n_colors=256, can_change_color=False) as fake_curses:
|
||||
syntax._init_screen(stdscr)
|
||||
assert syntax.color_manager.colors == {
|
||||
Color.parse('#cccccc'): 252,
|
||||
Color.parse('#333333'): 236,
|
||||
Color.parse('#000000'): 16,
|
||||
Color.parse('#009900'): 28,
|
||||
}
|
||||
assert syntax.color_manager.raw_pairs == {(252, 236): 1}
|
||||
assert fake_curses.colors == {}
|
||||
assert fake_curses.pairs == {1: (252, 236)}
|
||||
assert stdscr.attr == 1 << 8
|
||||
|
||||
|
||||
def test_init_screen_true_color(stdscr, syntax):
|
||||
with FakeCurses.patch(n_colors=256, can_change_color=True) as fake_curses:
|
||||
syntax._init_screen(stdscr)
|
||||
# weird colors happened with low color numbers so it counts down from max
|
||||
assert syntax.color_manager.colors == {
|
||||
Color.parse('#000000'): 255,
|
||||
Color.parse('#009900'): 254,
|
||||
Color.parse('#333333'): 253,
|
||||
Color.parse('#cccccc'): 252,
|
||||
}
|
||||
assert syntax.color_manager.raw_pairs == {(252, 253): 1}
|
||||
assert fake_curses.colors == {
|
||||
255: (0, 0, 0),
|
||||
254: (0, 600, 0),
|
||||
253: (200, 200, 200),
|
||||
252: (800, 800, 800),
|
||||
}
|
||||
assert fake_curses.pairs == {1: (252, 253)}
|
||||
assert stdscr.attr == 1 << 8
|
||||
|
||||
|
||||
def test_lazily_instantiated_pairs(stdscr, syntax):
|
||||
# pairs are assigned lazily to avoid hard upper limit (256) on pairs
|
||||
with FakeCurses.patch(n_colors=256, can_change_color=False) as fake_curses:
|
||||
syntax._init_screen(stdscr)
|
||||
|
||||
assert len(syntax.color_manager.raw_pairs) == 1
|
||||
assert len(fake_curses.pairs) == 1
|
||||
|
||||
style = THEME.select(('string.python',))
|
||||
attr = syntax.get_blank_file_highlighter().attr(style)
|
||||
assert attr == 2 << 8
|
||||
|
||||
assert len(syntax.color_manager.raw_pairs) == 2
|
||||
assert len(fake_curses.pairs) == 2
|
||||
|
||||
|
||||
def test_style_attributes_applied(stdscr, syntax):
|
||||
with FakeCurses.patch(n_colors=256, can_change_color=False):
|
||||
syntax._init_screen(stdscr)
|
||||
|
||||
style = THEME.select(('keyword.python',))
|
||||
attr = syntax.get_blank_file_highlighter().attr(style)
|
||||
assert attr == 2 << 8 | curses.A_BOLD
|
||||
Reference in New Issue
Block a user