use std::path::Path;
use std::process::Command;
use assert_cmd::prelude::*;
use tempfile::TempDir;
fn mnem(repo: &Path, args: &[&str]) -> Command {
let mut cmd = Command::cargo_bin("mnem").expect("built mnem binary");
cmd.current_dir(repo);
cmd.arg("-R").arg(repo);
for a in args {
cmd.arg(a);
}
cmd
}
#[test]
fn remote_list_empty_repo() {
let dir = TempDir::new().unwrap();
mnem(dir.path(), &["init", dir.path().to_str().unwrap()])
.assert()
.success();
let out = mnem(dir.path(), &["remote", "list"]).assert().success();
let stdout = String::from_utf8_lossy(&out.get_output().stdout).to_string();
assert!(
stdout.contains("<no remotes>"),
"empty repo should show no remotes, got: {stdout}"
);
}
#[test]
fn remote_round_trip_through_config_toml() {
let dir = TempDir::new().unwrap();
mnem(dir.path(), &["init", dir.path().to_str().unwrap()])
.assert()
.success();
mnem(
dir.path(),
&[
"remote",
"add",
"origin",
"https://alice.example/notes.car",
"--token-env",
"MNEM_ORIGIN_TOKEN",
],
)
.assert()
.success();
mnem(
dir.path(),
&["remote", "add", "backup", "https://example.com/backup"],
)
.assert()
.success();
let listed = mnem(dir.path(), &["remote", "list"]).assert().success();
let listed_out = String::from_utf8_lossy(&listed.get_output().stdout).to_string();
assert!(
listed_out.contains("origin") && listed_out.contains("backup"),
"list should surface both remotes, got: {listed_out}"
);
assert!(listed_out.contains("https://alice.example/notes.car"));
assert!(listed_out.contains("https://example.com/backup"));
let shown = mnem(dir.path(), &["remote", "show", "origin"])
.assert()
.success();
let shown_out = String::from_utf8_lossy(&shown.get_output().stdout).to_string();
assert!(
shown_out.contains("https://alice.example/notes.car"),
"show should carry url: {shown_out}"
);
assert!(
shown_out.contains("MNEM_ORIGIN_TOKEN"),
"show should carry token env-var name: {shown_out}"
);
let cfg = std::fs::read_to_string(dir.path().join(".mnem/config.toml")).unwrap();
assert!(
cfg.contains("MNEM_ORIGIN_TOKEN"),
"token_env name must persist: {cfg}"
);
assert!(
!cfg.to_lowercase().contains("token ="),
"config.toml must NOT carry a bare token field, got: {cfg}"
);
mnem(dir.path(), &["remote", "remove", "backup"])
.assert()
.success();
let after = mnem(dir.path(), &["remote", "list"]).assert().success();
let after_out = String::from_utf8_lossy(&after.get_output().stdout).to_string();
assert!(
after_out.contains("origin") && !after_out.contains("backup"),
"backup should be gone, origin survive: {after_out}"
);
}
#[test]
fn remote_add_duplicate_fails() {
let dir = TempDir::new().unwrap();
mnem(dir.path(), &["init", dir.path().to_str().unwrap()])
.assert()
.success();
mnem(
dir.path(),
&["remote", "add", "origin", "https://x.example/x.car"],
)
.assert()
.success();
let out = mnem(
dir.path(),
&["remote", "add", "origin", "https://y.example/y.car"],
)
.assert()
.failure();
let stderr = String::from_utf8_lossy(&out.get_output().stderr).to_string();
assert!(
stderr.contains("already exists"),
"duplicate-remote error expected: {stderr}"
);
}
#[test]
fn remote_show_missing_fails() {
let dir = TempDir::new().unwrap();
mnem(dir.path(), &["init", dir.path().to_str().unwrap()])
.assert()
.success();
let out = mnem(dir.path(), &["remote", "show", "origin"])
.assert()
.failure();
let stderr = String::from_utf8_lossy(&out.get_output().stderr).to_string();
assert!(
stderr.contains("not found"),
"missing-remote error expected: {stderr}"
);
}
#[test]
fn remote_add_rejects_file_scheme() {
let dir = TempDir::new().unwrap();
mnem(dir.path(), &["init", dir.path().to_str().unwrap()])
.assert()
.success();
let out = mnem(
dir.path(),
&["remote", "add", "origin", "file:///tmp/local.car"],
)
.assert()
.failure();
let stderr = String::from_utf8_lossy(&out.get_output().stderr).to_string();
assert!(
stderr.contains("file://"),
"rejection should call out the scheme: {stderr}"
);
assert!(
stderr.contains("mnem clone"),
"rejection should point at mnem clone: {stderr}"
);
}