mirror of
https://github.com/talwat/lowfi
synced 2026-05-12 19:43:18 +00:00
for some reason, rodio decided it would be a great idea to change all of the core terminology to be less technical. this is frankly strange, but it's best not to use an outdated version of the dependency. rodio is for some reason switching to a "breaking change every single update" versioning model. why? i have frankly no idea, semver exists for a reason and they decided just not to use it. 0.x.x is stupid, and people should realize semver exists for a reason. to the total of zero people who will read this, thanks for reading my short rant.
227 lines
6.2 KiB
Rust
227 lines
6.2 KiB
Rust
/* The lowfi UI:
|
|
┌─────────────────────────────┐
|
|
│ loading │
|
|
│ [ ] 00:00/00:00 │
|
|
│ [s]kip [p]ause [q]uit │
|
|
└─────────────────────────────┘
|
|
*/
|
|
|
|
#[cfg(test)]
|
|
mod components {
|
|
use crate::ui::interface;
|
|
|
|
use std::time::Duration;
|
|
|
|
#[test]
|
|
fn format_duration_works() {
|
|
let d = Duration::from_secs(62);
|
|
assert_eq!(interface::components::format_duration(&d), "01:02");
|
|
}
|
|
|
|
#[test]
|
|
fn format_duration_zero() {
|
|
let d = Duration::from_secs(0);
|
|
assert_eq!(interface::components::format_duration(&d), "00:00");
|
|
}
|
|
|
|
#[test]
|
|
fn format_duration_hours_wrap() {
|
|
let d = Duration::from_secs(3661); // 1:01:01
|
|
assert_eq!(interface::components::format_duration(&d), "61:01");
|
|
}
|
|
|
|
#[test]
|
|
fn audio_bar_contains_percentage() {
|
|
let s = interface::components::audio_bar(10, 0.5, "50%");
|
|
assert!(s.contains("50%"));
|
|
assert!(s.starts_with(" volume:"));
|
|
}
|
|
|
|
#[test]
|
|
fn audio_bar_muted_volume() {
|
|
let s = interface::components::audio_bar(8, 0.0, "0%");
|
|
assert!(s.contains("0%"));
|
|
}
|
|
|
|
#[test]
|
|
fn audio_bar_full_volume() {
|
|
let s = interface::components::audio_bar(10, 1.0, "100%");
|
|
assert!(s.contains("100%"));
|
|
}
|
|
|
|
#[test]
|
|
fn controls_has_items() {
|
|
let s = interface::components::controls(30);
|
|
assert!(s.contains("[s]"));
|
|
assert!(s.contains("[p]"));
|
|
assert!(s.contains("[q]"));
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod window {
|
|
use crate::ui::interface::Window;
|
|
|
|
#[test]
|
|
fn new_border_strings() {
|
|
let w = Window::new(10, false, false, false);
|
|
assert!(w.titlebar.content.starts_with('┌'));
|
|
assert!(w.statusbar.starts_with('└'));
|
|
|
|
let w2 = Window::new(5, true, false, false);
|
|
assert!(w2.titlebar.content.is_empty());
|
|
assert!(w2.statusbar.is_empty());
|
|
}
|
|
|
|
fn sided(text: &str) -> String {
|
|
return format!("│ {text} │");
|
|
}
|
|
|
|
#[test]
|
|
fn simple() {
|
|
let w = Window::new(3, false, false, false);
|
|
let (render, height) = w.render(vec![String::from("abc")]).unwrap();
|
|
|
|
const MIDDLE: &str = "─────";
|
|
assert_eq!(format!("┌{MIDDLE}┐\n{}\n└{MIDDLE}┘", sided("abc")), render);
|
|
assert_eq!(height, 3);
|
|
}
|
|
|
|
#[test]
|
|
fn spaced() {
|
|
let w = Window::new(3, false, true, false);
|
|
let (render, height) = w
|
|
.render(vec![
|
|
String::from("abc"),
|
|
String::from(" b"),
|
|
String::from("c"),
|
|
])
|
|
.unwrap();
|
|
|
|
const MIDDLE: &str = "─────";
|
|
assert_eq!(
|
|
format!(
|
|
"┌{MIDDLE}┐\n{}\n{}\n{}\n└{MIDDLE}┘",
|
|
sided("abc"),
|
|
sided(" b "),
|
|
sided("c "),
|
|
),
|
|
render
|
|
);
|
|
assert_eq!(height, 5);
|
|
}
|
|
|
|
#[test]
|
|
fn zero_width_window() {
|
|
let w = Window::new(0, false, false, false);
|
|
assert!(!w.titlebar.content.is_empty());
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod interface {
|
|
use crossterm::style::Stylize;
|
|
use std::{sync::Arc, time::Duration};
|
|
use tokio::time::Instant;
|
|
|
|
use crate::{
|
|
downloader::Progress,
|
|
player::Current,
|
|
tracks,
|
|
ui::{Interface, State},
|
|
};
|
|
|
|
#[tokio::test]
|
|
async fn loading() {
|
|
let sink = Arc::new(rodio::Player::new().0);
|
|
let mut state = State::initial(sink, String::from("test"));
|
|
let menu = Interface::default().menu(&mut state);
|
|
|
|
assert_eq!(menu[0], "loading ");
|
|
assert_eq!(menu[1], " [ ] 00:00/00:00 ");
|
|
assert_eq!(
|
|
menu[2],
|
|
format!(
|
|
"{}kip {}ause {}uit",
|
|
"[s]".bold(),
|
|
"[p]".bold(),
|
|
"[q]".bold()
|
|
)
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn volume() {
|
|
let sink = Arc::new(rodio::Player::new().0);
|
|
sink.set_volume(0.5);
|
|
|
|
let mut state = State::initial(sink, String::from("test"));
|
|
state.volume_timer = Some(Instant::now());
|
|
|
|
let menu = Interface::default().menu(&mut state);
|
|
assert_eq!(menu[0], "loading ");
|
|
assert_eq!(menu[1], " volume: [///// ] 50% ");
|
|
assert_eq!(
|
|
menu[2],
|
|
format!(
|
|
"{}kip {}ause {}uit",
|
|
"[s]".bold(),
|
|
"[p]".bold(),
|
|
"[q]".bold()
|
|
)
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn progress() {
|
|
let sink = Arc::new(rodio::Player::new().0);
|
|
Progress::new().set(0.5);
|
|
let mut state = State::initial(sink, String::from("test"));
|
|
state.current = Current::Loading(Some(Progress::new()));
|
|
|
|
let menu = Interface::default().menu(&mut state);
|
|
|
|
assert_eq!(menu[0], format!("loading {} ", "50%".bold()));
|
|
assert_eq!(menu[1], " [ ] 00:00/00:00 ");
|
|
assert_eq!(
|
|
menu[2],
|
|
format!(
|
|
"{}kip {}ause {}uit",
|
|
"[s]".bold(),
|
|
"[p]".bold(),
|
|
"[q]".bold()
|
|
)
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn track() {
|
|
let sink = Arc::new(rodio::Player::new().0);
|
|
let track = tracks::Info {
|
|
path: "/path".to_owned(),
|
|
display: "Test Track".to_owned(),
|
|
width: 4 + 1 + 5,
|
|
duration: Some(Duration::from_secs(8)),
|
|
};
|
|
|
|
let mut state = State::initial(sink, String::from("test"));
|
|
state.current = Current::Track(track.clone());
|
|
let menu = Interface::default().menu(&mut state);
|
|
|
|
assert_eq!(
|
|
menu[0],
|
|
format!("playing {} ", track.display.bold())
|
|
);
|
|
assert_eq!(menu[1], " [ ] 00:00/00:08 ");
|
|
assert_eq!(
|
|
menu[2],
|
|
format!(
|
|
"{}kip {}ause {}uit",
|
|
"[s]".bold(),
|
|
"[p]".bold(),
|
|
"[q]".bold()
|
|
)
|
|
);
|
|
}
|
|
}
|