arc/tests/tracking.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

215 lines
5.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
}
#[test]
fn ignore_matches_arc_directory() {
let dir = init_repo();
std::fs::write(dir.path().join("real.txt"), "data\n").unwrap();
let output = arc_cmd()
.arg("status")
.current_dir(dir.path())
.output()
.expect("failed");
assert!(output.status.success());
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(!stdout.contains(".arc"));
assert!(stdout.contains("real.txt"));
}
#[test]
fn ignore_directory_pattern() {
let dir = init_repo();
std::fs::write(dir.path().join(".arcignore"), "build/\n").unwrap();
std::fs::create_dir_all(dir.path().join("build")).unwrap();
std::fs::write(dir.path().join("build/output.bin"), "binary\n").unwrap();
std::fs::write(dir.path().join("src.txt"), "source\n").unwrap();
let output = arc_cmd()
.arg("status")
.current_dir(dir.path())
.output()
.expect("failed");
assert!(output.status.success());
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(!stdout.contains("output.bin"));
assert!(stdout.contains("src.txt"));
}
#[test]
fn ignore_wildcard_pattern() {
let dir = init_repo();
std::fs::write(dir.path().join(".arcignore"), "*.o\n").unwrap();
std::fs::write(dir.path().join("main.o"), "object\n").unwrap();
std::fs::write(dir.path().join("main.c"), "source\n").unwrap();
let output = arc_cmd()
.arg("status")
.current_dir(dir.path())
.output()
.expect("failed");
assert!(output.status.success());
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(!stdout.contains("main.o"));
assert!(stdout.contains("main.c"));
}
#[test]
fn negation_pattern_overrides_ignore() {
let dir = init_repo();
std::fs::write(dir.path().join(".arcignore"), "*.log\n!important.log\n").unwrap();
std::fs::write(dir.path().join("debug.log"), "debug\n").unwrap();
std::fs::write(dir.path().join("important.log"), "keep\n").unwrap();
let output = arc_cmd()
.arg("status")
.current_dir(dir.path())
.output()
.expect("failed");
assert!(output.status.success());
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(!stdout.contains("debug.log"));
assert!(stdout.contains("important.log"));
}
#[test]
fn state_reconstruction_multi_commit() {
let dir = init_repo();
std::fs::write(dir.path().join("a.txt"), "v1\n").unwrap();
arc_cmd()
.args(["commit", "c1"])
.current_dir(dir.path())
.output()
.expect("failed");
std::fs::write(dir.path().join("b.txt"), "b\n").unwrap();
arc_cmd()
.args(["commit", "c2"])
.current_dir(dir.path())
.output()
.expect("failed");
std::fs::write(dir.path().join("a.txt"), "v2\n").unwrap();
arc_cmd()
.args(["commit", "c3"])
.current_dir(dir.path())
.output()
.expect("failed");
let output = arc_cmd()
.arg("status")
.current_dir(dir.path())
.output()
.expect("failed");
assert!(output.status.success());
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("working tree clean"));
}
#[test]
fn state_reconstruction_with_delete() {
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", "c1"])
.current_dir(dir.path())
.output()
.expect("failed");
std::fs::remove_file(dir.path().join("b.txt")).unwrap();
arc_cmd()
.args(["commit", "c2"])
.current_dir(dir.path())
.output()
.expect("failed");
let output = arc_cmd()
.arg("status")
.current_dir(dir.path())
.output()
.expect("failed");
assert!(output.status.success());
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("working tree clean"));
}
#[test]
fn binary_file_commit_and_status() {
let dir = init_repo();
std::fs::write(dir.path().join("binary.bin"), [0u8, 1, 2, 255, 254, 253]).unwrap();
let output = arc_cmd()
.args(["commit", "add binary"])
.current_dir(dir.path())
.output()
.expect("failed");
assert!(output.status.success());
let status = arc_cmd()
.arg("status")
.current_dir(dir.path())
.output()
.expect("failed");
assert!(status.status.success());
let stdout = String::from_utf8_lossy(&status.stdout);
assert!(stdout.contains("working tree clean"));
}
#[test]
fn zstd_compressed_storage() {
let dir = init_repo();
std::fs::write(dir.path().join("file.txt"), "content\n").unwrap();
let output = arc_cmd()
.args(["commit", "test zstd"])
.current_dir(dir.path())
.output()
.expect("failed");
assert!(output.status.success());
let commits_dir = dir.path().join(".arc").join("commits");
let entries: Vec<_> = std::fs::read_dir(&commits_dir)
.unwrap()
.filter_map(|e| e.ok())
.collect();
assert_eq!(entries.len(), 1);
let entry = &entries[0];
let name = entry.file_name().to_string_lossy().to_string();
assert!(
name.ends_with(".zst"),
"commit file should have .zst extension"
);
let bytes = std::fs::read(entry.path()).unwrap();
assert_eq!(
&bytes[0..4],
&[0x28, 0xB5, 0x2F, 0xFD],
"should have zstd magic bytes"
);
}