147 lines
4.4 KiB
Python
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
|