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.
334 lines
8.8 KiB
Rust
334 lines
8.8 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
|
|
}
|
|
|
|
fn commit_file(dir: &TempDir, name: &str, content: &str, msg: &str) -> String {
|
|
std::fs::write(dir.path().join(name), content).unwrap();
|
|
let output = arc_cmd()
|
|
.args(["commit", msg])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed to commit");
|
|
assert!(output.status.success());
|
|
String::from_utf8_lossy(&output.stdout)
|
|
.trim()
|
|
.strip_prefix("✓ committed ")
|
|
.unwrap()
|
|
.to_string()
|
|
}
|
|
|
|
#[test]
|
|
fn mark_add_creates_bookmark() {
|
|
let dir = init_repo();
|
|
commit_file(&dir, "a.txt", "hello\n", "first");
|
|
|
|
let output = arc_cmd()
|
|
.args(["mark", "add", "feature"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
assert!(output.status.success());
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
assert!(stdout.contains("bookmark feature set at"));
|
|
|
|
let bookmark_path = dir.path().join(".arc").join("bookmarks").join("feature");
|
|
assert!(bookmark_path.exists());
|
|
}
|
|
|
|
#[test]
|
|
fn mark_add_at_specific_commit() {
|
|
let dir = init_repo();
|
|
let id1 = commit_file(&dir, "a.txt", "v1\n", "first");
|
|
commit_file(&dir, "a.txt", "v2\n", "second");
|
|
|
|
let short = &id1[..12];
|
|
let output = arc_cmd()
|
|
.args(["mark", "add", "old", short])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
assert!(output.status.success());
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
assert!(stdout.contains("bookmark old set at"));
|
|
}
|
|
|
|
#[test]
|
|
fn mark_add_fails_without_commits() {
|
|
let dir = init_repo();
|
|
|
|
let output = arc_cmd()
|
|
.args(["mark", "add", "feature"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
assert!(!output.status.success());
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
assert!(stderr.contains("no commits yet"));
|
|
}
|
|
|
|
#[test]
|
|
fn mark_rm_removes_bookmark() {
|
|
let dir = init_repo();
|
|
commit_file(&dir, "a.txt", "hello\n", "first");
|
|
|
|
arc_cmd()
|
|
.args(["mark", "add", "feature"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
let output = arc_cmd()
|
|
.args(["mark", "rm", "feature"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
assert!(output.status.success());
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
assert!(stdout.contains("bookmark feature removed"));
|
|
|
|
let bookmark_path = dir.path().join(".arc").join("bookmarks").join("feature");
|
|
assert!(!bookmark_path.exists());
|
|
}
|
|
|
|
#[test]
|
|
fn mark_rm_fails_for_active_bookmark() {
|
|
let dir = init_repo();
|
|
commit_file(&dir, "a.txt", "hello\n", "first");
|
|
|
|
let output = arc_cmd()
|
|
.args(["mark", "rm", "main"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
assert!(!output.status.success());
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
assert!(stderr.contains("cannot remove active bookmark"));
|
|
}
|
|
|
|
#[test]
|
|
fn mark_rm_fails_for_nonexistent() {
|
|
let dir = init_repo();
|
|
commit_file(&dir, "a.txt", "hello\n", "first");
|
|
|
|
let output = arc_cmd()
|
|
.args(["mark", "rm", "nonexistent"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
assert!(!output.status.success());
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
assert!(stderr.contains("bookmark not found"));
|
|
}
|
|
|
|
#[test]
|
|
fn mark_list_shows_bookmarks() {
|
|
let dir = init_repo();
|
|
commit_file(&dir, "a.txt", "hello\n", "first");
|
|
|
|
arc_cmd()
|
|
.args(["mark", "add", "feature"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
arc_cmd()
|
|
.args(["mark", "add", "dev"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
let output = arc_cmd()
|
|
.args(["mark", "list"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
assert!(output.status.success());
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
assert!(stdout.contains("dev"));
|
|
assert!(stdout.contains("feature"));
|
|
assert!(stdout.contains("main"));
|
|
}
|
|
|
|
#[test]
|
|
fn mark_list_marks_active_bookmark() {
|
|
let dir = init_repo();
|
|
commit_file(&dir, "a.txt", "hello\n", "first");
|
|
|
|
arc_cmd()
|
|
.args(["mark", "add", "feature"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
let output = arc_cmd()
|
|
.args(["mark", "list"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
assert!(output.status.success());
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
assert!(stdout.contains("★ main"));
|
|
assert!(stdout.contains(" feature"));
|
|
}
|
|
|
|
#[test]
|
|
fn mark_list_sorted_alphabetically() {
|
|
let dir = init_repo();
|
|
commit_file(&dir, "a.txt", "hello\n", "first");
|
|
|
|
arc_cmd()
|
|
.args(["mark", "add", "zebra"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
arc_cmd()
|
|
.args(["mark", "add", "alpha"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
let output = arc_cmd()
|
|
.args(["mark", "list"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
let alpha_pos = stdout.find("alpha").unwrap();
|
|
let main_pos = stdout.find("main").unwrap();
|
|
let zebra_pos = stdout.find("zebra").unwrap();
|
|
assert!(alpha_pos < main_pos);
|
|
assert!(main_pos < zebra_pos);
|
|
}
|
|
|
|
#[test]
|
|
fn mark_rename_renames_bookmark() {
|
|
let dir = init_repo();
|
|
commit_file(&dir, "a.txt", "hello\n", "first");
|
|
|
|
arc_cmd()
|
|
.args(["mark", "add", "feature"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
let output = arc_cmd()
|
|
.args(["mark", "rename", "feature", "bugfix"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
assert!(output.status.success());
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
assert!(stdout.contains("bookmark feature renamed to bugfix"));
|
|
|
|
let old_path = dir.path().join(".arc").join("bookmarks").join("feature");
|
|
let new_path = dir.path().join(".arc").join("bookmarks").join("bugfix");
|
|
assert!(!old_path.exists());
|
|
assert!(new_path.exists());
|
|
}
|
|
|
|
#[test]
|
|
fn mark_rename_updates_head_if_active() {
|
|
let dir = init_repo();
|
|
commit_file(&dir, "a.txt", "hello\n", "first");
|
|
|
|
let output = arc_cmd()
|
|
.args(["mark", "rename", "main", "trunk"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
assert!(output.status.success());
|
|
|
|
let head = std::fs::read_to_string(dir.path().join(".arc").join("HEAD")).unwrap();
|
|
assert!(head.contains("trunk"));
|
|
assert!(!head.contains("main"));
|
|
}
|
|
|
|
#[test]
|
|
fn mark_rename_fails_if_target_exists() {
|
|
let dir = init_repo();
|
|
commit_file(&dir, "a.txt", "hello\n", "first");
|
|
|
|
arc_cmd()
|
|
.args(["mark", "add", "feature"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
let output = arc_cmd()
|
|
.args(["mark", "rename", "feature", "main"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
assert!(!output.status.success());
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
assert!(stderr.contains("bookmark already exists"));
|
|
}
|
|
|
|
#[test]
|
|
fn mark_rename_fails_if_source_missing() {
|
|
let dir = init_repo();
|
|
commit_file(&dir, "a.txt", "hello\n", "first");
|
|
|
|
let output = arc_cmd()
|
|
.args(["mark", "rename", "nonexistent", "newname"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
assert!(!output.status.success());
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
assert!(stderr.contains("bookmark not found"));
|
|
}
|
|
|
|
#[test]
|
|
fn mark_add_overwrites_existing_bookmark() {
|
|
let dir = init_repo();
|
|
let id1 = commit_file(&dir, "a.txt", "v1\n", "first");
|
|
let id2 = commit_file(&dir, "a.txt", "v2\n", "second");
|
|
|
|
arc_cmd()
|
|
.args(["mark", "add", "feature"])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
let short1 = &id1[..12];
|
|
arc_cmd()
|
|
.args(["mark", "add", "feature", short1])
|
|
.current_dir(dir.path())
|
|
.output()
|
|
.expect("failed");
|
|
|
|
let bookmark =
|
|
std::fs::read_to_string(dir.path().join(".arc").join("bookmarks").join("feature")).unwrap();
|
|
assert!(bookmark.contains(&id1));
|
|
assert!(!bookmark.contains(&id2));
|
|
}
|