mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-09-11 10:43:46 +08:00
@@ -6,6 +6,7 @@ from pathlib import Path
|
||||
import pyray as rl
|
||||
|
||||
from openpilot.common.basedir import BASEDIR
|
||||
from openpilot.system.ui.lib.application import gui_app
|
||||
|
||||
ACTIVE_THEME_COLORS_PATH = Path(BASEDIR) / "starpilot/assets/active_theme/colors/colors.json"
|
||||
STOCK_THEME_COLORS_PATH = Path(BASEDIR) / "starpilot/assets/stock_theme/colors/colors.json"
|
||||
@@ -21,6 +22,7 @@ _FALLBACK_THEME_COLORS = {
|
||||
}
|
||||
|
||||
_THEME_COLOR_CACHE: dict[str, object] = {
|
||||
"frame": None,
|
||||
"stamp": None,
|
||||
"colors": None,
|
||||
}
|
||||
@@ -89,7 +91,12 @@ def _build_color(entry: object, fallback: tuple[int, int, int, int]) -> rl.Color
|
||||
|
||||
|
||||
def _load_theme_colors() -> dict[str, rl.Color]:
|
||||
frame = gui_app.frame
|
||||
if frame == _THEME_COLOR_CACHE["frame"] and _THEME_COLOR_CACHE["colors"] is not None:
|
||||
return _THEME_COLOR_CACHE["colors"] # type: ignore[return-value]
|
||||
|
||||
stamp = (_file_stamp(STOCK_THEME_COLORS_PATH), _file_stamp(ACTIVE_THEME_COLORS_PATH))
|
||||
_THEME_COLOR_CACHE["frame"] = frame
|
||||
if stamp == _THEME_COLOR_CACHE["stamp"] and _THEME_COLOR_CACHE["colors"] is not None:
|
||||
return _THEME_COLOR_CACHE["colors"] # type: ignore[return-value]
|
||||
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
import importlib.util
|
||||
import json
|
||||
from pathlib import Path
|
||||
import sys
|
||||
from types import ModuleType
|
||||
|
||||
MODULE_PATH = Path(__file__).resolve().parents[1] / "lib" / "starpilot_theme.py"
|
||||
SPEC = importlib.util.spec_from_file_location("starpilot_theme_under_test", MODULE_PATH)
|
||||
assert SPEC is not None and SPEC.loader is not None
|
||||
|
||||
|
||||
class FakeGuiApp:
|
||||
def __init__(self):
|
||||
self._frame = 0
|
||||
|
||||
@property
|
||||
def frame(self):
|
||||
return self._frame
|
||||
|
||||
|
||||
application_module_name = "openpilot.system.ui.lib.application"
|
||||
application_module = sys.modules.get(application_module_name)
|
||||
installed_fake_application = application_module is None
|
||||
if application_module is None:
|
||||
application_module = ModuleType(application_module_name)
|
||||
application_module.gui_app = FakeGuiApp()
|
||||
sys.modules[application_module_name] = application_module
|
||||
|
||||
starpilot_theme = importlib.util.module_from_spec(SPEC)
|
||||
SPEC.loader.exec_module(starpilot_theme)
|
||||
if installed_fake_application:
|
||||
sys.modules.pop(application_module_name, None)
|
||||
|
||||
|
||||
def _reset_theme_cache():
|
||||
starpilot_theme._THEME_COLOR_CACHE.update(frame=None, stamp=None, colors=None)
|
||||
|
||||
|
||||
def _track_file_stamps(monkeypatch):
|
||||
file_stamps = []
|
||||
original_file_stamp = starpilot_theme._file_stamp
|
||||
|
||||
def file_stamp(path):
|
||||
file_stamps.append(path)
|
||||
return original_file_stamp(path)
|
||||
|
||||
monkeypatch.setattr(starpilot_theme, "_file_stamp", file_stamp)
|
||||
return file_stamps
|
||||
|
||||
|
||||
def _color_tuple(color):
|
||||
return color.r, color.g, color.b, color.a
|
||||
|
||||
|
||||
def test_theme_files_are_checked_once_per_render_frame(tmp_path, monkeypatch):
|
||||
stock_path = tmp_path / "stock.json"
|
||||
active_path = tmp_path / "active.json"
|
||||
stock_path.write_text(json.dumps({"LaneLines": {"red": 1, "green": 2, "blue": 3}}))
|
||||
active_path.write_text(json.dumps({}))
|
||||
monkeypatch.setattr(starpilot_theme, "STOCK_THEME_COLORS_PATH", stock_path)
|
||||
monkeypatch.setattr(starpilot_theme, "ACTIVE_THEME_COLORS_PATH", active_path)
|
||||
monkeypatch.setattr(starpilot_theme.gui_app, "_frame", 10)
|
||||
file_stamps = _track_file_stamps(monkeypatch)
|
||||
_reset_theme_cache()
|
||||
|
||||
assert _color_tuple(starpilot_theme.get_theme_color("LaneLines")) == (1, 2, 3, 178)
|
||||
assert _color_tuple(starpilot_theme.get_theme_color("Path")) == (48, 255, 156, 255)
|
||||
assert len(file_stamps) == 2
|
||||
|
||||
monkeypatch.setattr(starpilot_theme.gui_app, "_frame", 11)
|
||||
starpilot_theme.get_theme_color("LeadMarker")
|
||||
assert len(file_stamps) == 4
|
||||
|
||||
|
||||
def test_theme_file_changes_are_seen_on_the_next_frame(tmp_path, monkeypatch):
|
||||
stock_path = tmp_path / "stock.json"
|
||||
active_path = tmp_path / "active.json"
|
||||
stock_path.write_text(json.dumps({}))
|
||||
active_path.write_text(json.dumps({"Path": {"red": 1, "green": 2, "blue": 3, "alpha": 4}}))
|
||||
monkeypatch.setattr(starpilot_theme, "STOCK_THEME_COLORS_PATH", stock_path)
|
||||
monkeypatch.setattr(starpilot_theme, "ACTIVE_THEME_COLORS_PATH", active_path)
|
||||
monkeypatch.setattr(starpilot_theme.gui_app, "_frame", 20)
|
||||
_reset_theme_cache()
|
||||
|
||||
assert _color_tuple(starpilot_theme.get_theme_color("Path")) == (1, 2, 3, 4)
|
||||
active_path.write_text(json.dumps({"Path": {"red": 5, "green": 6, "blue": 7, "alpha": 8}}))
|
||||
assert _color_tuple(starpilot_theme.get_theme_color("Path")) == (1, 2, 3, 4)
|
||||
|
||||
monkeypatch.setattr(starpilot_theme.gui_app, "_frame", 21)
|
||||
assert _color_tuple(starpilot_theme.get_theme_color("Path")) == (5, 6, 7, 8)
|
||||
|
||||
|
||||
def test_frame_counter_reset_checks_theme_files_again(tmp_path, monkeypatch):
|
||||
stock_path = tmp_path / "stock.json"
|
||||
active_path = tmp_path / "active.json"
|
||||
stock_path.write_text(json.dumps({}))
|
||||
active_path.write_text(json.dumps({}))
|
||||
monkeypatch.setattr(starpilot_theme, "STOCK_THEME_COLORS_PATH", stock_path)
|
||||
monkeypatch.setattr(starpilot_theme, "ACTIVE_THEME_COLORS_PATH", active_path)
|
||||
monkeypatch.setattr(starpilot_theme.gui_app, "_frame", 30)
|
||||
file_stamps = _track_file_stamps(monkeypatch)
|
||||
_reset_theme_cache()
|
||||
|
||||
starpilot_theme.get_theme_color("Path")
|
||||
monkeypatch.setattr(starpilot_theme.gui_app, "_frame", 0)
|
||||
starpilot_theme.get_theme_color("Path")
|
||||
|
||||
assert len(file_stamps) == 4
|
||||
Reference in New Issue
Block a user