mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-06 23:35:08 +00:00
Whole-tree audit. Every symbol was checked against core, the plugin monorepo and all eight third-party plugins in plugins.json first. - Deprecate (removal 3.10.0) plugin-facing methods nothing calls: LogoDownloader bulk download, ConfigManager backup/secret wrappers, APIHelper extras, BackgroundDataService poll API, PluginManager / PluginStateManager info readers, and a few CacheManager, FontManager, BaseOddsManager, DynamicTeamResolver methods and PluginTestCase. plugin_api_usage.py learns their receiver names; DEPRECATIONS doc regenerated. - Remove core-internal dead code: CacheMetrics, Vegas status/stats plumbing, sync "new cycle" message (followers ignore unknown types), unused operation types, test-only PluginCatalog readers, IPC to_dict and ping, _parse_form_value, CacheStrategyProtocol, ErrorAggregator callbacks, duplicate web response helpers. - Web UI: drop never-mounted json-file-manager.js, the example widget, utils/error_handler.js, four uncalled PluginAPI methods, and 29 escapeHtml shims (call window.LEDEscape directly). Public globals, BaseWidget and widget names unchanged. - Remove six one-off scripts (owner decision) and the unused markupsafe and pytest-mock pins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
238 lines
8.4 KiB
Python
238 lines
8.4 KiB
Python
"""
|
|
Tests for src/vegas_mode/config.py
|
|
|
|
Covers VegasModeConfig: from_config, get_frame_interval,
|
|
get_ordered_plugins, validate.
|
|
"""
|
|
|
|
import dataclasses
|
|
|
|
import pytest
|
|
from src.vegas_mode.config import VegasModeConfig
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Default construction
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class TestVegasModeConfigDefaults:
|
|
def test_default_disabled(self):
|
|
cfg = VegasModeConfig()
|
|
assert cfg.enabled is False
|
|
|
|
def test_default_scroll_speed(self):
|
|
cfg = VegasModeConfig()
|
|
assert cfg.scroll_speed == 50.0
|
|
|
|
def test_default_separator_width(self):
|
|
cfg = VegasModeConfig()
|
|
assert cfg.separator_width == 32
|
|
|
|
def test_default_target_fps(self):
|
|
cfg = VegasModeConfig()
|
|
assert cfg.target_fps == 125
|
|
|
|
def test_default_plugin_order_empty(self):
|
|
cfg = VegasModeConfig()
|
|
assert cfg.plugin_order == []
|
|
|
|
def test_default_excluded_plugins_empty(self):
|
|
cfg = VegasModeConfig()
|
|
assert len(cfg.excluded_plugins) == 0
|
|
|
|
def test_defaults_match_the_shipped_template(self):
|
|
# The template, the web UI help and CONFIG_REFERENCE all document
|
|
# these values. max_cycle_duration defaulted to 600 in code while all
|
|
# three said 240, so an install without the key ran iterations 2.5x
|
|
# longer than documented.
|
|
import json
|
|
from pathlib import Path
|
|
template = json.loads(
|
|
(Path(__file__).resolve().parent.parent / "config"
|
|
/ "config.template.json").read_text(encoding="utf-8"))
|
|
shipped = template["display"]["vegas_scroll"]
|
|
defaults = dataclasses.asdict(VegasModeConfig())
|
|
defaults["excluded_plugins"] = sorted(defaults["excluded_plugins"])
|
|
mismatched = {k: (v, defaults[k]) for k, v in shipped.items()
|
|
if k in defaults and defaults[k] != v}
|
|
assert not mismatched, f"template vs code default: {mismatched}"
|
|
|
|
def test_missing_keys_read_the_field_defaults(self):
|
|
# from_config used to repeat every default; with no keys set it must
|
|
# produce exactly the dataclass defaults.
|
|
assert VegasModeConfig.from_config({}) == VegasModeConfig()
|
|
assert (VegasModeConfig.from_config({"display": {"vegas_scroll": {}}})
|
|
== VegasModeConfig())
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# from_config
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class TestFromConfig:
|
|
def _cfg(self, **kwargs) -> dict:
|
|
return {"display": {"vegas_scroll": kwargs}}
|
|
|
|
def test_enabled_flag(self):
|
|
cfg = VegasModeConfig.from_config(self._cfg(enabled=True))
|
|
assert cfg.enabled is True
|
|
|
|
def test_scroll_speed(self):
|
|
cfg = VegasModeConfig.from_config(self._cfg(scroll_speed=80.0))
|
|
assert cfg.scroll_speed == 80.0
|
|
|
|
def test_separator_width(self):
|
|
cfg = VegasModeConfig.from_config(self._cfg(separator_width=16))
|
|
assert cfg.separator_width == 16
|
|
|
|
def test_plugin_order(self):
|
|
cfg = VegasModeConfig.from_config(self._cfg(plugin_order=["a", "b", "c"]))
|
|
assert cfg.plugin_order == ["a", "b", "c"]
|
|
|
|
def test_excluded_plugins(self):
|
|
cfg = VegasModeConfig.from_config(self._cfg(excluded_plugins=["x", "y"]))
|
|
assert "x" in cfg.excluded_plugins
|
|
assert "y" in cfg.excluded_plugins
|
|
|
|
def test_target_fps(self):
|
|
cfg = VegasModeConfig.from_config(self._cfg(target_fps=60))
|
|
assert cfg.target_fps == 60
|
|
|
|
def test_buffer_ahead(self):
|
|
cfg = VegasModeConfig.from_config(self._cfg(buffer_ahead=3))
|
|
assert cfg.buffer_ahead == 3
|
|
|
|
def test_min_max_cycle_duration(self):
|
|
cfg = VegasModeConfig.from_config(self._cfg(min_cycle_duration=30, max_cycle_duration=120))
|
|
assert cfg.min_cycle_duration == 30
|
|
assert cfg.max_cycle_duration == 120
|
|
|
|
def test_defaults_when_missing(self):
|
|
cfg = VegasModeConfig.from_config({})
|
|
assert cfg.enabled is False
|
|
assert cfg.scroll_speed == 50.0
|
|
|
|
def test_frame_based_scrolling(self):
|
|
cfg = VegasModeConfig.from_config(self._cfg(frame_based_scrolling=False))
|
|
assert cfg.frame_based_scrolling is False
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# get_frame_interval
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class TestGetFrameInterval:
|
|
def test_125fps(self):
|
|
cfg = VegasModeConfig(target_fps=125)
|
|
assert abs(cfg.get_frame_interval() - 1.0 / 125) < 1e-9
|
|
|
|
def test_60fps(self):
|
|
cfg = VegasModeConfig(target_fps=60)
|
|
assert abs(cfg.get_frame_interval() - 1.0 / 60) < 1e-6
|
|
|
|
def test_zero_fps_guarded(self):
|
|
cfg = VegasModeConfig(target_fps=0)
|
|
# Should not raise ZeroDivisionError (max(1, fps) guard)
|
|
result = cfg.get_frame_interval()
|
|
assert result == 1.0
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# get_ordered_plugins
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class TestGetOrderedPlugins:
|
|
def test_natural_order_when_no_order_configured(self):
|
|
cfg = VegasModeConfig()
|
|
available = ["a", "b", "c"]
|
|
result = cfg.get_ordered_plugins(available)
|
|
assert result == ["a", "b", "c"]
|
|
|
|
def test_explicit_order_followed(self):
|
|
cfg = VegasModeConfig(plugin_order=["c", "a", "b"])
|
|
available = ["a", "b", "c"]
|
|
result = cfg.get_ordered_plugins(available)
|
|
assert result == ["c", "a", "b"]
|
|
|
|
def test_unavailable_plugins_skipped(self):
|
|
cfg = VegasModeConfig(plugin_order=["c", "x", "a"])
|
|
available = ["a", "b", "c"]
|
|
result = cfg.get_ordered_plugins(available)
|
|
assert "x" not in result
|
|
assert result[:2] == ["c", "a"]
|
|
|
|
def test_excluded_plugins_removed(self):
|
|
cfg = VegasModeConfig(excluded_plugins={"b"})
|
|
available = ["a", "b", "c"]
|
|
result = cfg.get_ordered_plugins(available)
|
|
assert "b" not in result
|
|
|
|
def test_unordered_available_appended(self):
|
|
cfg = VegasModeConfig(plugin_order=["a"])
|
|
available = ["a", "b", "c"]
|
|
result = cfg.get_ordered_plugins(available)
|
|
assert result[0] == "a"
|
|
assert "b" in result
|
|
assert "c" in result
|
|
|
|
def test_empty_available(self):
|
|
cfg = VegasModeConfig(plugin_order=["a"])
|
|
result = cfg.get_ordered_plugins([])
|
|
assert result == []
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# validate
|
|
# ---------------------------------------------------------------------------
|
|
|
|
class TestValidate:
|
|
def test_valid_config_no_errors(self):
|
|
cfg = VegasModeConfig()
|
|
errors = cfg.validate()
|
|
assert errors == []
|
|
|
|
def test_scroll_speed_too_low(self):
|
|
cfg = VegasModeConfig(scroll_speed=0.5)
|
|
errors = cfg.validate()
|
|
assert any("scroll_speed" in e for e in errors)
|
|
|
|
def test_scroll_speed_too_high(self):
|
|
cfg = VegasModeConfig(scroll_speed=300.0)
|
|
errors = cfg.validate()
|
|
assert any("scroll_speed" in e for e in errors)
|
|
|
|
def test_separator_width_negative(self):
|
|
cfg = VegasModeConfig(separator_width=-1)
|
|
errors = cfg.validate()
|
|
assert any("separator_width" in e for e in errors)
|
|
|
|
def test_separator_width_too_large(self):
|
|
cfg = VegasModeConfig(separator_width=200)
|
|
errors = cfg.validate()
|
|
assert any("separator_width" in e for e in errors)
|
|
|
|
def test_target_fps_too_low(self):
|
|
cfg = VegasModeConfig(target_fps=10)
|
|
errors = cfg.validate()
|
|
assert any("target_fps" in e for e in errors)
|
|
|
|
def test_target_fps_too_high(self):
|
|
cfg = VegasModeConfig(target_fps=300)
|
|
errors = cfg.validate()
|
|
assert any("target_fps" in e for e in errors)
|
|
|
|
def test_buffer_ahead_too_low(self):
|
|
cfg = VegasModeConfig(buffer_ahead=0)
|
|
errors = cfg.validate()
|
|
assert any("buffer_ahead" in e for e in errors)
|
|
|
|
def test_buffer_ahead_too_high(self):
|
|
cfg = VegasModeConfig(buffer_ahead=10)
|
|
errors = cfg.validate()
|
|
assert any("buffer_ahead" in e for e in errors)
|
|
|
|
def test_multiple_errors_returned(self):
|
|
cfg = VegasModeConfig(scroll_speed=0.1, target_fps=5)
|
|
errors = cfg.validate()
|
|
assert len(errors) >= 2
|