use ralph::checkpoint::Checkpoint;
use ralph::config::{Config, SessionConfig};
use ralph::providers::Message;
use ralph::session::Session;
use ralph::tools::file_tools;
use tempfile::TempDir;
fn test_config(sessions_dir: &str) -> Config {
let mut config = Config::default();
config.session = SessionConfig {
auto_resume: false,
sessions_dir: Some(sessions_dir.to_string()),
clean_after_days: 30,
};
config
}
fn make_session(workspace: &std::path::Path, config: &Config) -> Session {
Session::create(workspace, "anthropic", "claude-sonnet-4-6", config).unwrap()
}
#[tokio::test]
async fn create_checkpoint_at_session_start() {
let dir = TempDir::new().unwrap();
let workspace = dir.path().join("ws");
std::fs::create_dir_all(&workspace).unwrap();
let sessions_dir = dir.path().join("sessions");
let config = test_config(&sessions_dir.display().to_string());
let session = make_session(&workspace, &config);
let cp = Checkpoint::create(&session, "initial", &Default::default())
.await
.unwrap();
assert_eq!(cp.meta.name, "initial");
assert_eq!(cp.meta.turn, 0);
}
#[tokio::test]
async fn list_checkpoints_sorted_by_sequence() {
let dir = TempDir::new().unwrap();
let workspace = dir.path().join("ws");
std::fs::create_dir_all(&workspace).unwrap();
let sessions_dir = dir.path().join("sessions");
let config = test_config(&sessions_dir.display().to_string());
let session = make_session(&workspace, &config);
Checkpoint::create(&session, "first", &Default::default())
.await
.unwrap();
Checkpoint::create(&session, "second", &Default::default())
.await
.unwrap();
Checkpoint::create(&session, "third", &Default::default())
.await
.unwrap();
let list = Checkpoint::list(&session);
assert_eq!(list.len(), 3);
assert_eq!(list[0].name, "first");
assert_eq!(list[1].name, "second");
assert_eq!(list[2].name, "third");
}
#[tokio::test]
async fn find_checkpoint_by_name() {
let dir = TempDir::new().unwrap();
let workspace = dir.path().join("ws");
std::fs::create_dir_all(&workspace).unwrap();
let sessions_dir = dir.path().join("sessions");
let config = test_config(&sessions_dir.display().to_string());
let session = make_session(&workspace, &config);
Checkpoint::create(&session, "my-checkpoint", &Default::default())
.await
.unwrap();
let found = Checkpoint::find(&session, "my-checkpoint").unwrap();
assert_eq!(found.meta.name, "my-checkpoint");
}
#[tokio::test]
async fn find_checkpoint_by_number() {
let dir = TempDir::new().unwrap();
let workspace = dir.path().join("ws");
std::fs::create_dir_all(&workspace).unwrap();
let sessions_dir = dir.path().join("sessions");
let config = test_config(&sessions_dir.display().to_string());
let session = make_session(&workspace, &config);
Checkpoint::create(&session, "alpha", &Default::default())
.await
.unwrap();
Checkpoint::create(&session, "beta", &Default::default())
.await
.unwrap();
let found = Checkpoint::find(&session, "2").unwrap();
assert_eq!(found.meta.name, "beta");
}
#[tokio::test]
async fn find_nonexistent_checkpoint_errors() {
let dir = TempDir::new().unwrap();
let workspace = dir.path().join("ws");
std::fs::create_dir_all(&workspace).unwrap();
let sessions_dir = dir.path().join("sessions");
let config = test_config(&sessions_dir.display().to_string());
let session = make_session(&workspace, &config);
assert!(Checkpoint::find(&session, "ghost").is_err());
assert!(Checkpoint::find(&session, "99").is_err());
}
#[tokio::test]
async fn checkpoint_snapshots_modified_files() {
let dir = TempDir::new().unwrap();
let workspace = dir.path().join("ws");
std::fs::create_dir_all(&workspace).unwrap();
let sessions_dir = dir.path().join("sessions");
let config = test_config(&sessions_dir.display().to_string());
let file_path = workspace.join("src").join("lib.rs");
file_tools::write_file(&file_path, "pub fn hello() {}").unwrap();
let mut session = make_session(&workspace, &config);
session.modified_files.push(file_path.clone());
let cp = Checkpoint::create(&session, "with-files", &Default::default())
.await
.unwrap();
assert_eq!(cp.meta.modified_files.len(), 1);
assert!(cp.meta.modified_files[0].contains("lib.rs"));
let snapshot = session
.checkpoints_dir()
.join(&cp.meta.id)
.join("files")
.join("src")
.join("lib.rs");
assert!(snapshot.exists());
let snapshot_content = std::fs::read_to_string(&snapshot).unwrap();
assert_eq!(snapshot_content, "pub fn hello() {}");
}
#[tokio::test]
async fn checkpoint_preserves_messages() {
let dir = TempDir::new().unwrap();
let workspace = dir.path().join("ws");
std::fs::create_dir_all(&workspace).unwrap();
let sessions_dir = dir.path().join("sessions");
let config = test_config(&sessions_dir.display().to_string());
let mut session = make_session(&workspace, &config);
session.messages.push(Message::user("do the thing"));
session.messages.push(Message::assistant("done!"));
session.flush().unwrap();
let cp = Checkpoint::create(&session, "with-msgs", &Default::default())
.await
.unwrap();
assert_eq!(cp.messages.len(), 2);
}