use assert_cmd::Command;
use predicates::prelude::*;
use tempfile::TempDir;
fn make_diff_repo() -> TempDir {
let dir = TempDir::new().unwrap();
let repo = git2::Repository::init(dir.path()).unwrap();
let src_dir = dir.path().join("src");
std::fs::create_dir_all(&src_dir).unwrap();
std::fs::write(
src_dir.join("lib.rs"),
"pub fn compute(x: i32) -> i32 {\n x * 2\n}\n",
)
.unwrap();
std::fs::write(
src_dir.join("main.rs"),
"use crate::compute;\n\nfn main() {\n let result = compute(21);\n println!(\"{}\", result);\n}\n",
)
.unwrap();
std::fs::write(
dir.path().join("Cargo.toml"),
"[package]\nname = \"diff_test\"\nversion = \"0.1.0\"\n",
)
.unwrap();
let mut index = repo.index().unwrap();
index
.add_all(["*"].iter(), git2::IndexAddOption::DEFAULT, None)
.unwrap();
index.write().unwrap();
let tree_id = index.write_tree().unwrap();
let tree = repo.find_tree(tree_id).unwrap();
let sig = git2::Signature::now("Test", "test@test.com").unwrap();
repo.commit(Some("HEAD"), &sig, &sig, "initial commit", &tree, &[])
.unwrap();
dir
}
#[test]
fn test_diff_no_changes() {
let repo = make_diff_repo();
Command::new(assert_cmd::cargo_bin!("cxpak"))
.args(["diff", "--tokens", "50k"])
.current_dir(repo.path())
.assert()
.success()
.stdout(predicate::str::contains("No changes detected."));
}
#[test]
fn test_diff_shows_changes() {
let repo = make_diff_repo();
std::fs::write(
repo.path().join("src/lib.rs"),
"pub fn compute(x: i32) -> i32 {\n x * 3\n}\n",
)
.unwrap();
Command::new(assert_cmd::cargo_bin!("cxpak"))
.args(["diff", "--tokens", "50k"])
.current_dir(repo.path())
.assert()
.success()
.stdout(predicate::str::contains("src/lib.rs"));
}
#[test]
fn test_diff_includes_context() {
let repo = make_diff_repo();
std::fs::write(
repo.path().join("src/lib.rs"),
"pub fn compute(x: i32) -> i32 {\n x * 4\n}\n",
)
.unwrap();
Command::new(assert_cmd::cargo_bin!("cxpak"))
.args(["diff", "--tokens", "50k"])
.current_dir(repo.path())
.assert()
.success()
.stdout(predicate::str::contains("lib.rs"));
}
#[test]
fn test_diff_json_format() {
let repo = make_diff_repo();
std::fs::write(
repo.path().join("src/lib.rs"),
"pub fn compute(x: i32) -> i32 {\n x * 5\n}\n",
)
.unwrap();
let output = Command::new(assert_cmd::cargo_bin!("cxpak"))
.args(["diff", "--tokens", "50k", "--format", "json"])
.current_dir(repo.path())
.assert()
.success()
.get_output()
.stdout
.clone();
let content = String::from_utf8(output).unwrap();
let parsed: Result<serde_json::Value, _> = serde_json::from_str(&content);
assert!(parsed.is_ok(), "output should be valid JSON");
assert!(
content.contains("metadata"),
"JSON should contain metadata key"
);
}
#[test]
fn test_diff_xml_format() {
let repo = make_diff_repo();
std::fs::write(
repo.path().join("src/lib.rs"),
"pub fn compute(x: i32) -> i32 {\n x * 6\n}\n",
)
.unwrap();
Command::new(assert_cmd::cargo_bin!("cxpak"))
.args(["diff", "--tokens", "50k", "--format", "xml"])
.current_dir(repo.path())
.assert()
.success()
.stdout(predicate::str::contains("<cxpak>"));
}
#[test]
fn test_diff_with_ref() {
let repo = make_diff_repo();
std::fs::write(
repo.path().join("src/lib.rs"),
"pub fn compute(x: i32) -> i32 {\n x * 10\n}\n",
)
.unwrap();
let git_repo = git2::Repository::open(repo.path()).unwrap();
let sig = git2::Signature::now("Test", "test@test.com").unwrap();
let mut index = git_repo.index().unwrap();
index
.add_all(["*"].iter(), git2::IndexAddOption::DEFAULT, None)
.unwrap();
index.write().unwrap();
let tree_id = index.write_tree().unwrap();
let tree = git_repo.find_tree(tree_id).unwrap();
let head = git_repo.head().unwrap().peel_to_commit().unwrap();
git_repo
.commit(Some("HEAD"), &sig, &sig, "second commit", &tree, &[&head])
.unwrap();
Command::new(assert_cmd::cargo_bin!("cxpak"))
.args(["diff", "--tokens", "50k", "--git-ref", "HEAD~1"])
.current_dir(repo.path())
.assert()
.success()
.stdout(predicate::str::contains("src/lib.rs"));
}
#[test]
fn test_diff_out_flag() {
let repo = make_diff_repo();
let out_dir = TempDir::new().unwrap();
let out_file = out_dir.path().join("diff_output.md");
std::fs::write(
repo.path().join("src/lib.rs"),
"pub fn compute(x: i32) -> i32 {\n x * 7\n}\n",
)
.unwrap();
Command::new(assert_cmd::cargo_bin!("cxpak"))
.args([
"diff",
"--tokens",
"50k",
"--out",
out_file.to_str().unwrap(),
])
.current_dir(repo.path())
.assert()
.success();
assert!(out_file.exists(), "--out file should be created");
let content = std::fs::read_to_string(&out_file).unwrap();
assert!(
content.contains("lib.rs"),
"output file should mention changed file"
);
}
#[test]
fn test_diff_not_git_repo() {
let dir = TempDir::new().unwrap();
Command::new(assert_cmd::cargo_bin!("cxpak"))
.args(["diff", "--tokens", "50k"])
.current_dir(dir.path())
.assert()
.failure()
.stderr(predicate::str::contains("could not find repository"));
}
#[test]
fn test_diff_verbose() {
let repo = make_diff_repo();
std::fs::write(
repo.path().join("src/lib.rs"),
"pub fn compute(x: i32) -> i32 {\n x * 8\n}\n",
)
.unwrap();
Command::new(assert_cmd::cargo_bin!("cxpak"))
.args(["diff", "--tokens", "50k", "--verbose"])
.current_dir(repo.path())
.assert()
.success()
.stderr(predicate::str::contains("cxpak:"));
}
#[test]
fn test_diff_with_path_argument() {
let repo = make_diff_repo();
std::fs::write(
repo.path().join("src/lib.rs"),
"pub fn compute(x: i32) -> i32 {\n x * 9\n}\n",
)
.unwrap();
Command::new(assert_cmd::cargo_bin!("cxpak"))
.args(["diff", "--tokens", "50k"])
.arg(repo.path())
.assert()
.success()
.stdout(predicate::str::contains("src/lib.rs"));
}