use std::path::PathBuf;
pub struct SocketPath;
impl SocketPath {
#[must_use]
pub fn for_app(app_name: &str) -> PathBuf {
Self::runtime_base(app_name).join(format!("{app_name}.sock"))
}
#[must_use]
pub fn pid_file(app_name: &str) -> PathBuf {
Self::runtime_base(app_name).join(format!("{app_name}.pid"))
}
#[must_use]
pub fn runtime_base(app_name: &str) -> PathBuf {
let base = std::env::var("XDG_RUNTIME_DIR").map_or_else(
|_| dirs::runtime_dir().unwrap_or_else(std::env::temp_dir),
PathBuf::from,
);
base.join(app_name)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn socket_path_contains_app_name() {
let path = SocketPath::for_app("tobira");
assert!(path.to_string_lossy().contains("tobira"));
assert!(path.to_string_lossy().ends_with("tobira.sock"));
}
#[test]
fn pid_file_contains_app_name() {
let path = SocketPath::pid_file("tobira");
assert!(path.to_string_lossy().contains("tobira"));
assert!(path.to_string_lossy().ends_with("tobira.pid"));
}
#[test]
fn socket_and_pid_share_directory() {
let sock = SocketPath::for_app("myapp");
let pid = SocketPath::pid_file("myapp");
assert_eq!(sock.parent(), pid.parent());
}
#[test]
fn runtime_base_contains_app_name() {
let base = SocketPath::runtime_base("karakuri");
assert!(base.to_string_lossy().ends_with("karakuri"));
}
#[test]
fn respects_xdg_runtime_dir() {
unsafe { std::env::set_var("XDG_RUNTIME_DIR", "/tmp/test-xdg-runtime") };
let path = SocketPath::for_app("test");
unsafe { std::env::remove_var("XDG_RUNTIME_DIR") };
assert!(path.starts_with("/tmp/test-xdg-runtime/test"));
}
}