diff --git a/cbd-tui/src/app/now_playing.rs b/cbd-tui/src/app/now_playing.rs index 119a1e2..e5ec91b 100644 --- a/cbd-tui/src/app/now_playing.rs +++ b/cbd-tui/src/app/now_playing.rs @@ -142,10 +142,16 @@ impl NowPlaying { .constraints([Constraint::Min(10), Constraint::Max(completion_size)]) .split(now_playing_layout[1]); + // Clamped: the player's position can overrun a stale or wrong + // duration (streams, hand-written track files), and + // `LineGauge` panics on ratios outside 0..=1. let ratio = if duration.is_zero() { 0.0 } else { - position.as_secs_f64().div(duration.as_secs_f64()) + position + .as_secs_f64() + .div(duration.as_secs_f64()) + .clamp(0.0, 1.0) }; let progress = LineGauge::default() @@ -180,3 +186,48 @@ impl NowPlaying { } } } + +#[cfg(test)] +mod tests { + use super::*; + use ratatui::{backend::TestBackend, Terminal}; + + /// A now-playing pane mid-track, built directly (no `update_track`, + /// which fires a desktop notification). + fn now_playing(position_ms: u32, duration_ms: u32) -> NowPlaying { + NowPlaying { + play_state: PlayState::Playing, + duration: Some(Duration::from_millis(duration_ms.into())), + modifiers: QueueModifiers::default(), + position: Some(Duration::from_millis(position_ms.into())), + track: Some(Track { + path: "/fs/radio.cbd-track.toml".to_string(), + artist: "artist".to_string(), + title: "title".to_string(), + duration: None, + album: None, + }), + } + } + + fn render(pane: &NowPlaying) { + let backend = TestBackend::new(60, 12); + let mut terminal = Terminal::new(backend).expect("test terminal"); + terminal + .draw(|f| pane.render(f, f.area())) + .expect("draw must not panic"); + } + + /// The position can overrun a stale or wrong duration (streams, + /// hand-written track files); the gauge must clamp instead of hitting + /// ratatui's `ratio should be between 0 and 1` panic. + #[test] + fn progress_gauge_survives_position_past_duration() { + render(&now_playing(90_000, 60_000)); + } + + #[test] + fn progress_gauge_survives_a_zero_duration() { + render(&now_playing(5_000, 0)); + } +}