from __future__ import annotations from io import BytesIO import httpx import pytest from PIL import Image from beefy_player import artwork def png_bytes(size=(400, 200)) -> bytes: buffer = BytesIO() Image.new("RGBA", size, (20, 180, 220, 180)).save(buffer, format="PNG") return buffer.getvalue() def test_protocol_detection() -> None: assert artwork.detect_protocol({"KITTY_WINDOW_ID": "1"}) == "tgp" assert artwork.detect_protocol({"TERM": "xterm-kitty"}) == "tgp" assert artwork.detect_protocol({"TERM_PROGRAM": "WezTerm"}) == "iterm2" assert artwork.detect_protocol({"WEZTERM_EXECUTABLE": "/bin/wezterm"}) == "iterm2" assert artwork.detect_protocol({"TERM_PROGRAM": "iTerm.app"}) == "iterm2" assert artwork.detect_protocol({"ITERM_SESSION_ID": "x"}) == "iterm2" assert artwork.detect_protocol({"TERM_PROGRAM": "Apple_Terminal"}) is None assert artwork.detect_protocol({"TMUX": "/tmp/tmux", "KITTY_WINDOW_ID": "1"}) == "tgp" assert artwork.detect_protocol({"TMUX": "/tmp/tmux", "TERM_PROGRAM": "WezTerm"}) is None assert artwork.detect_protocol({"ZELLIJ": "1", "TERM_PROGRAM": "WezTerm"}) is None assert artwork.detect_protocol({"KITTY_PID": "1"}) == "tgp" assert artwork.detect_protocol({"NO_COLOR": "", "KITTY_WINDOW_ID": "1"}) is None assert artwork.detect_protocol({"BEEFY_IMAGES": "0", "KITTY_WINDOW_ID": "1"}) is None assert artwork.detect_protocol({"BEEFY_IMAGES": "tgp"}) == "tgp" assert artwork.detect_protocol({"BEEFY_IMAGES": "iterm2"}) == "iterm2" # the pre-rename variable still works assert artwork.detect_protocol({"SOMAFM_IMAGES": "0"}) is None def test_fit_image_crops_to_the_cell_box() -> None: fitted = artwork.fit_image(png_bytes(), 13, 8) assert fitted is not None cell_width, cell_height = artwork.cell_size() expected = (13 * cell_width) / (8 * cell_height) assert fitted.width / fitted.height == pytest.approx(expected, rel=0.01) assert artwork.fit_image(b"not an image", 13, 8) is None def test_image_cache_roundtrip() -> None: data = png_bytes() url = "https://example.invalid/art.png" artwork.save_cached(url, data) assert artwork.load_cached(url) == data assert artwork.load_cached("https://example.invalid/other.png") is None @pytest.mark.asyncio async def test_fetch_validates_and_caches() -> None: data = png_bytes((120, 120)) url = "https://example.invalid/logo.png" def handler(request: httpx.Request) -> httpx.Response: return httpx.Response(200, content=data, headers={"content-type": "image/png"}) async with httpx.AsyncClient(transport=httpx.MockTransport(handler)) as client: fetched = await artwork.fetch(client, url) assert fetched == data assert artwork.load_cached(url) == data def test_multiplexer_env_values_that_mean_no() -> None: # Some wrappers export ZELLIJ=0 / TMUX=0 outside a multiplexer; that must # not disable iTerm2 or Kitty graphics. assert artwork.detect_protocol({"ZELLIJ": "0", "TERM_PROGRAM": "iTerm.app"}) == "iterm2" assert artwork.detect_protocol({"ZELLIJ": "", "TERM_PROGRAM": "iTerm.app"}) == "iterm2" assert artwork.detect_protocol({"TMUX": "0", "KITTY_WINDOW_ID": "1"}) == "tgp" # ...while a real multiplexer still downgrades to the mosaic. assert artwork.detect_protocol({"TMUX": "/tmp/tmux-501/default,1,0", "TERM_PROGRAM": "iTerm.app"}) is None assert artwork.detect_protocol({"STY": "1234.pts-0.host", "TERM_PROGRAM": "iTerm.app"}) is None