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
}
fn mnem_no_repo(args: &[&str]) -> Command {
let mut cmd = Command::cargo_bin("mnem").expect("built mnem binary");
for a in args {
cmd.arg(a);
}
cmd
}
fn file_url(p: &Path) -> String {
let s = p.to_string_lossy().replace('\\', "/");
if s.starts_with('/') {
format!("file://{s}")
} else {
format!("file:///{s}")
}
}
#[test]
fn clone_file_url_round_trips_commit_head() {
let src = TempDir::new().unwrap();
mnem(src.path(), &["init", src.path().to_str().unwrap()])
.assert()
.success();
mnem(
src.path(),
&[
"add",
"node",
"--summary",
"cloneable payload",
"--label",
"doc",
"--no-embed",
],
)
.assert()
.success();
let car_dir = TempDir::new().unwrap();
let car = car_dir.path().join("snapshot.car");
mnem(
src.path(),
&["export", car.to_str().unwrap(), "--from", "HEAD"],
)
.assert()
.success();
assert!(car.exists());
let dst_root = TempDir::new().unwrap();
let dst = dst_root.path().join("mirror");
let url = file_url(&car);
let cloned = mnem_no_repo(&["clone", &url, dst.to_str().unwrap()])
.assert()
.success();
let stdout = String::from_utf8_lossy(&cloned.get_output().stdout).to_string();
assert!(
stdout.contains("cloned ") && stdout.contains("blocks"),
"clone output shape: {stdout}"
);
assert!(
stdout.contains("origin/main"),
"clone should report origin/main tracking ref, got: {stdout}"
);
let cfg = std::fs::read_to_string(dst.join(".mnem/config.toml")).expect("config.toml");
assert!(
cfg.contains("[remote.origin]"),
"config must carry [remote.origin], got: {cfg}"
);
assert!(
cfg.contains(&url),
"config must carry the source URL, got: {cfg}"
);
let src_log = mnem(src.path(), &["log", "-n", "1", "--format=json"])
.assert()
.success();
let src_stdout = String::from_utf8_lossy(&src_log.get_output().stdout).to_string();
let src_line = src_stdout
.lines()
.next()
.expect("expected at least one op from src");
let src_v: serde_json::Value = serde_json::from_str(src_line).expect("json");
let src_cid = src_v["cid"].as_str().unwrap().to_string();
assert!(!src_cid.is_empty());
let refs_out = mnem(&dst, &["ref", "list"]).assert().success();
let refs_stdout = String::from_utf8_lossy(&refs_out.get_output().stdout).to_string();
assert!(
refs_stdout.contains("refs/remotes/origin/main"),
"dst should carry origin/main tracking ref, got: {refs_stdout}"
);
}
#[test]
fn clone_refuses_into_existing_mnem_dir() {
let src = TempDir::new().unwrap();
mnem(src.path(), &["init", src.path().to_str().unwrap()])
.assert()
.success();
mnem(
src.path(),
&["add", "node", "--summary", "src", "--no-embed"],
)
.assert()
.success();
let car_dir = TempDir::new().unwrap();
let car = car_dir.path().join("s.car");
mnem(src.path(), &["export", car.to_str().unwrap()])
.assert()
.success();
let dst = TempDir::new().unwrap();
mnem(dst.path(), &["init", dst.path().to_str().unwrap()])
.assert()
.success();
let url = file_url(&car);
let out = mnem_no_repo(&["clone", &url, dst.path().to_str().unwrap()])
.assert()
.failure();
let stderr = String::from_utf8_lossy(&out.get_output().stderr).to_string();
assert!(
stderr.contains("already contains") || stderr.contains("refusing"),
"expected refuse-to-clobber error, got: {stderr}"
);
}
#[test]
fn clone_rejects_https_scheme_actionably() {
let dst = TempDir::new().unwrap();
let target = dst.path().join("mirror");
let out = mnem_no_repo(&[
"clone",
"https://example.com/alice/notes",
target.to_str().unwrap(),
])
.assert()
.failure();
let stderr = String::from_utf8_lossy(&out.get_output().stderr).to_string();
assert!(
stderr.contains("not yet implemented"),
"deferred-scheme error must be actionable: {stderr}"
);
assert!(
stderr.contains("PR 3") || stderr.contains("") || stderr.contains("ROADMAP"),
"deferred-scheme error must point at the roadmap: {stderr}"
);
}