lifecycle_test.rs
1 use crate::harness::{LspTestClient, TempWorkspace}; 2 use serde_json::json; 3 4 #[test] 5 fn test_initialize_response_capabilities() { 6 let workspace = TempWorkspace::new(); 7 let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP"); 8 9 let result = client.initialize().expect("Initialize failed"); 10 11 let capabilities = result.get("capabilities").expect("Missing capabilities"); 12 13 assert!( 14 capabilities.get("hoverProvider").is_some(), 15 "Missing hoverProvider" 16 ); 17 assert!( 18 capabilities.get("completionProvider").is_some(), 19 "Missing completionProvider" 20 ); 21 assert!( 22 capabilities.get("definitionProvider").is_some(), 23 "Missing definitionProvider" 24 ); 25 assert!( 26 capabilities.get("referencesProvider").is_some(), 27 "Missing referencesProvider" 28 ); 29 assert!( 30 capabilities.get("renameProvider").is_some(), 31 "Missing renameProvider" 32 ); 33 34 let rename = capabilities.get("renameProvider").unwrap(); 35 assert_eq!(rename.get("prepareProvider"), Some(&json!(true))); 36 37 let sync = capabilities.get("textDocumentSync").unwrap(); 38 assert_eq!( 39 sync.as_i64(), 40 Some(2), 41 "Expected TextDocumentSyncKind::INCREMENTAL" 42 ); 43 44 let commands = capabilities 45 .get("executeCommandProvider") 46 .expect("Missing executeCommandProvider") 47 .get("commands") 48 .expect("Missing commands") 49 .as_array() 50 .expect("Commands should be array"); 51 52 assert!( 53 commands.iter().any(|c| c == "ecolog.file.setActive"), 54 "Missing ecolog.file.setActive command" 55 ); 56 assert!( 57 commands.iter().any(|c| c == "ecolog.listEnvVariables"), 58 "Missing ecolog.listEnvVariables command" 59 ); 60 61 client.shutdown().expect("Shutdown failed"); 62 } 63 64 #[test] 65 fn test_shutdown_and_exit() { 66 let workspace = TempWorkspace::new(); 67 let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP"); 68 69 client.initialize().expect("Initialize failed"); 70 71 let result = client.request("shutdown", None); 72 assert!(result.is_ok(), "Shutdown request failed"); 73 74 let _ = client.notify("exit", None); 75 76 std::thread::sleep(std::time::Duration::from_millis(100)); 77 } 78 79 #[test] 80 fn test_initialization_trigger_characters() { 81 let workspace = TempWorkspace::new(); 82 let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP"); 83 84 let result = client.initialize().expect("Initialize failed"); 85 86 let capabilities = result.get("capabilities").expect("Missing capabilities"); 87 let completion = capabilities 88 .get("completionProvider") 89 .expect("Missing completionProvider"); 90 let triggers = completion.get("triggerCharacters"); 91 92 assert!(triggers.is_some(), "Should have triggerCharacters"); 93 let triggers = triggers 94 .unwrap() 95 .as_array() 96 .expect("triggerCharacters should be array"); 97 98 assert!( 99 triggers.iter().any(|t| t == "."), 100 "Should include '.' as trigger character" 101 ); 102 103 client.shutdown().expect("Shutdown failed"); 104 } 105 106 #[test] 107 fn test_double_initialize_fails() { 108 let workspace = TempWorkspace::new(); 109 let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP"); 110 111 client.initialize().expect("First initialize failed"); 112 113 let result = client.request( 114 "initialize", 115 Some(json!({ 116 "processId": std::process::id(), 117 "rootUri": format!("file://{}", workspace.root.display()), 118 "capabilities": {} 119 })), 120 ); 121 122 assert!(result.is_err(), "Second initialize should fail"); 123 124 client.shutdown().expect("Shutdown failed"); 125 }