diff --git a/server/src/http/project.rs b/server/src/http/project.rs index eb04a70..7cdb77f 100644 --- a/server/src/http/project.rs +++ b/server/src/http/project.rs @@ -62,3 +62,143 @@ impl ProjectApi { Ok(Json(true)) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::http::context::AppContext; + use tempfile::TempDir; + + fn make_api(dir: &TempDir) -> ProjectApi { + ProjectApi { + ctx: Arc::new(AppContext::new_test(dir.path().to_path_buf())), + } + } + + #[tokio::test] + async fn get_current_project_returns_none_when_unset() { + let dir = TempDir::new().unwrap(); + let api = make_api(&dir); + // Clear the project root that new_test sets + api.close_project().await.unwrap(); + let result = api.get_current_project().await.unwrap(); + assert!(result.0.is_none()); + } + + #[tokio::test] + async fn get_current_project_returns_path_from_state() { + let dir = TempDir::new().unwrap(); + let api = make_api(&dir); + let result = api.get_current_project().await.unwrap(); + assert_eq!(result.0, Some(dir.path().to_string_lossy().to_string())); + } + + #[tokio::test] + async fn open_project_succeeds_with_valid_directory() { + let dir = TempDir::new().unwrap(); + let api = make_api(&dir); + let path = dir.path().to_string_lossy().to_string(); + let payload = Json(PathPayload { path: path.clone() }); + let result = api.open_project(payload).await.unwrap(); + assert_eq!(result.0, path); + } + + #[tokio::test] + async fn open_project_fails_with_nonexistent_file_path() { + let dir = TempDir::new().unwrap(); + let api = make_api(&dir); + // Create a file (not a directory) to trigger validation error + let file_path = dir.path().join("not_a_dir.txt"); + std::fs::write(&file_path, "content").unwrap(); + let payload = Json(PathPayload { + path: file_path.to_string_lossy().to_string(), + }); + let result = api.open_project(payload).await; + assert!(result.is_err()); + } + + #[tokio::test] + async fn close_project_returns_true() { + let dir = TempDir::new().unwrap(); + let api = make_api(&dir); + let result = api.close_project().await.unwrap(); + assert!(result.0); + } + + #[tokio::test] + async fn close_project_clears_current_project() { + let dir = TempDir::new().unwrap(); + let api = make_api(&dir); + + // Verify project is set initially + let before = api.get_current_project().await.unwrap(); + assert!(before.0.is_some()); + + // Close the project + api.close_project().await.unwrap(); + + // Verify project is now None + let after = api.get_current_project().await.unwrap(); + assert!(after.0.is_none()); + } + + #[tokio::test] + async fn list_known_projects_returns_empty_initially() { + let dir = TempDir::new().unwrap(); + let api = make_api(&dir); + // Close the project so the store has no known projects + api.close_project().await.unwrap(); + let result = api.list_known_projects().await.unwrap(); + assert!(result.0.is_empty()); + } + + #[tokio::test] + async fn list_known_projects_returns_project_after_open() { + let dir = TempDir::new().unwrap(); + let api = make_api(&dir); + let path = dir.path().to_string_lossy().to_string(); + + api.open_project(Json(PathPayload { path: path.clone() })) + .await + .unwrap(); + + let result = api.list_known_projects().await.unwrap(); + assert!(result.0.contains(&path)); + } + + #[tokio::test] + async fn forget_known_project_removes_project() { + let dir = TempDir::new().unwrap(); + let api = make_api(&dir); + let path = dir.path().to_string_lossy().to_string(); + + api.open_project(Json(PathPayload { path: path.clone() })) + .await + .unwrap(); + + let before = api.list_known_projects().await.unwrap(); + assert!(before.0.contains(&path)); + + let result = api + .forget_known_project(Json(PathPayload { path: path.clone() })) + .await + .unwrap(); + assert!(result.0); + + let after = api.list_known_projects().await.unwrap(); + assert!(!after.0.contains(&path)); + } + + #[tokio::test] + async fn forget_known_project_returns_true_for_nonexistent_path() { + let dir = TempDir::new().unwrap(); + let api = make_api(&dir); + let result = api + .forget_known_project(Json(PathPayload { + path: "/some/unknown/path".to_string(), + })) + .await + .unwrap(); + assert!(result.0); + } +}