test: cover app and playback controller mixin behavior

This commit is contained in:
2026-02-18 03:17:48 +01:00
parent 4bc9b3fd3f
commit e88dcee155
8 changed files with 791 additions and 0 deletions

View File

@@ -0,0 +1,148 @@
from __future__ import annotations
from dataclasses import dataclass
from typing import cast
from auditui.app.progress import AppProgressMixin
from textual.events import Key
from textual.widgets import DataTable
@dataclass(slots=True)
class FakeKeyEvent:
"""Minimal key event carrying key value and prevent_default state."""
key: str
prevented: bool = False
def prevent_default(self) -> None:
"""Mark event as prevented."""
self.prevented = True
@dataclass(slots=True)
class FakeStatic:
"""Minimal static widget with text and visibility fields."""
display: bool = False
text: str = ""
def update(self, value: str) -> None:
"""Store rendered text value."""
self.text = value
@dataclass(slots=True)
class FakeProgressBar:
"""Minimal progress bar widget storing latest progress value."""
progress: float = 0.0
def update(self, progress: float) -> None:
"""Store progress value for assertions."""
self.progress = progress
@dataclass(slots=True)
class FakeContainer:
"""Minimal container exposing display property."""
display: bool = False
class DummyPlayback:
"""Playback shim exposing only members used by AppProgressMixin."""
def __init__(self) -> None:
"""Initialize playback state and update counters."""
self.is_playing = False
self._status: str | None = None
self._progress: tuple[str, float, float] | None = None
self.saved_calls = 0
def check_status(self):
"""Return configurable status check message."""
return self._status
def get_current_progress(self):
"""Return configurable progress tuple."""
return self._progress
def update_position_if_needed(self) -> None:
"""Record periodic save invocations."""
self.saved_calls += 1
class DummyProgressApp(AppProgressMixin):
"""Mixin host that records action dispatch and widget updates."""
def __init__(self) -> None:
"""Initialize fake widgets and playback state."""
self.playback = DummyPlayback()
self.focused = object()
self.actions: list[str] = []
self.messages: list[str] = []
self.progress_info = FakeStatic()
self.progress_bar = FakeProgressBar()
self.progress_container = FakeContainer()
def action_seek_backward(self) -> None:
"""Record backward seek action dispatch."""
self.actions.append("seek_backward")
def action_toggle_playback(self) -> None:
"""Record toggle playback action dispatch."""
self.actions.append("toggle")
def update_status(self, message: str) -> None:
"""Capture status messages for assertions."""
self.messages.append(message)
def query_one(self, selector: str, _type: object):
"""Return fake widgets by selector used by progress mixin."""
return {
"#progress_info": self.progress_info,
"#progress_bar": self.progress_bar,
"#progress_bar_container": self.progress_container,
}[selector]
def test_on_key_dispatches_seek_when_playing() -> None:
"""Ensure left key is intercepted and dispatched to seek action."""
app = DummyProgressApp()
app.playback.is_playing = True
event = FakeKeyEvent("left")
app.on_key(cast(Key, event))
assert event.prevented is True
assert app.actions == ["seek_backward"]
def test_on_key_dispatches_space_when_table_focused() -> None:
"""Ensure space is intercepted and dispatched when table is focused."""
app = DummyProgressApp()
app.focused = DataTable()
event = FakeKeyEvent("space")
app.on_key(cast(Key, event))
assert event.prevented is True
assert app.actions == ["toggle"]
def test_check_playback_status_hides_progress_after_message() -> None:
"""Ensure playback status message triggers hide-progress behavior."""
app = DummyProgressApp()
app.playback._status = "Finished"
app._check_playback_status()
assert app.messages[-1] == "Finished"
assert app.progress_info.display is False
assert app.progress_container.display is False
def test_update_progress_renders_visible_progress_row() -> None:
"""Ensure valid progress data updates widgets and makes them visible."""
app = DummyProgressApp()
app.playback.is_playing = True
app.playback._progress = ("Chapter", 30.0, 60.0)
app._update_progress()
assert app.progress_bar.progress == 50.0
assert app.progress_info.display is True
assert app.progress_container.display is True