use std::{
fs::{File, copy, create_dir, create_dir_all, remove_dir_all},
io::Write,
os::unix::fs::symlink,
path::PathBuf,
process::{Command, Stdio},
};
use mpdclient::{Connection, connection::idle::IdleReturn};
use rand::Rng;
pub fn setup_mpd(
setup: impl Fn(TestPath) -> eyre::Result<()>,
conn: impl Fn(Connection) -> eyre::Result<()>,
) -> eyre::Result<()> {
let id: String = format!("{:05}", rand::rng().random::<u16>());
println!("==== Test: {id} ====");
let tmp = get_tmp();
let test_path = PathBuf::from(tmp).join("mpdclient-tests").join(id);
if test_path.exists() {
remove_dir_all(&test_path)?;
}
create_dir_all(&test_path)?;
println!("Path: {}", test_path.to_string_lossy());
create_dir(test_path.join("music"))?;
create_dir(test_path.join("playlists"))?;
setup(TestPath {
path: test_path.clone(),
})?;
let mpd_conf = test_path.join("mpd.conf");
File::create(&mpd_conf)?.write_all(
include_str!("../assets/mpd.conf")
.replace("%pwd%", &test_path.to_string_lossy())
.as_bytes(),
)?;
let mut mpd = Command::new("mpd")
.arg("--no-daemon")
.arg(mpd_conf)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
println!("MPD pid: {}", mpd.id());
let mpd_sock = test_path.join("mpd.sock");
while !mpd_sock.exists() {
std::thread::sleep(std::time::Duration::from_millis(10));
}
let connection = Connection::connect(Some(&mpd_sock.to_string_lossy()), 0, 0)?;
if connection.status()?.update() {
connection.idle().idle_mask(&[IdleReturn::Update])?;
}
let conn_res = conn(connection);
mpd.kill()?;
conn_res?;
remove_dir_all(test_path)?;
Ok(())
}
pub fn get_tmp() -> String {
std::env::var("TMPDIR").unwrap_or("/tmp".to_string())
}
pub struct TestPath {
pub path: PathBuf,
}
#[allow(unused)]
impl TestPath {
fn music_dir(&self) -> PathBuf {
self.path.join("music")
}
fn playlists_dir(&self) -> PathBuf {
self.path.join("playlists")
}
pub fn song(&self, target: &str) -> eyre::Result<()> {
symlink(
PathBuf::from("tests/assets/silence.mp3").canonicalize()?,
self.music_dir().join(format!("{target}.mp3")),
)?;
Ok(())
}
pub fn song_copy(&self, target: &str) -> eyre::Result<()> {
copy(
PathBuf::from("tests/assets/silence.mp3").canonicalize()?,
self.music_dir().join(format!("{target}.mp3")),
)?;
Ok(())
}
pub fn playlist(&self) -> eyre::Result<()> {
copy(
PathBuf::from("tests/assets/playlist.m3u").canonicalize()?,
self.playlists_dir().join("playlist.m3u"),
)?;
Ok(())
}
pub fn directory(&self) -> eyre::Result<()> {
create_dir(self.music_dir().join("dir"))?;
Ok(())
}
pub fn file(&self, target: &str) -> eyre::Result<()> {
File::create(self.music_dir().join(target))?;
Ok(())
}
}