Files
babi/tests/hl/syntax_test.py
2020-03-21 14:19:51 -07:00

147 lines
4.4 KiB
Python

import contextlib
import curses
from unittest import mock
import pytest
from babi.color_manager import ColorManager
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(tmpdir):
return Syntax(Grammars.from_syntax_dir(tmpdir), 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.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.blank_file_highlighter().attr(style)
assert attr == 2 << 8 | curses.A_BOLD