#[cfg(feature = "mcp")]
mod mcp_tests {
use std::path::PathBuf;
use std::time::Duration;
use lspz::daemon::protocol::{DaemonRequest, DaemonResponse};
use lspz::daemon::{DaemonServer, socket_path_for_workspace};
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::net::UnixStream;
#[tokio::test]
async fn test_daemon_session_reuse() {
let test_id = format!("lspz-test-reuse-{}", std::process::id());
let socket_path = PathBuf::from(format!("/tmp/{test_id}.sock"));
let server = DaemonServer::new(socket_path.clone());
let daemon_handle = tokio::spawn(async move {
let _ = server.start().await;
});
tokio::time::sleep(Duration::from_millis(300)).await;
async fn send_spawn(
socket: &PathBuf,
id: u64,
lang: &str,
backend: &str,
) -> DaemonResponse {
let mut stream = UnixStream::connect(socket).await.unwrap();
let req = DaemonRequest {
id,
method: "lsp/spawn".into(),
params: serde_json::json!({
"language": lang,
"backend": backend,
"root_path": "/tmp/lspz-test-workspace",
}),
};
stream
.write_all(format!("{}\n", serde_json::to_string(&req).unwrap()).as_bytes())
.await
.unwrap();
stream.flush().await.unwrap();
let mut buf_reader = BufReader::new(&mut stream);
let mut line = String::new();
tokio::time::timeout(Duration::from_secs(3), buf_reader.read_line(&mut line))
.await
.unwrap()
.unwrap();
serde_json::from_str(line.trim()).unwrap()
}
let resp1 = send_spawn(&socket_path, 1, "rust", "echo").await;
let resp2 = send_spawn(&socket_path, 2, "rust", "echo").await;
assert_eq!(resp1.error, resp2.error);
if resp1.error.is_none() {
assert_eq!(resp1.result["session_key"], resp2.result["session_key"]);
}
daemon_handle.abort();
let _ = std::fs::remove_file(&socket_path);
}
#[test]
fn test_socket_path_deterministic() {
let a = socket_path_for_workspace("/home/user/my-project");
let b = socket_path_for_workspace("/home/user/my-project");
assert_eq!(a, b);
}
#[test]
fn test_socket_path_different_workspaces() {
let a = socket_path_for_workspace("/home/user/project-a");
let b = socket_path_for_workspace("/home/user/project-b");
assert_ne!(a, b);
}
#[tokio::test]
async fn test_daemon_unknown_method() {
let test_id = format!("lspz-test-unknown-{}", std::process::id());
let socket_path = PathBuf::from(format!("/tmp/{test_id}.sock"));
let server = DaemonServer::new(socket_path.clone());
let daemon_handle = tokio::spawn(async move {
let _ = server.start().await;
});
tokio::time::sleep(Duration::from_millis(300)).await;
let mut stream = UnixStream::connect(&socket_path).await.unwrap();
let req = DaemonRequest {
id: 1,
method: "nonexistent/method".into(),
params: serde_json::Value::Null,
};
stream
.write_all(format!("{}\n", serde_json::to_string(&req).unwrap()).as_bytes())
.await
.unwrap();
stream.flush().await.unwrap();
let mut buf_reader = BufReader::new(&mut stream);
let mut line = String::new();
tokio::time::timeout(Duration::from_secs(3), buf_reader.read_line(&mut line))
.await
.unwrap()
.unwrap();
let resp: DaemonResponse = serde_json::from_str(line.trim()).unwrap();
assert!(
resp.error.is_some(),
"Expected error for unknown method, got: {resp:?}"
);
assert!(resp.error.unwrap().contains("Unknown method"));
daemon_handle.abort();
let _ = std::fs::remove_file(&socket_path);
}
}