forked from genewildish/Mainline
217 lines
7.2 KiB
Python
217 lines
7.2 KiB
Python
"""
|
|
Tests for engine.config module.
|
|
"""
|
|
|
|
import sys
|
|
import tempfile
|
|
from pathlib import Path
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
|
|
from engine import config
|
|
|
|
|
|
class TestArgValue:
|
|
"""Tests for _arg_value helper."""
|
|
|
|
def test_returns_value_when_flag_present(self):
|
|
"""Returns the value following the flag."""
|
|
with patch.object(sys, "argv", ["prog", "--font-file", "test.otf"]):
|
|
result = config._arg_value("--font-file")
|
|
assert result == "test.otf"
|
|
|
|
def test_returns_none_when_flag_missing(self):
|
|
"""Returns None when flag is not present."""
|
|
with patch.object(sys, "argv", ["prog"]):
|
|
result = config._arg_value("--font-file")
|
|
assert result is None
|
|
|
|
def test_returns_none_when_no_value(self):
|
|
"""Returns None when flag is last."""
|
|
with patch.object(sys, "argv", ["prog", "--font-file"]):
|
|
result = config._arg_value("--font-file")
|
|
assert result is None
|
|
|
|
|
|
class TestArgInt:
|
|
"""Tests for _arg_int helper."""
|
|
|
|
def test_parses_valid_int(self):
|
|
"""Parses valid integer."""
|
|
with patch.object(sys, "argv", ["prog", "--font-index", "5"]):
|
|
result = config._arg_int("--font-index", 0)
|
|
assert result == 5
|
|
|
|
def test_returns_default_on_invalid(self):
|
|
"""Returns default on invalid input."""
|
|
with patch.object(sys, "argv", ["prog", "--font-index", "abc"]):
|
|
result = config._arg_int("--font-index", 0)
|
|
assert result == 0
|
|
|
|
def test_returns_default_when_missing(self):
|
|
"""Returns default when flag missing."""
|
|
with patch.object(sys, "argv", ["prog"]):
|
|
result = config._arg_int("--font-index", 10)
|
|
assert result == 10
|
|
|
|
|
|
class TestResolveFontPath:
|
|
"""Tests for _resolve_font_path helper."""
|
|
|
|
def test_returns_absolute_paths(self):
|
|
"""Absolute paths are returned as-is."""
|
|
result = config._resolve_font_path("/absolute/path.otf")
|
|
assert result == "/absolute/path.otf"
|
|
|
|
def test_resolves_relative_paths(self):
|
|
"""Relative paths are resolved to repo root."""
|
|
result = config._resolve_font_path("fonts/test.otf")
|
|
assert str(config._REPO_ROOT) in result
|
|
|
|
def test_expands_user_home(self):
|
|
"""Tilde paths are expanded."""
|
|
with patch("pathlib.Path.expanduser", return_value=Path("/home/user/fonts")):
|
|
result = config._resolve_font_path("~/fonts/test.otf")
|
|
assert isinstance(result, str)
|
|
|
|
|
|
class TestListFontFiles:
|
|
"""Tests for _list_font_files helper."""
|
|
|
|
def test_returns_empty_for_missing_dir(self):
|
|
"""Returns empty list for missing directory."""
|
|
result = config._list_font_files("/nonexistent/directory")
|
|
assert result == []
|
|
|
|
def test_filters_by_extension(self):
|
|
"""Only returns valid font extensions."""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
Path(tmpdir, "valid.otf").touch()
|
|
Path(tmpdir, "valid.ttf").touch()
|
|
Path(tmpdir, "invalid.txt").touch()
|
|
Path(tmpdir, "image.png").touch()
|
|
|
|
result = config._list_font_files(tmpdir)
|
|
assert len(result) == 2
|
|
assert all(f.endswith((".otf", ".ttf")) for f in result)
|
|
|
|
def test_sorts_alphabetically(self):
|
|
"""Results are sorted alphabetically."""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
Path(tmpdir, "zfont.otf").touch()
|
|
Path(tmpdir, "afont.otf").touch()
|
|
|
|
result = config._list_font_files(tmpdir)
|
|
filenames = [Path(f).name for f in result]
|
|
assert filenames == ["afont.otf", "zfont.otf"]
|
|
|
|
|
|
class TestDefaults:
|
|
"""Tests for default configuration values."""
|
|
|
|
def test_headline_limit(self):
|
|
"""HEADLINE_LIMIT has sensible default."""
|
|
assert config.HEADLINE_LIMIT > 0
|
|
|
|
def test_feed_timeout(self):
|
|
"""FEED_TIMEOUT has sensible default."""
|
|
assert config.FEED_TIMEOUT > 0
|
|
|
|
def test_font_extensions(self):
|
|
"""Font extensions are defined."""
|
|
assert ".otf" in config._FONT_EXTENSIONS
|
|
assert ".ttf" in config._FONT_EXTENSIONS
|
|
assert ".ttc" in config._FONT_EXTENSIONS
|
|
|
|
|
|
class TestGlyphs:
|
|
"""Tests for glyph constants."""
|
|
|
|
def test_glitch_glyphs_defined(self):
|
|
"""GLITCH glyphs are defined."""
|
|
assert len(config.GLITCH) > 0
|
|
|
|
def test_kata_glyphs_defined(self):
|
|
"""KATA glyphs are defined."""
|
|
assert len(config.KATA) > 0
|
|
|
|
|
|
class TestSetFontSelection:
|
|
"""Tests for set_font_selection function."""
|
|
|
|
def test_updates_font_path(self):
|
|
"""Updates FONT_PATH globally."""
|
|
original = config.FONT_PATH
|
|
config.set_font_selection(font_path="/new/path.otf")
|
|
assert config.FONT_PATH == "/new/path.otf"
|
|
config.FONT_PATH = original
|
|
|
|
def test_updates_font_index(self):
|
|
"""Updates FONT_INDEX globally."""
|
|
original = config.FONT_INDEX
|
|
config.set_font_selection(font_index=5)
|
|
assert config.FONT_INDEX == 5
|
|
config.FONT_INDEX = original
|
|
|
|
def test_handles_none_values(self):
|
|
"""Handles None values gracefully."""
|
|
original_path = config.FONT_PATH
|
|
original_index = config.FONT_INDEX
|
|
|
|
config.set_font_selection(font_path=None, font_index=None)
|
|
assert original_path == config.FONT_PATH
|
|
assert original_index == config.FONT_INDEX
|
|
|
|
|
|
class TestActiveTheme:
|
|
"""Tests for ACTIVE_THEME global and set_active_theme function."""
|
|
|
|
def test_active_theme_initially_none(self):
|
|
"""ACTIVE_THEME should be None at module start."""
|
|
# Reset to None to test initial state
|
|
original = config.ACTIVE_THEME
|
|
config.ACTIVE_THEME = None
|
|
try:
|
|
assert config.ACTIVE_THEME is None
|
|
finally:
|
|
config.ACTIVE_THEME = original
|
|
|
|
def test_set_active_theme_green(self):
|
|
"""Setting green theme works correctly."""
|
|
config.set_active_theme("green")
|
|
assert config.ACTIVE_THEME is not None
|
|
assert config.ACTIVE_THEME.name == "green"
|
|
assert len(config.ACTIVE_THEME.main_gradient) == 12
|
|
assert len(config.ACTIVE_THEME.message_gradient) == 12
|
|
|
|
def test_set_active_theme_default(self):
|
|
"""Default theme is green when not specified."""
|
|
config.set_active_theme()
|
|
assert config.ACTIVE_THEME is not None
|
|
assert config.ACTIVE_THEME.name == "green"
|
|
|
|
def test_set_active_theme_invalid(self):
|
|
"""Invalid theme_id raises KeyError."""
|
|
with pytest.raises(KeyError):
|
|
config.set_active_theme("nonexistent")
|
|
|
|
def test_set_active_theme_all_themes(self):
|
|
"""Verify orange and purple themes work."""
|
|
# Test orange
|
|
config.set_active_theme("orange")
|
|
assert config.ACTIVE_THEME.name == "orange"
|
|
|
|
# Test purple
|
|
config.set_active_theme("purple")
|
|
assert config.ACTIVE_THEME.name == "purple"
|
|
|
|
def test_set_active_theme_idempotent(self):
|
|
"""Calling set_active_theme multiple times works."""
|
|
config.set_active_theme("green")
|
|
first_theme = config.ACTIVE_THEME
|
|
config.set_active_theme("green")
|
|
second_theme = config.ACTIVE_THEME
|
|
assert first_theme.name == second_theme.name
|
|
assert first_theme.name == "green"
|