Skip to content

Commit

Permalink
GH-4: Fix alt fonts, GH-5: add tests (#6)
Browse files Browse the repository at this point in the history
* Add tests
  • Loading branch information
qexat authored May 2, 2023
1 parent ab2e3e3 commit b54fb58
Show file tree
Hide file tree
Showing 6 changed files with 268 additions and 18 deletions.
4 changes: 4 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from setuptools import setup

if __name__ == "__main__":
setup(extras_require={"dev": ["pytest", "coverage"]})
17 changes: 10 additions & 7 deletions src/coquille/coquille.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
__all__ = ["apply", "Coquille", "EscapeSequence", "prepare"]

# ... don't say anything.
if TYPE_CHECKING:
if TYPE_CHECKING: # pragma: no cover
if sys.version_info >= (3, 10):
from typing import ParamSpec

Expand All @@ -23,7 +23,7 @@


@overload
def prepare(sequence: EscapeSequence) -> EscapeSequence:
def prepare(sequence: EscapeSequence) -> EscapeSequence: # pragma: no cover
pass


Expand All @@ -32,7 +32,7 @@ def prepare(
sequence: Callable[P, EscapeSequence],
*args: P.args,
**kwargs: P.kwargs,
) -> EscapeSequence:
) -> EscapeSequence: # pragma: no cover
pass


Expand All @@ -55,7 +55,10 @@ def prepare(


@overload
def apply(sequence: EscapeSequence, file: SupportsWrite[str] | None = None) -> None:
def apply(
sequence: EscapeSequence,
file: SupportsWrite[str] | None = None,
) -> None: # pragma: no cover
pass


Expand All @@ -65,7 +68,7 @@ def apply(
file: SupportsWrite[str] | None = None,
*args: P.args,
**kwargs: P.kwargs,
) -> None:
) -> None: # pragma: no cover
pass


Expand Down Expand Up @@ -139,7 +142,7 @@ class Coquille:

@overload
@classmethod
def new(cls: type[Self], *sequences: EscapeSequence) -> Self:
def new(cls: type[Self], *sequences: EscapeSequence) -> Self: # pragma: no cover
pass

@overload
Expand All @@ -148,7 +151,7 @@ def new(
cls: type[Self],
*sequences: EscapeSequence,
file: SupportsWrite[str],
) -> Self:
) -> Self: # pragma: no cover
pass

@classmethod
Expand Down
22 changes: 11 additions & 11 deletions src/coquille/sequences.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@

# Helper types
EscapeSequence = NewType("EscapeSequence", str)
AltFontNumber = Literal[11, 12, 13, 14, 15, 16, 17, 18, 19]
AltFontNumber = Literal[1, 2, 3, 4, 5, 6, 7, 8, 9]


