arc/tests/commit.rs
hanna 2e0952f9fb
feat: add colored output with distinct symbols using the colored crate
Add a centralized ui module with Arc's visual identity: colored commit
IDs (magenta), bookmarks (cyan), tags (yellow), status symbols, and
diff highlighting. Update all command output and tests accordingly.
2026-02-09 03:51:59 +00:00

307 lines
8.1 KiB
Rust

use std::process::Command;
use tempfile::TempDir;
fn arc_cmd() -> Command {
let mut cmd = Command::new(env!("CARGO_BIN_EXE_arc"));
cmd.env("NO_COLOR", "1");
cmd
}
fn init_repo() -> TempDir {
let dir = TempDir::new().unwrap();
arc_cmd()
.arg("init")
.current_dir(dir.path())
.output()
.expect("failed to init");
dir
}
#[test]
fn commit_first_creates_commit() {
let dir = init_repo();
std::fs::write(dir.path().join("hello.txt"), "hello world\n").unwrap();
let output = arc_cmd()
.args(["commit", "initial commit"])
.current_dir(dir.path())
.output()
.expect("failed to run arc");
assert!(output.status.success());
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("committed"));
}
#[test]
fn commit_creates_zst_file() {
let dir = init_repo();
std::fs::write(dir.path().join("file.txt"), "content\n").unwrap();
let output = arc_cmd()
.args(["commit", "add file"])
.current_dir(dir.path())
.output()
.expect("failed to run arc");
assert!(output.status.success());
let stdout = String::from_utf8_lossy(&output.stdout);
let commit_id = stdout.trim().strip_prefix("✓ committed ").unwrap();
let commits_dir = dir.path().join(".arc").join("commits");
let found = std::fs::read_dir(&commits_dir)
.unwrap()
.filter_map(|e| e.ok())
.any(|e| e.file_name().to_string_lossy().starts_with(commit_id));
assert!(found, "commit .zst file should exist");
}
#[test]
fn commit_updates_head_to_attached() {
let dir = init_repo();
std::fs::write(dir.path().join("a.txt"), "a\n").unwrap();
arc_cmd()
.args(["commit", "first"])
.current_dir(dir.path())
.output()
.expect("failed to run arc");
let head = std::fs::read_to_string(dir.path().join(".arc").join("HEAD")).unwrap();
assert!(head.contains("attached"));
assert!(head.contains("main"));
}
#[test]
fn commit_updates_bookmark_ref() {
let dir = init_repo();
std::fs::write(dir.path().join("a.txt"), "a\n").unwrap();
let output = arc_cmd()
.args(["commit", "first"])
.current_dir(dir.path())
.output()
.expect("failed to run arc");
let stdout = String::from_utf8_lossy(&output.stdout);
let commit_id = stdout.trim().strip_prefix("✓ committed ").unwrap();
let bookmark =
std::fs::read_to_string(dir.path().join(".arc").join("bookmarks").join("main")).unwrap();
assert!(bookmark.contains(commit_id));
}
#[test]
fn commit_fails_with_no_changes() {
let dir = init_repo();
let output = arc_cmd()
.args(["commit", "empty"])
.current_dir(dir.path())
.output()
.expect("failed to run arc");
assert!(!output.status.success());
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(stderr.contains("nothing to commit"));
}
#[test]
fn commit_nothing_after_same_content() {
let dir = init_repo();
std::fs::write(dir.path().join("a.txt"), "hello\n").unwrap();
arc_cmd()
.args(["commit", "first"])
.current_dir(dir.path())
.output()
.expect("failed to run arc");
let output = arc_cmd()
.args(["commit", "second"])
.current_dir(dir.path())
.output()
.expect("failed to run arc");
assert!(!output.status.success());
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(stderr.contains("nothing to commit"));
}
#[test]
fn second_commit_has_parent() {
let dir = init_repo();
std::fs::write(dir.path().join("a.txt"), "first\n").unwrap();
let first = arc_cmd()
.args(["commit", "first"])
.current_dir(dir.path())
.output()
.expect("failed");
let first_id = String::from_utf8_lossy(&first.stdout)
.trim()
.strip_prefix("✓ committed ")
.unwrap()
.to_string();
std::fs::write(dir.path().join("a.txt"), "second\n").unwrap();
let second = arc_cmd()
.args(["commit", "second"])
.current_dir(dir.path())
.output()
.expect("failed");
assert!(second.status.success());
let head = std::fs::read_to_string(dir.path().join(".arc").join("HEAD")).unwrap();
let second_id = String::from_utf8_lossy(&second.stdout)
.trim()
.strip_prefix("✓ committed ")
.unwrap()
.to_string();
assert!(head.contains(&second_id));
assert_ne!(first_id, second_id);
}
#[test]
fn commit_ignores_arc_directory() {
let dir = init_repo();
std::fs::write(dir.path().join("file.txt"), "data\n").unwrap();
let output = arc_cmd()
.args(["commit", "test"])
.current_dir(dir.path())
.output()
.expect("failed");
assert!(output.status.success());
}
#[test]
fn commit_ignores_arcignore_patterns() {
let dir = init_repo();
std::fs::write(dir.path().join(".arcignore"), "*.log\n").unwrap();
std::fs::write(dir.path().join("data.log"), "log data\n").unwrap();
std::fs::write(dir.path().join("keep.txt"), "keep\n").unwrap();
arc_cmd()
.args(["commit", "first"])
.current_dir(dir.path())
.output()
.expect("failed");
std::fs::remove_file(dir.path().join("data.log")).unwrap();
let output = arc_cmd()
.args(["commit", "should fail"])
.current_dir(dir.path())
.output()
.expect("failed");
assert!(!output.status.success());
}
#[test]
fn commit_detects_deletions() {
let dir = init_repo();
std::fs::write(dir.path().join("a.txt"), "a\n").unwrap();
std::fs::write(dir.path().join("b.txt"), "b\n").unwrap();
arc_cmd()
.args(["commit", "add files"])
.current_dir(dir.path())
.output()
.expect("failed");
std::fs::remove_file(dir.path().join("b.txt")).unwrap();
let output = arc_cmd()
.args(["commit", "delete b"])
.current_dir(dir.path())
.output()
.expect("failed");
assert!(output.status.success());
}
#[test]
fn commit_detects_modifications() {
let dir = init_repo();
std::fs::write(dir.path().join("a.txt"), "original\n").unwrap();
arc_cmd()
.args(["commit", "add file"])
.current_dir(dir.path())
.output()
.expect("failed");
std::fs::write(dir.path().join("a.txt"), "modified\n").unwrap();
let output = arc_cmd()
.args(["commit", "modify file"])
.current_dir(dir.path())
.output()
.expect("failed");
assert!(output.status.success());
}
#[test]
fn commit_outside_repo_fails() {
let dir = TempDir::new().unwrap();
let output = arc_cmd()
.args(["commit", "fail"])
.current_dir(dir.path())
.output()
.expect("failed to run arc");
assert!(!output.status.success());
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(stderr.contains("not an arc repository"));
}
#[test]
fn commit_with_subdirectories() {
let dir = init_repo();
std::fs::create_dir_all(dir.path().join("src").join("nested")).unwrap();
std::fs::write(dir.path().join("src/nested/deep.txt"), "deep\n").unwrap();
std::fs::write(dir.path().join("root.txt"), "root\n").unwrap();
let output = arc_cmd()
.args(["commit", "nested dirs"])
.current_dir(dir.path())
.output()
.expect("failed");
assert!(output.status.success());
}
#[test]
fn three_sequential_commits_succeed() {
let dir = init_repo();
std::fs::write(dir.path().join("a.txt"), "v1\n").unwrap();
let c1 = arc_cmd()
.args(["commit", "c1"])
.current_dir(dir.path())
.output()
.expect("failed");
assert!(c1.status.success());
std::fs::write(dir.path().join("b.txt"), "v1\n").unwrap();
let c2 = arc_cmd()
.args(["commit", "c2"])
.current_dir(dir.path())
.output()
.expect("failed");
assert!(c2.status.success());
std::fs::write(dir.path().join("a.txt"), "v2\n").unwrap();
let c3 = arc_cmd()
.args(["commit", "c3"])
.current_dir(dir.path())
.output()
.expect("failed");
assert!(c3.status.success());
}