Clamp the progress gauge ratio

The player position can overrun a stale or wrong duration (streams,
hand-written track files), and ratatui's LineGauge asserts its ratio
into 0..=1 — the TUI died with "ratio should be between 0 and 1"
mid-playback. Clamp instead, with render regression tests for both the
overrun and the zero-duration case.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Test User 2026-07-21 02:06:02 +02:00
parent 955c7ea5b4
commit 8bb653ab3e
1 changed files with 52 additions and 1 deletions

View File

@ -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));
}
}