test: boost coverage to 76% and optimize Store inspection
This commit is contained in:
1 parent
81aac7245b
commit
26cf6cee80
3 files changed
+340
-1
No files matched your search
@@ -1,5 +1,6 @@
|
|||||||
use serde_json::Value;
|
use serde_json::{json, Value};
|
||||||
use std::io::{BufRead, BufReader, Read, Write};
|
use std::io::{BufRead, BufReader, Read, Write};
|
||||||
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
fn send_message(stdin: &mut std::process::ChildStdin, msg: Value) {
|
fn send_message(stdin: &mut std::process::ChildStdin, msg: Value) {
|
||||||
let s = serde_json::to_string(&msg).unwrap();
|
let s = serde_json::to_string(&msg).unwrap();
|
||||||
|
|||||||
@@ -2690,4 +2690,334 @@ mod tests {
|
|||||||
let tasks = handler.state.tasks.read();
|
let tasks = handler.state.tasks.read();
|
||||||
assert_eq!(tasks[0].status, "in_progress");
|
assert_eq!(tasks[0].status, "in_progress");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_pin_file() {
|
||||||
|
let handler = setup_test_handler("pin_file");
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 100,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "pin_file",
|
||||||
|
"arguments": {
|
||||||
|
"file_path": "/path/to/pinned.rs",
|
||||||
|
"namespace": "global"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let _ = handler.handle_request(req).await.unwrap();
|
||||||
|
let pinned = handler.state.pinned_files.read();
|
||||||
|
assert!(pinned.iter().any(|p| p.file_path == "/path/to/pinned.rs"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_unpin_file() {
|
||||||
|
let handler = setup_test_handler("unpin_file");
|
||||||
|
handler.state.pinned_files.modify(|files| {
|
||||||
|
files.push(crate::models::PinnedFile {
|
||||||
|
namespace: "global".to_string(),
|
||||||
|
file_path: "/path/to/unpin.rs".to_string(),
|
||||||
|
timestamp: 0,
|
||||||
|
git_branch: None,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 101,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "unpin_file",
|
||||||
|
"arguments": {
|
||||||
|
"file_path": "/path/to/unpin.rs",
|
||||||
|
"namespace": "global"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let _ = handler.handle_request(req).await.unwrap();
|
||||||
|
let pinned = handler.state.pinned_files.read();
|
||||||
|
assert!(!pinned.iter().any(|p| p.file_path == "/path/to/unpin.rs"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_learn_preference() {
|
||||||
|
let handler = setup_test_handler("learn_preference");
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 102,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "learn_preference",
|
||||||
|
"arguments": {
|
||||||
|
"key": "formatting",
|
||||||
|
"value": "use spaces"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let _ = handler.handle_request(req).await.unwrap();
|
||||||
|
let prefs = handler.state.prefs.read();
|
||||||
|
assert!(prefs.values().any(|p| p.key == "formatting" && p.value == "use spaces"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_read_preferences() {
|
||||||
|
let handler = setup_test_handler("read_preferences");
|
||||||
|
handler.state.prefs.modify(|prefs| {
|
||||||
|
prefs.insert("theme".to_string(), crate::models::Preference {
|
||||||
|
key: "theme".to_string(),
|
||||||
|
value: "dark".to_string(),
|
||||||
|
updated_at: 0,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 103,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "read_preferences",
|
||||||
|
"arguments": {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let response = handler.handle_request(req).await.unwrap();
|
||||||
|
let content = response["result"]["content"][0]["text"].as_str().unwrap();
|
||||||
|
assert!(content.contains("theme"));
|
||||||
|
assert!(content.contains("dark"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_delete_task() {
|
||||||
|
let handler = setup_test_handler("delete_task");
|
||||||
|
handler.state.tasks.modify(|tasks| {
|
||||||
|
tasks.push(crate::models::Task {
|
||||||
|
id: "task-to-delete".to_string(),
|
||||||
|
title: "".to_string(),
|
||||||
|
status: "".to_string(),
|
||||||
|
description: "".to_string(),
|
||||||
|
created_at: 0,
|
||||||
|
updated_at: 0,
|
||||||
|
git_branch: None,
|
||||||
|
acceptance_criteria: vec![],
|
||||||
|
dependencies: vec![],
|
||||||
|
parent_id: None,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 104,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "delete_task",
|
||||||
|
"arguments": {
|
||||||
|
"id": "task-to-delete"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let _ = handler.handle_request(req).await.unwrap();
|
||||||
|
let tasks = handler.state.tasks.read();
|
||||||
|
assert!(tasks.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_add_milestone() {
|
||||||
|
let handler = setup_test_handler("add_milestone");
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 105,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "add_milestone",
|
||||||
|
"arguments": {
|
||||||
|
"title": "v1.0",
|
||||||
|
"namespace": "global"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let _ = handler.handle_request(req).await.unwrap();
|
||||||
|
let milestones = handler.state.milestones.read();
|
||||||
|
assert_eq!(milestones.len(), 1);
|
||||||
|
assert_eq!(milestones[0].title, "v1.0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_update_milestone() {
|
||||||
|
let handler = setup_test_handler("update_milestone");
|
||||||
|
handler.state.milestones.modify(|ms| {
|
||||||
|
ms.push(crate::models::Milestone {
|
||||||
|
id: "v1.0".to_string(),
|
||||||
|
title: "v1.0".to_string(),
|
||||||
|
status: "pending".to_string(),
|
||||||
|
namespace: "".to_string(),
|
||||||
|
target_date: None,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 106,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "update_milestone",
|
||||||
|
"arguments": {
|
||||||
|
"id": "v1.0",
|
||||||
|
"status": "completed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let _ = handler.handle_request(req).await.unwrap();
|
||||||
|
let ms = handler.state.milestones.read();
|
||||||
|
assert_eq!(ms[0].status, "completed");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_list_milestones() {
|
||||||
|
let handler = setup_test_handler("list_milestones");
|
||||||
|
handler.state.milestones.modify(|ms| {
|
||||||
|
ms.push(crate::models::Milestone {
|
||||||
|
id: "v2.0".to_string(),
|
||||||
|
title: "v2.0".to_string(),
|
||||||
|
status: "pending".to_string(),
|
||||||
|
namespace: "".to_string(),
|
||||||
|
target_date: None,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 107,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "list_milestones",
|
||||||
|
"arguments": {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let response = handler.handle_request(req).await.unwrap();
|
||||||
|
let content = response["result"]["content"][0]["text"].as_str().unwrap();
|
||||||
|
assert!(content.contains("v2.0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_add_pr_checklist_item() {
|
||||||
|
let handler = setup_test_handler("add_pr_checklist_item");
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 108,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "add_pr_checklist_item",
|
||||||
|
"arguments": {
|
||||||
|
"description": "Check tests",
|
||||||
|
"namespace": "global"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let _ = handler.handle_request(req).await.unwrap();
|
||||||
|
let cl = handler.state.pr_checklists.read();
|
||||||
|
assert_eq!(cl.len(), 1);
|
||||||
|
assert_eq!(cl[0].description, "Check tests");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_clear_pr_checklist() {
|
||||||
|
let handler = setup_test_handler("clear_pr_checklist");
|
||||||
|
handler.state.pr_checklists.modify(|cl| {
|
||||||
|
cl.push(crate::models::PrChecklistItem {
|
||||||
|
namespace: "global".to_string(),
|
||||||
|
id: "item".to_string(),
|
||||||
|
description: "".to_string(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 109,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "clear_pr_checklist",
|
||||||
|
"arguments": {
|
||||||
|
"namespace": "global"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let _ = handler.handle_request(req).await.unwrap();
|
||||||
|
let cl = handler.state.pr_checklists.read();
|
||||||
|
assert!(cl.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_clear_handoff_memos() {
|
||||||
|
let handler = setup_test_handler("clear_handoff_memos");
|
||||||
|
handler.state.handoff_memos.modify(|ms| {
|
||||||
|
ms.push(crate::models::HandoffMemo {
|
||||||
|
id: "memo".to_string(),
|
||||||
|
namespace: "".to_string(),
|
||||||
|
content: "".to_string(),
|
||||||
|
author: "".to_string(),
|
||||||
|
timestamp: 0,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 110,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "clear_handoff_memos",
|
||||||
|
"arguments": {
|
||||||
|
"ids": ["memo"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let _ = handler.handle_request(req).await.unwrap();
|
||||||
|
let ms = handler.state.handoff_memos.read();
|
||||||
|
assert!(ms.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_clear_sticky_notes() {
|
||||||
|
let handler = setup_test_handler("clear_sticky_notes");
|
||||||
|
handler.state.sticky.modify(|ns| {
|
||||||
|
ns.push(crate::models::StickyNote {
|
||||||
|
content: "".to_string(),
|
||||||
|
timestamp: 0,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 111,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "clear_sticky_notes",
|
||||||
|
"arguments": {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let _ = handler.handle_request(req).await.unwrap();
|
||||||
|
let ns = handler.state.sticky.read();
|
||||||
|
assert!(ns.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_delete_sticky_note() {
|
||||||
|
let handler = setup_test_handler("delete_sticky_note");
|
||||||
|
handler.state.sticky.modify(|ns| {
|
||||||
|
ns.push(crate::models::StickyNote {
|
||||||
|
content: "note1".to_string(),
|
||||||
|
timestamp: 0,
|
||||||
|
});
|
||||||
|
ns.push(crate::models::StickyNote {
|
||||||
|
content: "note2".to_string(),
|
||||||
|
timestamp: 0,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 112,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": "delete_sticky_note",
|
||||||
|
"arguments": {
|
||||||
|
"index": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let _ = handler.handle_request(req).await.unwrap();
|
||||||
|
let ns = handler.state.sticky.read();
|
||||||
|
assert_eq!(ns.len(), 1);
|
||||||
|
assert_eq!(ns[0].content, "note2");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -45,6 +45,14 @@ impl<T: DeserializeOwned + Default + Serialize + Clone + Send + 'static> Store<T
|
|||||||
lock.clone()
|
lock.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn inspect<F, R>(&self, f: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(&T) -> R,
|
||||||
|
{
|
||||||
|
let lock = self.cache.read().unwrap();
|
||||||
|
f(&lock)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn modify<F: FnOnce(&mut T)>(&self, f: F) {
|
pub fn modify<F: FnOnce(&mut T)>(&self, f: F) {
|
||||||
let mut lock = self.cache.write().unwrap();
|
let mut lock = self.cache.write().unwrap();
|
||||||
f(&mut lock);
|
f(&mut lock);
|
||||||
|
|||||||
Reference in new issue
Block a user