1use super::open_board_locked;
8use crate::error::Result;
9use std::path::Path;
10
11#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct UndoOutcome {
14 pub reverted: String,
16}
17
18pub async fn undo_last_mutation(project_dir: &Path) -> Result<UndoOutcome> {
24 let (_board_dir, repo, _config, _lock) = open_board_locked(project_dir).await?;
25 let reverted = repo.undo().await?;
26 Ok(UndoOutcome { reverted })
27}
28
29#[cfg(test)]
30mod tests {
31 use super::*;
32 use crate::config::{Config, StorageBackend};
33 use crate::error::Error;
34 use crate::service::{ListFilter, NewItem, add_item, init_board, list_items};
35 use tempfile::TempDir;
36
37 async fn init_with_backend(dir: &Path, backend: StorageBackend) {
38 init_board(dir).await.expect("init");
39 let config_path = dir.join(".pinto/config.toml");
40 let mut config = Config::load(&config_path).await.expect("config");
41 config.storage.backend = backend;
42 config.save(&config_path).await.expect("save config");
43 }
44
45 #[tokio::test]
46 async fn undo_reverts_the_last_git_mutation() {
47 let dir = TempDir::new().expect("temp dir");
48 init_with_backend(dir.path(), StorageBackend::Git).await;
49 let first = add_item(dir.path(), "First", NewItem::default())
50 .await
51 .expect("add");
52 let second = add_item(dir.path(), "Second", NewItem::default())
53 .await
54 .expect("add");
55
56 let outcome = undo_last_mutation(dir.path()).await.expect("undo");
57 assert_eq!(outcome.reverted, format!("pinto: add {}", second.id));
58
59 let ids: Vec<_> = list_items(dir.path(), &ListFilter::default())
61 .await
62 .expect("list")
63 .into_iter()
64 .map(|item| item.id)
65 .collect();
66 assert!(ids.contains(&first.id), "first item remains");
67 assert!(!ids.contains(&second.id), "second item reverted");
68 }
69
70 #[tokio::test]
71 async fn undo_on_file_backend_is_unsupported() {
72 let dir = TempDir::new().expect("temp dir");
73 init_with_backend(dir.path(), StorageBackend::File).await;
74 add_item(dir.path(), "First", NewItem::default())
75 .await
76 .expect("add");
77
78 let err = undo_last_mutation(dir.path())
79 .await
80 .expect_err("file backend keeps no history");
81 assert!(
82 matches!(err, Error::UndoUnsupported { backend } if backend == "file"),
83 "expected UndoUnsupported(file)"
84 );
85 }
86}