use coderlib::core::{CoderLib, CoderLibConfig};
use coderlib::lsp::{LspConfig, LspServerConfig};
use std::collections::HashMap;
use std::path::PathBuf;
use tempfile::TempDir;
use tokio;
#[tokio::test]
async fn test_lsp_integration_basic() {
let temp_dir = TempDir::new().unwrap();
let test_file = temp_dir.path().join("test.rs");
std::fs::write(&test_file, r#"
fn main() {
let unused_variable = 42;
println!("Hello, world!");
}
"#).unwrap();
let mut lsp_config = LspConfig::default();
lsp_config.enabled = false;
let mut config = CoderLibConfig::default();
config.lsp = lsp_config;
let coderlib = CoderLib::new(config).await.unwrap();
let supports_rust = coderlib.lsp_supports_file(&test_file);
println!("LSP supports Rust file: {}", supports_rust);
let diagnostics = coderlib.get_diagnostics(&test_file).await.unwrap();
assert!(diagnostics.is_empty(), "Should have no diagnostics when LSP is disabled");
let content = std::fs::read_to_string(&test_file).unwrap();
assert!(coderlib.lsp_did_open(&test_file, &content).await.is_ok());
assert!(coderlib.lsp_did_change(&test_file, &content).await.is_ok());
assert!(coderlib.lsp_did_close(&test_file).await.is_ok());
let active_servers = coderlib.lsp_active_servers().await;
assert!(active_servers.is_empty(), "Should have no active servers when LSP is disabled");
}
#[tokio::test]
async fn test_lsp_config_creation() {
let config = LspConfig::default();
assert!(config.servers.contains_key("rust"));
assert!(config.servers.contains_key("go"));
let rust_config = &config.servers["rust"];
assert_eq!(rust_config.command, "rust-analyzer");
assert!(rust_config.enabled);
assert!(rust_config.auto_start);
assert!(rust_config.handles_file(&PathBuf::from("main.rs")));
assert!(rust_config.handles_file(&PathBuf::from("lib.rs")));
assert!(!rust_config.handles_file(&PathBuf::from("main.go")));
}
#[tokio::test]
async fn test_lsp_server_config() {
let mut servers = HashMap::new();
servers.insert("test".to_string(), LspServerConfig {
name: "Test Server".to_string(),
command: "test-lsp".to_string(),
args: vec!["--stdio".to_string()],
env: HashMap::new(),
file_patterns: vec!["*.test".to_string()],
enabled: true,
auto_start: false,
settings: serde_json::json!({"test": true}),
});
let lsp_config = LspConfig {
enabled: true,
timeout: std::time::Duration::from_secs(10),
max_servers: 3,
servers,
};
let mut config = CoderLibConfig::default();
config.lsp = lsp_config;
let coderlib = CoderLib::new(config).await.unwrap();
assert!(coderlib.lsp_supports_file(&PathBuf::from("example.test")));
assert!(!coderlib.lsp_supports_file(&PathBuf::from("example.rs")));
}
#[tokio::test]
async fn test_diagnostics_tool() {
use coderlib::tools::{Tool, DiagnosticsTool};
use coderlib::integration::HostIntegration;
use serde_json::json;
struct MockHost;
#[async_trait::async_trait]
impl HostIntegration for MockHost {
async fn send_message(&self, _message: String) -> Result<(), coderlib::integration::IntegrationError> {
Ok(())
}
async fn get_current_file(&self) -> Result<Option<std::path::PathBuf>, coderlib::integration::IntegrationError> {
Ok(None)
}
async fn get_file_content(&self, _path: &std::path::Path) -> Result<String, coderlib::integration::IntegrationError> {
Ok(String::new())
}
async fn set_file_content(&self, _path: &std::path::Path, _content: &str) -> Result<(), coderlib::integration::IntegrationError> {
Ok(())
}
async fn show_notification(&self, _message: String, _level: coderlib::integration::MessageLevel) -> Result<(), coderlib::integration::IntegrationError> {
Ok(())
}
async fn get_workspace_root(&self) -> Result<Option<std::path::PathBuf>, coderlib::integration::IntegrationError> {
Ok(None)
}
async fn list_files(&self, _pattern: Option<String>) -> Result<Vec<std::path::PathBuf>, coderlib::integration::IntegrationError> {
Ok(Vec::new())
}
fn get_capabilities(&self) -> coderlib::integration::HostCapabilities {
coderlib::integration::HostCapabilities {
can_edit_files: true,
can_execute_commands: false,
can_show_notifications: true,
supports_streaming: false,
}
}
}
let tool = DiagnosticsTool::new();
let host = MockHost;
assert_eq!(tool.name(), "diagnostics");
assert!(!tool.description().is_empty());
let schema = tool.parameter_schema();
assert!(schema.get("properties").is_some());
assert!(schema.get("required").is_some());
let invalid_params = json!({});
let result = tool.execute(invalid_params, &host).await;
assert!(result.is_err());
let valid_params = json!({
"file_path": "test.rs"
});
let result = tool.execute(valid_params, &host).await;
assert!(result.is_ok());
let response = result.unwrap();
assert!(response.content.contains("LSP service not available"));
}
#[test]
fn test_lsp_language_detection() {
use coderlib::lsp::LspServerConfig;
let config = LspServerConfig::default();
assert_eq!(config.get_language_id(&PathBuf::from("main.rs")), Some("rust".to_string()));
assert_eq!(config.get_language_id(&PathBuf::from("main.go")), Some("go".to_string()));
assert_eq!(config.get_language_id(&PathBuf::from("script.py")), Some("python".to_string()));
assert_eq!(config.get_language_id(&PathBuf::from("app.js")), Some("javascript".to_string()));
assert_eq!(config.get_language_id(&PathBuf::from("app.ts")), Some("typescript".to_string()));
assert_eq!(config.get_language_id(&PathBuf::from("unknown.xyz")), None);
}