storkit: merge 444_refactor_extract_shared_test_helpers_test_ctx_write_story_file_make_api
This commit is contained in:
@@ -64,6 +64,13 @@ impl AnthropicApi {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl From<Arc<AppContext>> for AnthropicApi {
|
||||
fn from(ctx: Arc<AppContext>) -> Self {
|
||||
Self::new(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
#[OpenApi(tag = "AnthropicTags::Anthropic")]
|
||||
impl AnthropicApi {
|
||||
/// Check whether an Anthropic API key is stored.
|
||||
@@ -151,25 +158,16 @@ impl AnthropicApi {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::context::AppContext;
|
||||
use crate::http::test_helpers::{make_api, test_ctx};
|
||||
use serde_json::json;
|
||||
use std::sync::Arc;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn test_ctx(dir: &TempDir) -> AppContext {
|
||||
AppContext::new_test(dir.path().to_path_buf())
|
||||
}
|
||||
|
||||
fn make_api(dir: &TempDir) -> AnthropicApi {
|
||||
AnthropicApi::new(Arc::new(test_ctx(dir)))
|
||||
}
|
||||
|
||||
// -- get_anthropic_api_key (private helper) --
|
||||
|
||||
#[test]
|
||||
fn get_api_key_returns_err_when_not_set() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let ctx = test_ctx(&dir);
|
||||
let ctx = test_ctx(dir.path());
|
||||
let result = get_anthropic_api_key(&ctx);
|
||||
assert!(result.is_err());
|
||||
assert!(result.unwrap_err().contains("not found"));
|
||||
@@ -178,7 +176,7 @@ mod tests {
|
||||
#[test]
|
||||
fn get_api_key_returns_err_when_empty() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let ctx = test_ctx(&dir);
|
||||
let ctx = test_ctx(dir.path());
|
||||
ctx.store.set(KEY_ANTHROPIC_API_KEY, json!(""));
|
||||
let result = get_anthropic_api_key(&ctx);
|
||||
assert!(result.is_err());
|
||||
@@ -188,7 +186,7 @@ mod tests {
|
||||
#[test]
|
||||
fn get_api_key_returns_err_when_not_string() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let ctx = test_ctx(&dir);
|
||||
let ctx = test_ctx(dir.path());
|
||||
ctx.store.set(KEY_ANTHROPIC_API_KEY, json!(12345));
|
||||
let result = get_anthropic_api_key(&ctx);
|
||||
assert!(result.is_err());
|
||||
@@ -198,7 +196,7 @@ mod tests {
|
||||
#[test]
|
||||
fn get_api_key_returns_key_when_set() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let ctx = test_ctx(&dir);
|
||||
let ctx = test_ctx(dir.path());
|
||||
ctx.store.set(KEY_ANTHROPIC_API_KEY, json!("sk-ant-test123"));
|
||||
let result = get_anthropic_api_key(&ctx);
|
||||
assert_eq!(result.unwrap(), "sk-ant-test123");
|
||||
@@ -209,7 +207,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn key_exists_returns_false_when_not_set() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<AnthropicApi>(&dir);
|
||||
let result = api.get_anthropic_api_key_exists().await.unwrap();
|
||||
assert!(!result.0);
|
||||
}
|
||||
@@ -229,7 +227,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn set_api_key_returns_true() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<AnthropicApi>(&dir);
|
||||
let payload = Json(ApiKeyPayload {
|
||||
api_key: "sk-ant-test123".to_string(),
|
||||
});
|
||||
@@ -256,7 +254,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn list_models_fails_when_no_key() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<AnthropicApi>(&dir);
|
||||
let result = api.list_anthropic_models().await;
|
||||
assert!(result.is_err());
|
||||
}
|
||||
@@ -288,7 +286,7 @@ mod tests {
|
||||
#[test]
|
||||
fn new_creates_api_instance() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let _api = make_api(&dir);
|
||||
let _api = make_api::<AnthropicApi>(&dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
+25
-24
@@ -138,18 +138,19 @@ impl IoApi {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl From<std::sync::Arc<AppContext>> for IoApi {
|
||||
fn from(ctx: std::sync::Arc<AppContext>) -> Self {
|
||||
Self { ctx }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::context::AppContext;
|
||||
use crate::http::test_helpers::make_api;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn make_api(dir: &TempDir) -> IoApi {
|
||||
IoApi {
|
||||
ctx: Arc::new(AppContext::new_test(dir.path().to_path_buf())),
|
||||
}
|
||||
}
|
||||
|
||||
// --- list_directory_absolute ---
|
||||
|
||||
#[tokio::test]
|
||||
@@ -158,7 +159,7 @@ mod tests {
|
||||
std::fs::create_dir(dir.path().join("subdir")).unwrap();
|
||||
std::fs::write(dir.path().join("file.txt"), "content").unwrap();
|
||||
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<IoApi>(&dir);
|
||||
let payload = Json(FilePathPayload {
|
||||
path: dir.path().to_string_lossy().to_string(),
|
||||
});
|
||||
@@ -176,7 +177,7 @@ mod tests {
|
||||
let empty = dir.path().join("empty");
|
||||
std::fs::create_dir(&empty).unwrap();
|
||||
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<IoApi>(&dir);
|
||||
let payload = Json(FilePathPayload {
|
||||
path: empty.to_string_lossy().to_string(),
|
||||
});
|
||||
@@ -187,7 +188,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn list_directory_absolute_errors_on_nonexistent_path() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<IoApi>(&dir);
|
||||
let payload = Json(FilePathPayload {
|
||||
path: dir.path().join("nonexistent").to_string_lossy().to_string(),
|
||||
});
|
||||
@@ -201,7 +202,7 @@ mod tests {
|
||||
let file = dir.path().join("not_a_dir.txt");
|
||||
std::fs::write(&file, "content").unwrap();
|
||||
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<IoApi>(&dir);
|
||||
let payload = Json(FilePathPayload {
|
||||
path: file.to_string_lossy().to_string(),
|
||||
});
|
||||
@@ -216,7 +217,7 @@ mod tests {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let new_dir = dir.path().join("new_dir");
|
||||
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<IoApi>(&dir);
|
||||
let payload = Json(CreateDirectoryPayload {
|
||||
path: new_dir.to_string_lossy().to_string(),
|
||||
});
|
||||
@@ -231,7 +232,7 @@ mod tests {
|
||||
let existing = dir.path().join("existing");
|
||||
std::fs::create_dir(&existing).unwrap();
|
||||
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<IoApi>(&dir);
|
||||
let payload = Json(CreateDirectoryPayload {
|
||||
path: existing.to_string_lossy().to_string(),
|
||||
});
|
||||
@@ -244,7 +245,7 @@ mod tests {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let nested = dir.path().join("a").join("b").join("c");
|
||||
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<IoApi>(&dir);
|
||||
let payload = Json(CreateDirectoryPayload {
|
||||
path: nested.to_string_lossy().to_string(),
|
||||
});
|
||||
@@ -258,7 +259,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn get_home_directory_returns_a_path() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<IoApi>(&dir);
|
||||
let result = api.get_home_directory().await.unwrap();
|
||||
let home = &result.0;
|
||||
assert!(!home.is_empty());
|
||||
@@ -272,7 +273,7 @@ mod tests {
|
||||
let dir = TempDir::new().unwrap();
|
||||
std::fs::write(dir.path().join("hello.txt"), "hello world").unwrap();
|
||||
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<IoApi>(&dir);
|
||||
let payload = Json(FilePathPayload {
|
||||
path: "hello.txt".to_string(),
|
||||
});
|
||||
@@ -283,7 +284,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn read_file_errors_on_missing_file() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<IoApi>(&dir);
|
||||
let payload = Json(FilePathPayload {
|
||||
path: "nonexistent.txt".to_string(),
|
||||
});
|
||||
@@ -296,7 +297,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn write_file_creates_file() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<IoApi>(&dir);
|
||||
let payload = Json(WriteFilePayload {
|
||||
path: "output.txt".to_string(),
|
||||
content: "written content".to_string(),
|
||||
@@ -312,7 +313,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn write_file_creates_parent_dirs() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<IoApi>(&dir);
|
||||
let payload = Json(WriteFilePayload {
|
||||
path: "sub/dir/file.txt".to_string(),
|
||||
content: "nested".to_string(),
|
||||
@@ -334,7 +335,7 @@ mod tests {
|
||||
std::fs::write(dir.path().join("src/main.rs"), "fn main() {}").unwrap();
|
||||
std::fs::write(dir.path().join("README.md"), "# readme").unwrap();
|
||||
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<IoApi>(&dir);
|
||||
let result = api.list_project_files().await.unwrap();
|
||||
let files = &result.0;
|
||||
|
||||
@@ -348,7 +349,7 @@ mod tests {
|
||||
std::fs::create_dir(dir.path().join("subdir")).unwrap();
|
||||
std::fs::write(dir.path().join("file.txt"), "").unwrap();
|
||||
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<IoApi>(&dir);
|
||||
let result = api.list_project_files().await.unwrap();
|
||||
let files = &result.0;
|
||||
|
||||
@@ -363,7 +364,7 @@ mod tests {
|
||||
std::fs::write(dir.path().join("z_last.txt"), "").unwrap();
|
||||
std::fs::write(dir.path().join("a_first.txt"), "").unwrap();
|
||||
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<IoApi>(&dir);
|
||||
let result = api.list_project_files().await.unwrap();
|
||||
let files = &result.0;
|
||||
|
||||
@@ -380,7 +381,7 @@ mod tests {
|
||||
std::fs::create_dir(dir.path().join("adir")).unwrap();
|
||||
std::fs::write(dir.path().join("bfile.txt"), "").unwrap();
|
||||
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<IoApi>(&dir);
|
||||
let payload = Json(FilePathPayload {
|
||||
path: ".".to_string(),
|
||||
});
|
||||
@@ -394,7 +395,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn list_directory_errors_on_nonexistent() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<IoApi>(&dir);
|
||||
let payload = Json(FilePathPayload {
|
||||
path: "nonexistent_dir".to_string(),
|
||||
});
|
||||
|
||||
@@ -370,13 +370,9 @@ pub(super) async fn get_worktree_commits(worktree_path: &str, base_branch: &str)
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::context::AppContext;
|
||||
use crate::http::test_helpers::test_ctx;
|
||||
use crate::store::StoreOps;
|
||||
|
||||
fn test_ctx(dir: &std::path::Path) -> AppContext {
|
||||
AppContext::new_test(dir.to_path_buf())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tool_list_agents_empty() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
|
||||
@@ -279,11 +279,7 @@ pub(super) fn tool_loc_file(args: &Value, ctx: &AppContext) -> Result<String, St
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::context::AppContext;
|
||||
|
||||
fn test_ctx(dir: &std::path::Path) -> AppContext {
|
||||
AppContext::new_test(dir.to_path_buf())
|
||||
}
|
||||
use crate::http::test_helpers::test_ctx;
|
||||
|
||||
#[test]
|
||||
fn tool_get_server_logs_no_args_returns_string() {
|
||||
|
||||
@@ -304,12 +304,9 @@ pub(super) async fn tool_git_log(args: &Value, ctx: &AppContext) -> Result<Strin
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::context::AppContext;
|
||||
use crate::http::test_helpers::test_ctx;
|
||||
use serde_json::json;
|
||||
|
||||
fn test_ctx(dir: &std::path::Path) -> AppContext {
|
||||
AppContext::new_test(dir.to_path_buf())
|
||||
}
|
||||
|
||||
/// Create a temp directory with a git worktree structure and init a repo.
|
||||
fn setup_worktree() -> (tempfile::TempDir, PathBuf, AppContext) {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
|
||||
@@ -164,11 +164,7 @@ pub(super) fn tool_report_merge_failure(args: &Value, ctx: &AppContext) -> Resul
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::context::AppContext;
|
||||
|
||||
fn test_ctx(dir: &std::path::Path) -> AppContext {
|
||||
AppContext::new_test(dir.to_path_buf())
|
||||
}
|
||||
use crate::http::test_helpers::test_ctx;
|
||||
|
||||
fn setup_git_repo_in(dir: &std::path::Path) {
|
||||
std::process::Command::new("git")
|
||||
|
||||
@@ -1336,11 +1336,7 @@ async fn handle_tools_call(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::context::AppContext;
|
||||
|
||||
fn test_ctx(dir: &std::path::Path) -> AppContext {
|
||||
AppContext::new_test(dir.to_path_buf())
|
||||
}
|
||||
use crate::http::test_helpers::test_ctx;
|
||||
|
||||
#[test]
|
||||
fn json_rpc_response_serializes_success() {
|
||||
|
||||
@@ -194,11 +194,7 @@ pub(super) fn find_free_port(start: u16) -> u16 {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::context::AppContext;
|
||||
|
||||
fn test_ctx(dir: &std::path::Path) -> AppContext {
|
||||
AppContext::new_test(dir.to_path_buf())
|
||||
}
|
||||
use crate::http::test_helpers::test_ctx;
|
||||
|
||||
#[test]
|
||||
fn request_qa_in_tools_list() {
|
||||
|
||||
@@ -331,13 +331,9 @@ pub(super) fn handle_run_command_sse(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::context::AppContext;
|
||||
use crate::http::test_helpers::test_ctx;
|
||||
use serde_json::json;
|
||||
|
||||
fn test_ctx(dir: &std::path::Path) -> AppContext {
|
||||
AppContext::new_test(dir.to_path_buf())
|
||||
}
|
||||
|
||||
// ── is_dangerous ─────────────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -549,11 +549,7 @@ pub(super) fn parse_test_cases(value: Option<&Value>) -> Result<Vec<TestCaseResu
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::context::AppContext;
|
||||
|
||||
fn test_ctx(dir: &std::path::Path) -> AppContext {
|
||||
AppContext::new_test(dir.to_path_buf())
|
||||
}
|
||||
use crate::http::test_helpers::test_ctx;
|
||||
|
||||
#[test]
|
||||
fn parse_test_cases_empty() {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
pub mod agents;
|
||||
pub mod agents_sse;
|
||||
pub mod anthropic;
|
||||
#[cfg(test)]
|
||||
pub(crate) mod test_helpers;
|
||||
pub mod assets;
|
||||
pub mod bot_command;
|
||||
pub mod chat;
|
||||
|
||||
+13
-12
@@ -50,22 +50,23 @@ impl ModelApi {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl From<std::sync::Arc<AppContext>> for ModelApi {
|
||||
fn from(ctx: std::sync::Arc<AppContext>) -> Self {
|
||||
Self { ctx }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::context::AppContext;
|
||||
use crate::http::test_helpers::make_api;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn make_api(dir: &TempDir) -> ModelApi {
|
||||
ModelApi {
|
||||
ctx: Arc::new(AppContext::new_test(dir.path().to_path_buf())),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_model_preference_returns_none_when_unset() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<ModelApi>(&dir);
|
||||
let result = api.get_model_preference().await.unwrap();
|
||||
assert!(result.0.is_none());
|
||||
}
|
||||
@@ -73,7 +74,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn set_model_preference_returns_true() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<ModelApi>(&dir);
|
||||
let payload = Json(ModelPayload {
|
||||
model: "claude-3-sonnet".to_string(),
|
||||
});
|
||||
@@ -84,7 +85,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn get_model_preference_returns_value_after_set() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<ModelApi>(&dir);
|
||||
|
||||
let payload = Json(ModelPayload {
|
||||
model: "claude-3-sonnet".to_string(),
|
||||
@@ -98,7 +99,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn set_model_preference_overwrites_previous_value() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<ModelApi>(&dir);
|
||||
|
||||
api.set_model_preference(Json(ModelPayload {
|
||||
model: "model-a".to_string(),
|
||||
@@ -119,7 +120,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn get_ollama_models_returns_empty_list_for_unreachable_url() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<ModelApi>(&dir);
|
||||
// Port 1 is reserved and should immediately refuse the connection.
|
||||
let base_url = Query(Some("http://127.0.0.1:1".to_string()));
|
||||
let result = api.get_ollama_models(base_url).await;
|
||||
|
||||
+18
-17
@@ -73,22 +73,23 @@ impl ProjectApi {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl From<std::sync::Arc<AppContext>> for ProjectApi {
|
||||
fn from(ctx: std::sync::Arc<AppContext>) -> Self {
|
||||
Self { ctx }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::context::AppContext;
|
||||
use crate::http::test_helpers::make_api;
|
||||
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);
|
||||
let api = make_api::<ProjectApi>(&dir);
|
||||
// Clear the project root that new_test sets
|
||||
api.close_project().await.unwrap();
|
||||
let result = api.get_current_project().await.unwrap();
|
||||
@@ -98,7 +99,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn get_current_project_returns_path_from_state() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<ProjectApi>(&dir);
|
||||
let result = api.get_current_project().await.unwrap();
|
||||
assert_eq!(result.0, Some(dir.path().to_string_lossy().to_string()));
|
||||
}
|
||||
@@ -106,7 +107,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn open_project_succeeds_with_valid_directory() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<ProjectApi>(&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();
|
||||
@@ -116,7 +117,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn open_project_fails_with_nonexistent_file_path() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<ProjectApi>(&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();
|
||||
@@ -130,7 +131,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn close_project_returns_true() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<ProjectApi>(&dir);
|
||||
let result = api.close_project().await.unwrap();
|
||||
assert!(result.0);
|
||||
}
|
||||
@@ -138,7 +139,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn close_project_clears_current_project() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<ProjectApi>(&dir);
|
||||
|
||||
// Verify project is set initially
|
||||
let before = api.get_current_project().await.unwrap();
|
||||
@@ -155,7 +156,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn list_known_projects_returns_empty_initially() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<ProjectApi>(&dir);
|
||||
// Close the project so the store has no known projects
|
||||
api.close_project().await.unwrap();
|
||||
let result = api.list_known_projects().await.unwrap();
|
||||
@@ -165,7 +166,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn list_known_projects_returns_project_after_open() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<ProjectApi>(&dir);
|
||||
let path = dir.path().to_string_lossy().to_string();
|
||||
|
||||
api.open_project(Json(PathPayload { path: path.clone() }))
|
||||
@@ -179,7 +180,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn forget_known_project_removes_project() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<ProjectApi>(&dir);
|
||||
let path = dir.path().to_string_lossy().to_string();
|
||||
|
||||
api.open_project(Json(PathPayload { path: path.clone() }))
|
||||
@@ -202,7 +203,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn forget_known_project_returns_true_for_nonexistent_path() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<ProjectApi>(&dir);
|
||||
let result = api
|
||||
.forget_known_project(Json(PathPayload {
|
||||
path: "/some/unknown/path".to_string(),
|
||||
|
||||
+25
-29
@@ -104,27 +104,23 @@ pub fn get_editor_command_from_store(ctx: &AppContext) -> Option<String> {
|
||||
.and_then(|v| v.as_str().map(|s| s.to_string()))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl From<std::sync::Arc<AppContext>> for SettingsApi {
|
||||
fn from(ctx: std::sync::Arc<AppContext>) -> Self {
|
||||
Self { ctx }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::context::AppContext;
|
||||
use std::sync::Arc;
|
||||
use crate::http::test_helpers::{make_api, test_ctx};
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn test_ctx(dir: &TempDir) -> AppContext {
|
||||
AppContext::new_test(dir.path().to_path_buf())
|
||||
}
|
||||
|
||||
fn make_api(dir: &TempDir) -> SettingsApi {
|
||||
SettingsApi {
|
||||
ctx: Arc::new(AppContext::new_test(dir.path().to_path_buf())),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_editor_returns_none_when_unset() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<SettingsApi>(&dir);
|
||||
let result = api.get_editor().await.unwrap();
|
||||
assert!(result.0.editor_command.is_none());
|
||||
}
|
||||
@@ -132,7 +128,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn set_editor_stores_command() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<SettingsApi>(&dir);
|
||||
let payload = Json(EditorCommandPayload {
|
||||
editor_command: Some("zed".to_string()),
|
||||
});
|
||||
@@ -143,7 +139,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn set_editor_clears_command_on_null() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<SettingsApi>(&dir);
|
||||
api.set_editor(Json(EditorCommandPayload {
|
||||
editor_command: Some("zed".to_string()),
|
||||
}))
|
||||
@@ -161,7 +157,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn set_editor_clears_command_on_empty_string() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<SettingsApi>(&dir);
|
||||
let result = api
|
||||
.set_editor(Json(EditorCommandPayload {
|
||||
editor_command: Some(String::new()),
|
||||
@@ -174,7 +170,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn set_editor_trims_whitespace_only() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<SettingsApi>(&dir);
|
||||
let result = api
|
||||
.set_editor(Json(EditorCommandPayload {
|
||||
editor_command: Some(" ".to_string()),
|
||||
@@ -187,7 +183,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn get_editor_returns_value_after_set() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<SettingsApi>(&dir);
|
||||
api.set_editor(Json(EditorCommandPayload {
|
||||
editor_command: Some("cursor".to_string()),
|
||||
}))
|
||||
@@ -200,7 +196,7 @@ mod tests {
|
||||
#[test]
|
||||
fn editor_command_defaults_to_null() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let ctx = test_ctx(&dir);
|
||||
let ctx = test_ctx(dir.path());
|
||||
let result = get_editor_command_from_store(&ctx);
|
||||
assert!(result.is_none());
|
||||
}
|
||||
@@ -208,7 +204,7 @@ mod tests {
|
||||
#[test]
|
||||
fn set_editor_command_persists_in_store() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let ctx = test_ctx(&dir);
|
||||
let ctx = test_ctx(dir.path());
|
||||
|
||||
ctx.store.set(EDITOR_COMMAND_KEY, json!("zed"));
|
||||
ctx.store.save().unwrap();
|
||||
@@ -220,7 +216,7 @@ mod tests {
|
||||
#[test]
|
||||
fn get_editor_command_from_store_returns_value() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let ctx = test_ctx(&dir);
|
||||
let ctx = test_ctx(dir.path());
|
||||
|
||||
ctx.store.set(EDITOR_COMMAND_KEY, json!("code"));
|
||||
let result = get_editor_command_from_store(&ctx);
|
||||
@@ -230,7 +226,7 @@ mod tests {
|
||||
#[test]
|
||||
fn delete_editor_command_returns_none() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let ctx = test_ctx(&dir);
|
||||
let ctx = test_ctx(dir.path());
|
||||
|
||||
ctx.store.set(EDITOR_COMMAND_KEY, json!("cursor"));
|
||||
ctx.store.delete(EDITOR_COMMAND_KEY);
|
||||
@@ -258,7 +254,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn get_editor_http_handler_returns_null_when_not_set() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let ctx = test_ctx(&dir);
|
||||
let ctx = test_ctx(dir.path());
|
||||
let api = SettingsApi {
|
||||
ctx: Arc::new(ctx),
|
||||
};
|
||||
@@ -269,7 +265,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn set_editor_http_handler_stores_value() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let ctx = test_ctx(&dir);
|
||||
let ctx = test_ctx(dir.path());
|
||||
let api = SettingsApi {
|
||||
ctx: Arc::new(ctx),
|
||||
};
|
||||
@@ -286,7 +282,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn set_editor_http_handler_clears_value_when_null() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let ctx = test_ctx(&dir);
|
||||
let ctx = test_ctx(dir.path());
|
||||
let api = SettingsApi {
|
||||
ctx: Arc::new(ctx),
|
||||
};
|
||||
@@ -310,7 +306,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn open_file_returns_error_when_no_editor_configured() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<SettingsApi>(&dir);
|
||||
let result = api
|
||||
.open_file(Query("src/main.rs".to_string()), Query(Some(42)))
|
||||
.await;
|
||||
@@ -322,7 +318,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn open_file_spawns_editor_with_path_and_line() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<SettingsApi>(&dir);
|
||||
// Configure the editor to "echo" which is a safe no-op command
|
||||
api.set_editor(Json(EditorCommandPayload {
|
||||
editor_command: Some("echo".to_string()),
|
||||
@@ -339,7 +335,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn open_file_spawns_editor_with_path_only_when_no_line() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<SettingsApi>(&dir);
|
||||
api.set_editor(Json(EditorCommandPayload {
|
||||
editor_command: Some("echo".to_string()),
|
||||
}))
|
||||
@@ -355,7 +351,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn open_file_returns_error_for_nonexistent_editor() {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let api = make_api(&dir);
|
||||
let api = make_api::<SettingsApi>(&dir);
|
||||
api.set_editor(Json(EditorCommandPayload {
|
||||
editor_command: Some("this_editor_does_not_exist_xyz_abc".to_string()),
|
||||
}))
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
//! Shared test utilities for HTTP handler tests.
|
||||
//!
|
||||
//! Import with `use crate::http::test_helpers::{make_api, test_ctx};`
|
||||
|
||||
use crate::http::context::AppContext;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use tempfile::TempDir;
|
||||
|
||||
/// Build an [`AppContext`] rooted at `dir` for use in tests.
|
||||
pub(crate) fn test_ctx(dir: &Path) -> AppContext {
|
||||
AppContext::new_test(dir.to_path_buf())
|
||||
}
|
||||
|
||||
/// Build an API struct rooted in `dir` for use in tests.
|
||||
///
|
||||
/// Requires the API type to implement `From<Arc<AppContext>>`. Add a
|
||||
/// `#[cfg(test)]` impl block to each API struct to opt in.
|
||||
pub(crate) fn make_api<T: From<Arc<AppContext>>>(dir: &TempDir) -> T {
|
||||
Arc::new(test_ctx(dir.path())).into()
|
||||
}
|
||||
Reference in New Issue
Block a user