def escape_sequence(
Expand Down Expand Up @@ -167,7 +167,7 @@ def _disable_CSI(*args: int) -> EscapeSequence:
return _CSI_private("l", *args)


def _cursor_shape(n: int) -> EscapeSequence:
def cursor_shape(n: int) -> EscapeSequence:
return EscapeSequence(CHAR_ESC + f"[{n} q")


Expand Down Expand Up @@ -200,7 +200,7 @@ def cursor_horizontal_absolute(n: int = 1) -> EscapeSequence:
return CSI("G", n)


def cursor_position(n: int, m: int = 1) -> EscapeSequence:
def cursor_position(n: int = 1, m: int = 1) -> EscapeSequence:
return CSI("H", n, m)


Expand Down Expand Up @@ -249,13 +249,13 @@ def numpad(n: int) -> EscapeSequence:

# *- Cursor shapes -* #

user_defined_cursor_shape = _cursor_shape(0)
blinking_block_cursor_shape = _cursor_shape(1)
steady_block_cursor_shape = _cursor_shape(2)
blinking_underline_cursor_shape = _cursor_shape(3)
steady_underline_cursor_shape = _cursor_shape(4)
blinking_bar_cursor_shape = _cursor_shape(5)
steady_bar_cursor_shape = _cursor_shape(6)
user_defined_cursor_shape = cursor_shape(0)
blinking_block_cursor_shape = cursor_shape(1)
steady_block_cursor_shape = cursor_shape(2)
blinking_underline_cursor_shape = cursor_shape(3)
steady_underline_cursor_shape = cursor_shape(4)
blinking_bar_cursor_shape = cursor_shape(5)
steady_bar_cursor_shape = cursor_shape(6)


# aliases
Expand Down Expand Up @@ -312,7 +312,7 @@ def numpad(n: int) -> EscapeSequence:


def alternative_font(n: AltFontNumber) -> EscapeSequence:
return SGR(n - 10)
return SGR(n + 10)


fraktur = SGR(20) # [RS]
Expand Down
Empty file added tests/__init__.py
Empty file.
40 changes: 40 additions & 0 deletions tests/coquille_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from io import StringIO

import pytest
from coquille.coquille import *
from coquille.sequences import DEC_save_cursor
from coquille.sequences import erase_in_display
from coquille.sequences import select_graphical_rendition
from coquille.sequences import start_of_string


@pytest.mark.parametrize(
["args", "output"],
[
((DEC_save_cursor,), DEC_save_cursor),
((start_of_string,), "\u001bX"),
((erase_in_display, 2), "\u001b[2J"),
((select_graphical_rendition, 38, 5, 16), "\x1b[38;5;16m"),
],
)
def test_prepare(args, output):
assert prepare(*args) == output


@pytest.mark.parametrize(
["sequence", "args", "output"],
[
(DEC_save_cursor, (), DEC_save_cursor),
(start_of_string, (), "\u001bX"),
(erase_in_display, (2,), "\u001b[2J"),
(select_graphical_rendition, (38, 5, 16), "\x1b[38;5;16m"),
],
)
def test_apply(sequence, args, output):
file = StringIO()
apply(sequence, file, *args)
assert file.getvalue() == output


# TODO: test_ContextCoquille_*
# TODO: test_Coquille_*
203 changes: 203 additions & 0 deletions tests/sequences_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
import pytest
from coquille.sequences import *


@pytest.mark.parametrize(
["args", "result"],
[
(("N"), "\u001bN"), # code only
(("[", "i"), "\u001b[i"), # code + subcode
(("[", "m", 1), "\u001b[1m"), # code, subcode, 1 arg
(
("[", "m", 38, 2, 255, 127, 0),
"\u001b[38;2;255;127;0m",
), # code, subcode, n-args
],
)
def test_escape_sequence(args, result):
assert escape_sequence(*args) == result


def test_single_shift_two():
assert single_shift_two() == "\u001bN"


def test_single_shift_three():
assert single_shift_three() == "\u001bO"


def test_device_control_string():
assert device_control_string() == "\u001bP"


def test_string_terminator():
assert string_terminator() == "\u001b\\"


def test_operating_system_command():
assert operating_system_command() == "\u001b]"


def test_start_of_string():
assert start_of_string() == "\u001bX"


def test_privacy_message():
assert privacy_message() == "\u001b^"


def test_application_program_command():
assert application_program_command() == "\u001b_"


def test_cursor_shape():
assert cursor_shape(0) == "\u001b[0 q"


@pytest.mark.parametrize(
["args", "output"],
[
((), "\u001b[1A"),
((3,), "\u001b[3A"),
],
)
def test_cursor_up(args, output):
assert cursor_up(*args) == output


@pytest.mark.parametrize(
["args", "output"],
[
((), "\u001b[1B"),
((3,), "\u001b[3B"),
],
)
def test_cursor_down(args, output):
assert cursor_down(*args) == output


@pytest.mark.parametrize(
["args", "output"],
[
((), "\u001b[1C"),
((3,), "\u001b[3C"),
],
)
def test_cursor_forward(args, output):
assert cursor_forward(*args) == output


@pytest.mark.parametrize(
["args", "output"],
[
((), "\u001b[1D"),
((3,), "\u001b[3D"),
],
)
def test_cursor_back(args, output):
assert cursor_back(*args) == output


@pytest.mark.parametrize(
["args", "output"],
[
((), "\u001b[1E"),
((3,), "\u001b[3E"),
],
)
def test_cursor_next_line(args, output):
assert cursor_next_line(*args) == output


@pytest.mark.parametrize(
["args", "output"],
[
((), "\u001b[1F"),
((3,), "\u001b[3F"),
],
)
def test_cursor_previous_line(args, output):
assert cursor_previous_line(*args) == output


@pytest.mark.parametrize(
["args", "output"],
[
((), "\u001b[1G"),
((3,), "\u001b[3G"),
],
)
def test_cursor_horizontal_absolute(args, output):
assert cursor_horizontal_absolute(*args) == output


@pytest.mark.parametrize(
["kwargs", "output"],
[
({}, "\u001b[1;1H"),
({"n": 3}, "\u001b[3;1H"),
({"m": 3}, "\u001b[1;3H"),
({"n": 3, "m": 3}, "\u001b[3;3H"),
],
)
def test_cursor_position(kwargs, output):
assert cursor_position(**kwargs) == output


def test_erase_in_display():
assert erase_in_display(1) == "\u001b[1J"


def test_erase_in_line():
assert erase_in_line(1) == "\u001b[1K"


@pytest.mark.parametrize(
["args", "output"],
[
((), "\u001b[1S"),
((3,), "\u001b[3S"),
],
)
def test_scroll_up(args, output):
assert scroll_up(*args) == output


@pytest.mark.parametrize(
["args", "output"],
[
((), "\u001b[1T"),
((3,), "\u001b[3T"),
],
)
def test_scroll_down(args, output):
assert scroll_down(*args) == output


@pytest.mark.parametrize(
["kwargs", "output"],
[
({}, "\u001b[1;1f"),
({"n": 3}, "\u001b[3;1f"),
({"n": 3, "m": 4}, "\u001b[3;4f"),
({"m": 4}, "\u001b[1;4f"),
],
)
def test_horizontal_vertical_position(kwargs, output):
assert horizontal_vertical_position(**kwargs) == output


def test_alternative_font():
assert alternative_font(1) == "\x1b[11m"


def test_foreground_truecolor():
assert foreground_truecolor(255, 255, 255) == "\x1b[38;2;255;255;255m"


def test_background_truecolor():
assert background_truecolor(255, 255, 255) == "\x1b[48;2;255;255;255m"


def test_underline_truecolor():
assert underline_truecolor(255, 255, 255) == "\x1b[58;2;255;255;255m"

0 comments on commit b54fb58

Please sign in to comment.