use std::fs;
use std::process::Command;
use assert_cmd::prelude::*;
use predicates::prelude::*;
use tempfile::TempDir;
fn create_test_repo() -> TempDir {
let temp = TempDir::new().unwrap();
Command::new("git")
.args(["init"])
.current_dir(temp.path())
.output()
.expect("Failed to init git repo");
Command::new("git")
.args(["config", "user.email", "test@example.com"])
.current_dir(temp.path())
.output()
.expect("Failed to configure git email");
Command::new("git")
.args(["config", "user.name", "Test User"])
.current_dir(temp.path())
.output()
.expect("Failed to configure git name");
fs::write(temp.path().join("README.md"), "# Test Project").unwrap();
Command::new("git")
.args(["add", "."])
.current_dir(temp.path())
.output()
.expect("Failed to stage files");
Command::new("git")
.args(["commit", "-m", "Initial commit"])
.current_dir(temp.path())
.output()
.expect("Failed to create initial commit");
temp
}
fn agit_cmd() -> Command {
Command::new(env!("CARGO_BIN_EXE_agit"))
}
#[test]
fn test_init_creates_agit_directory() {
let temp = create_test_repo();
agit_cmd()
.arg("init")
.current_dir(temp.path())
.assert()
.success()
.stdout(predicate::str::contains("Initialized AGIT"));
let agit_dir = temp.path().join(".agit");
assert!(agit_dir.exists());
assert!(agit_dir.join("tmp").is_dir());
assert!(agit_dir.join("config.json").exists());
assert!(agit_dir.join("HEAD").exists());
assert!(agit_dir.join("index").exists());
assert!(!agit_dir.join("objects").exists());
assert!(!agit_dir.join("refs").exists());
}
#[test]
fn test_init_creates_instruction_files() {
let temp = create_test_repo();
agit_cmd()
.arg("init")
.current_dir(temp.path())
.assert()
.success();
assert!(temp.path().join("CLAUDE.md").exists());
assert!(temp.path().join(".cursorrules").exists());
assert!(temp.path().join(".mcp.json").exists());
assert!(temp.path().join(".cursor/mcp.json").exists());
}
#[test]
fn test_init_fails_if_not_git_repo() {
let temp = TempDir::new().unwrap();
agit_cmd()
.arg("init")
.current_dir(temp.path())
.assert()
.failure();
}
#[test]
fn test_init_fails_if_already_initialized() {
let temp = create_test_repo();
agit_cmd()
.arg("init")
.current_dir(temp.path())
.assert()
.success();
agit_cmd()
.arg("init")
.current_dir(temp.path())
.assert()
.failure()
.stderr(predicate::str::contains("already initialized"));
}
#[test]
fn test_record_adds_entry_to_index() {
let temp = create_test_repo();
agit_cmd()
.arg("init")
.current_dir(temp.path())
.assert()
.success();
agit_cmd()
.args(["record", "Planning to refactor the auth module"])
.current_dir(temp.path())
.assert()
.success()
.stdout(predicate::str::contains("Recorded"));
let index_content = fs::read_to_string(temp.path().join(".agit/index")).unwrap();
assert!(index_content.contains("Planning to refactor"));
}
#[test]
fn test_record_fails_if_not_initialized() {
let temp = create_test_repo();
agit_cmd()
.args(["record", "Some thought"])
.current_dir(temp.path())
.assert()
.failure()
.stderr(predicate::str::contains("not initialized"));
}
#[test]
fn test_status_shows_pending_thoughts() {
let temp = create_test_repo();
agit_cmd()
.arg("init")
.current_dir(temp.path())
.assert()
.success();
agit_cmd()
.arg("status")
.current_dir(temp.path())
.assert()
.success()
.stdout(predicate::str::contains("No pending thoughts"));
agit_cmd()
.args(["record", "Test thought"])
.current_dir(temp.path())
.assert()
.success();
agit_cmd()
.arg("status")
.current_dir(temp.path())
.assert()
.success()
.stdout(predicate::str::contains("Pending thoughts: 1"));
}
#[test]
fn test_commit_creates_neural_commit() {
let temp = create_test_repo();
agit_cmd()
.arg("init")
.current_dir(temp.path())
.assert()
.success();
agit_cmd()
.args(["record", "User wants to add auth"])
.current_dir(temp.path())
.assert()
.success();
agit_cmd()
.args(["commit", "-m", "Add authentication", "-y"])
.current_dir(temp.path())
.assert()
.success()
.stdout(predicate::str::contains("Created neural commit"));
agit_cmd()
.arg("log")
.current_dir(temp.path())
.assert()
.success()
.stdout(predicate::str::contains("commit"));
}
#[test]
fn test_commit_clears_index() {
let temp = create_test_repo();
agit_cmd()
.arg("init")
.current_dir(temp.path())
.assert()
.success();
agit_cmd()
.args(["record", "Test thought"])
.current_dir(temp.path())
.assert()
.success();
agit_cmd()
.args(["commit", "-m", "Test commit", "-y"])
.current_dir(temp.path())
.assert()
.success();
let index_content = fs::read_to_string(temp.path().join(".agit/index")).unwrap();
assert!(index_content.trim().is_empty());
}
#[test]
fn test_log_shows_commits() {
let temp = create_test_repo();
agit_cmd()
.arg("init")
.current_dir(temp.path())
.assert()
.success();
agit_cmd()
.args(["record", "First thought"])
.current_dir(temp.path())
.assert()
.success();
agit_cmd()
.args(["commit", "-m", "First neural commit", "-y"])
.current_dir(temp.path())
.assert()
.success();
agit_cmd()
.arg("log")
.current_dir(temp.path())
.assert()
.success()
.stdout(predicate::str::contains("commit"));
}
#[test]
fn test_log_empty_repo() {
let temp = create_test_repo();
agit_cmd()
.arg("init")
.current_dir(temp.path())
.assert()
.success();
agit_cmd()
.arg("log")
.current_dir(temp.path())
.assert()
.success()
.stdout(predicate::str::contains("No neural commits"));
}
#[test]
fn test_show_displays_commit_details() {
let temp = create_test_repo();
agit_cmd()
.arg("init")
.current_dir(temp.path())
.assert()
.success();
agit_cmd()
.args(["record", "Add feature X"])
.current_dir(temp.path())
.assert()
.success();
agit_cmd()
.args(["commit", "-m", "Add feature X", "-y"])
.current_dir(temp.path())
.assert()
.success();
agit_cmd()
.arg("show")
.current_dir(temp.path())
.assert()
.success()
.stdout(predicate::str::contains("Neural Commit"))
.stdout(predicate::str::contains("Summary"));
}
#[test]
fn test_full_workflow() {
let temp = create_test_repo();
agit_cmd()
.arg("init")
.current_dir(temp.path())
.assert()
.success();
agit_cmd()
.args(["record", "--intent", "Add user authentication"])
.current_dir(temp.path())
.assert()
.success();
agit_cmd()
.args(["record", "--ai", "Will implement JWT-based auth"])
.current_dir(temp.path())
.assert()
.success();
fs::write(temp.path().join("auth.rs"), "// Auth module").unwrap();
Command::new("git")
.args(["add", "."])
.current_dir(temp.path())
.output()
.unwrap();
Command::new("git")
.args(["commit", "-m", "Add auth module"])
.current_dir(temp.path())
.output()
.unwrap();
agit_cmd()
.args(["commit", "-m", "Add user authentication", "-y"])
.current_dir(temp.path())
.assert()
.success();
agit_cmd()
.arg("log")
.current_dir(temp.path())
.assert()
.success()
.stdout(predicate::str::contains("Intent"));
agit_cmd()
.args(["show", "--trace"])
.current_dir(temp.path())
.assert()
.success()
.stdout(predicate::str::contains("Trace"));
}