use std::path::PathBuf;
use std::time::SystemTime;
use tempfile::TempDir;
use git_paw::session::{
Session, SessionStatus, WorktreeEntry, delete_session_in, find_session_for_repo_in,
load_session_from, save_session_in,
};
fn make_session(suffix: &str) -> Session {
Session {
session_name: format!("paw-test-{suffix}"),
repo_path: PathBuf::from(format!("/tmp/fake-repo-{suffix}")),
project_name: format!("test-project-{suffix}"),
created_at: SystemTime::now(),
status: SessionStatus::Active,
worktrees: vec![
WorktreeEntry {
branch: "feature/auth".to_string(),
worktree_path: PathBuf::from(format!("/tmp/wt-{suffix}-auth")),
cli: "claude".to_string(),
},
WorktreeEntry {
branch: "fix/db".to_string(),
worktree_path: PathBuf::from(format!("/tmp/wt-{suffix}-db")),
cli: "gemini".to_string(),
},
],
}
}
#[test]
fn save_and_load_round_trip() {
let dir = TempDir::new().expect("create temp dir");
let session = make_session("roundtrip");
save_session_in(&session, dir.path()).expect("save");
let loaded = load_session_from(&session.session_name, dir.path())
.expect("load")
.expect("session should exist");
assert_eq!(loaded.session_name, session.session_name);
assert_eq!(loaded.repo_path, session.repo_path);
assert_eq!(loaded.project_name, session.project_name);
assert_eq!(loaded.status, SessionStatus::Active);
assert_eq!(loaded.worktrees.len(), 2);
assert_eq!(loaded.worktrees[0].branch, "feature/auth");
assert_eq!(loaded.worktrees[0].cli, "claude");
assert_eq!(loaded.worktrees[1].branch, "fix/db");
assert_eq!(loaded.worktrees[1].cli, "gemini");
}
#[test]
fn find_session_by_repo_path() {
let dir = TempDir::new().expect("create temp dir");
let session = make_session("find-repo");
save_session_in(&session, dir.path()).expect("save");
let found = find_session_for_repo_in(&session.repo_path, dir.path())
.expect("find")
.expect("session should be found");
assert_eq!(found.session_name, session.session_name);
}
#[test]
fn find_session_returns_none_for_unknown_repo() {
let dir = TempDir::new().expect("create temp dir");
let result = find_session_for_repo_in(&PathBuf::from("/nonexistent/repo"), dir.path())
.expect("find should not error");
assert!(result.is_none());
}
#[test]
fn find_correct_session_among_multiple() {
let dir = TempDir::new().expect("create temp dir");
let session_a = make_session("multi-a");
let session_b = make_session("multi-b");
save_session_in(&session_a, dir.path()).expect("save a");
save_session_in(&session_b, dir.path()).expect("save b");
let found = find_session_for_repo_in(&session_b.repo_path, dir.path())
.expect("find")
.expect("should find session b");
assert_eq!(found.session_name, session_b.session_name);
}
#[test]
fn delete_removes_session() {
let dir = TempDir::new().expect("create temp dir");
let session = make_session("delete");
save_session_in(&session, dir.path()).expect("save");
delete_session_in(&session.session_name, dir.path()).expect("delete");
let loaded = load_session_from(&session.session_name, dir.path()).expect("load");
assert!(loaded.is_none(), "session should be gone after delete");
}
#[test]
fn delete_nonexistent_is_idempotent() {
let dir = TempDir::new().expect("create temp dir");
let result = delete_session_in("nonexistent", dir.path());
assert!(
result.is_ok(),
"deleting nonexistent session should succeed"
);
}
#[test]
fn load_nonexistent_returns_none() {
let dir = TempDir::new().expect("create temp dir");
let loaded = load_session_from("does-not-exist", dir.path()).expect("load should not error");
assert!(loaded.is_none());
}
#[test]
fn saving_again_replaces_previous_state() {
let dir = TempDir::new().expect("create temp dir");
let mut session = make_session("overwrite");
save_session_in(&session, dir.path()).expect("save 1");
session.status = SessionStatus::Stopped;
save_session_in(&session, dir.path()).expect("save 2");
let loaded = load_session_from(&session.session_name, dir.path())
.expect("load")
.expect("session should exist");
assert_eq!(loaded.status, SessionStatus::Stopped);
}
#[test]
fn effective_status_active_when_tmux_alive() {
let session = make_session("eff-active");
let status = session.effective_status(|_| true);
assert_eq!(status, SessionStatus::Active);
}
#[test]
fn effective_status_stopped_when_tmux_dead() {
let session = make_session("eff-stopped");
let status = session.effective_status(|_| false);
assert_eq!(status, SessionStatus::Stopped);
}
#[test]
fn effective_status_stopped_stays_stopped() {
let mut session = make_session("eff-stay-stopped");
session.status = SessionStatus::Stopped;
let status = session.effective_status(|_| true);
assert_eq!(status, SessionStatus::Stopped);
}
#[test]
fn saved_session_has_all_recovery_fields() {
let dir = TempDir::new().expect("create temp dir");
let session = make_session("recovery");
save_session_in(&session, dir.path()).expect("save");
let loaded = load_session_from(&session.session_name, dir.path())
.expect("load")
.expect("session should exist");
assert!(!loaded.session_name.is_empty());
assert!(!loaded.repo_path.as_os_str().is_empty());
assert!(!loaded.project_name.is_empty());
assert!(!loaded.worktrees.is_empty());
for wt in &loaded.worktrees {
assert!(!wt.branch.is_empty(), "branch must be set for recovery");
assert!(
!wt.worktree_path.as_os_str().is_empty(),
"worktree path must be set"
);
assert!(!wt.cli.is_empty(), "CLI must be set for recovery");
}
}