use std::path::Path;
use std::process::{Command, Output};
use tempfile::TempDir;
fn aristo_bin() -> &'static str {
env!("CARGO_BIN_EXE_aristo")
}
fn run(home: &Path, cwd: &Path, args: &[&str]) -> Output {
let mut c = Command::new(aristo_bin());
c.env_clear();
if let Ok(p) = std::env::var("PATH") {
c.env("PATH", p);
}
#[cfg(target_os = "macos")]
if let Ok(p) = std::env::var("DYLD_FALLBACK_LIBRARY_PATH") {
c.env("DYLD_FALLBACK_LIBRARY_PATH", p);
}
c.env("HOME", home);
c.env("XDG_CONFIG_HOME", home.join("xdg"));
c.env("ARISTO_NO_BROWSER", "1");
c.current_dir(cwd);
c.args(args);
c.output().expect("run aristo")
}
fn stdout(out: &Output) -> String {
String::from_utf8_lossy(&out.stdout).into_owned()
}
fn git_workspace(parent: &Path, name: &str, owner_repo: &str) -> std::path::PathBuf {
let ws = parent.join(name);
let git = ws.join(".git");
std::fs::create_dir_all(&git).unwrap();
std::fs::write(
git.join("config"),
format!("[remote \"origin\"]\n url = https://github.com/{owner_repo}\n"),
)
.unwrap();
ws
}
#[test]
fn two_repos_by_flag_resolve_independently() {
let tmp = TempDir::new().unwrap();
let home = tmp.path().join("home");
std::fs::create_dir_all(&home).unwrap();
let cwd = tmp.path().join("work");
std::fs::create_dir_all(&cwd).unwrap();
let a = run(
&home,
&cwd,
&[
"auth",
"login",
"--token",
"tok_A",
"--repo",
"org/repoA",
"--server",
"https://a.example.com",
],
);
assert!(a.status.success(), "login A: {}", stdout(&a));
let b = run(
&home,
&cwd,
&[
"auth",
"login",
"--token",
"tok_B",
"--repo",
"org/repoB",
"--server",
"https://b.example.com",
],
);
assert!(b.status.success(), "login B: {}", stdout(&b));
let ta = run(&home, &cwd, &["auth", "token", "--repo", "org/repoA"]);
assert_eq!(stdout(&ta).trim(), "tok_A");
let tb = run(&home, &cwd, &["auth", "token", "--repo", "org/repoB"]);
assert_eq!(stdout(&tb).trim(), "tok_B");
let st = run(&home, &cwd, &["auth", "status"]);
let s = stdout(&st);
assert!(s.contains("org/repoA"), "status: {s}");
assert!(s.contains("org/repoB"), "status: {s}");
assert!(s.contains("a.example.com"), "status: {s}");
assert!(s.contains("b.example.com"), "status: {s}");
assert!(
!s.contains("tok_A") && !s.contains("tok_B"),
"status leaked a token: {s}"
);
}
#[test]
fn auth_token_resolves_by_cwd_repo() {
let tmp = TempDir::new().unwrap();
let home = tmp.path().join("home");
std::fs::create_dir_all(&home).unwrap();
let ws_a = git_workspace(tmp.path(), "a", "org/repoA");
let ws_b = git_workspace(tmp.path(), "b", "org/repoB");
assert!(run(&home, &ws_a, &["auth", "login", "--token", "tok_A"])
.status
.success());
assert!(run(&home, &ws_b, &["auth", "login", "--token", "tok_B"])
.status
.success());
assert_eq!(
stdout(&run(&home, &ws_a, &["auth", "token"])).trim(),
"tok_A"
);
assert_eq!(
stdout(&run(&home, &ws_b, &["auth", "token"])).trim(),
"tok_B"
);
}
#[test]
fn logout_repo_scoped_removes_only_that_entry() {
let tmp = TempDir::new().unwrap();
let home = tmp.path().join("home");
std::fs::create_dir_all(&home).unwrap();
let cwd = tmp.path().join("work");
std::fs::create_dir_all(&cwd).unwrap();
run(
&home,
&cwd,
&["auth", "login", "--token", "tok_A", "--repo", "org/repoA"],
);
run(
&home,
&cwd,
&["auth", "login", "--token", "tok_B", "--repo", "org/repoB"],
);
let out = run(&home, &cwd, &["auth", "logout", "--repo", "org/repoA"]);
assert!(out.status.success(), "{}", stdout(&out));
assert!(stdout(&out).contains("logged out"), "{}", stdout(&out));
let st = stdout(&run(&home, &cwd, &["auth", "status"]));
assert!(st.contains("org/repoB"), "status: {st}");
assert!(!st.contains("org/repoA"), "repoA should be gone: {st}");
assert_eq!(
stdout(&run(&home, &cwd, &["auth", "token", "--repo", "org/repoB"])).trim(),
"tok_B"
);
let miss = run(&home, &cwd, &["auth", "token", "--repo", "org/repoA"]);
assert!(
!miss.status.success(),
"repoA token should error after logout"
);
}
#[test]
fn logout_all_clears_every_entry() {
let tmp = TempDir::new().unwrap();
let home = tmp.path().join("home");
std::fs::create_dir_all(&home).unwrap();
let cwd = tmp.path().join("work");
std::fs::create_dir_all(&cwd).unwrap();
run(
&home,
&cwd,
&["auth", "login", "--token", "tok_A", "--repo", "org/repoA"],
);
run(
&home,
&cwd,
&["auth", "login", "--token", "tok_B", "--repo", "org/repoB"],
);
let out = run(&home, &cwd, &["auth", "logout", "--all"]);
assert!(out.status.success());
assert!(stdout(&out).contains("logged out"), "{}", stdout(&out));
let st = stdout(&run(&home, &cwd, &["auth", "status"]));
assert!(st.contains("not authenticated"), "status: {st}");
}