use rinkaku_tui::review::ports::BrowserOpener;
pub(crate) struct SystemBrowserOpener;
fn command_for_os(target_os: &str) -> Option<&'static str> {
match target_os {
"macos" => Some("open"),
"linux" => Some("xdg-open"),
_ => None,
}
}
fn open_via_command(program: &str, url: &str) -> Result<(), String> {
let status = std::process::Command::new(program)
.arg(url)
.stdin(std::process::Stdio::null())
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::piped())
.spawn()
.map_err(|err| format!("failed to spawn {program}: {err}"))?
.wait()
.map_err(|err| format!("failed to wait for {program}: {err}"))?;
if !status.success() {
return Err(format!("{program} exited with {status}"));
}
Ok(())
}
impl BrowserOpener for SystemBrowserOpener {
fn open_url(&self, url: &str) -> Result<(), String> {
let Some(program) = command_for_os(std::env::consts::OS) else {
return Err(format!(
"no known browser-open command for platform {}",
std::env::consts::OS
));
};
open_via_command(program, url)
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn should_choose_open_on_macos() {
let actual = command_for_os("macos");
assert_eq!(Some("open"), actual);
}
#[test]
fn should_choose_xdg_open_on_linux() {
let actual = command_for_os("linux");
assert_eq!(Some("xdg-open"), actual);
}
#[test]
fn should_return_none_for_an_unsupported_platform() {
let actual = command_for_os("windows");
assert_eq!(None, actual);
}
#[test]
fn should_report_spawn_failure_when_command_does_not_exist() {
let actual = open_via_command("rinkaku-nonexistent-browser-cmd", "https://example.com");
assert_eq!(
true,
actual
.unwrap_err()
.starts_with("failed to spawn rinkaku-nonexistent-browser-cmd")
);
}
}