hover_test.rs
1 use crate::harness::{LspTestClient, TempWorkspace}; 2 use std::thread; 3 use std::time::Duration; 4 5 #[test] 6 fn test_hover_direct_env_reference_js() { 7 let workspace = TempWorkspace::new(); 8 let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP"); 9 client.initialize().expect("Initialize failed"); 10 11 let uri = workspace.file_uri("test.js"); 12 let content = "const url = process.env.DB_URL;"; 13 workspace.create_file("test.js", content); 14 15 client 16 .open_document(&uri, "javascript", content) 17 .expect("Failed to open document"); 18 19 thread::sleep(Duration::from_millis(300)); 20 21 let hover = client.hover(&uri, 0, 24).expect("Hover request failed"); 22 23 assert!(!hover.is_null(), "Expected hover result for DB_URL"); 24 25 let contents = hover.get("contents").expect("Missing contents"); 26 let value = contents 27 .get("value") 28 .expect("Missing value") 29 .as_str() 30 .expect("Value not string"); 31 32 assert!( 33 value.contains("DB_URL"), 34 "Hover should contain variable name" 35 ); 36 assert!(value.contains("postgres://")); 37 38 client.shutdown().expect("Shutdown failed"); 39 } 40 41 #[test] 42 fn test_hover_bracket_notation_js() { 43 let workspace = TempWorkspace::new(); 44 let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP"); 45 client.initialize().expect("Initialize failed"); 46 47 let uri = workspace.file_uri("test.js"); 48 let content = "const key = process.env['API_KEY'];"; 49 workspace.create_file("test.js", content); 50 51 client 52 .open_document(&uri, "javascript", content) 53 .expect("Failed to open document"); 54 thread::sleep(Duration::from_millis(300)); 55 56 let hover = client.hover(&uri, 0, 26).expect("Hover request failed"); 57 58 assert!(!hover.is_null(), "Expected hover result for API_KEY"); 59 60 let contents = hover.get("contents").expect("Missing contents"); 61 let value = contents 62 .get("value") 63 .expect("Missing value") 64 .as_str() 65 .expect("Value not string"); 66 67 assert!( 68 value.contains("secret_key"), 69 "Hover should contain API_KEY value" 70 ); 71 72 client.shutdown().expect("Shutdown failed"); 73 } 74 75 #[test] 76 fn test_hover_destructuring() { 77 let workspace = TempWorkspace::new(); 78 let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP"); 79 client.initialize().expect("Initialize failed"); 80 81 let uri = workspace.file_uri("test.js"); 82 let content = "const { PORT } = process.env;"; 83 workspace.create_file("test.js", content); 84 85 client 86 .open_document(&uri, "javascript", content) 87 .expect("Failed to open document"); 88 thread::sleep(Duration::from_millis(300)); 89 90 let hover = client.hover(&uri, 0, 8).expect("Hover request failed"); 91 92 assert!(!hover.is_null(), "Expected hover result for PORT"); 93 94 let contents = hover.get("contents").expect("Missing contents"); 95 let value = contents 96 .get("value") 97 .expect("Missing value") 98 .as_str() 99 .expect("Value not string"); 100 101 assert!(value.contains("8080"), "Hover should contain PORT value"); 102 103 client.shutdown().expect("Shutdown failed"); 104 } 105 106 #[test] 107 fn test_hover_object_alias_chain() { 108 let workspace = TempWorkspace::new(); 109 let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP"); 110 client.initialize().expect("Initialize failed"); 111 112 let uri = workspace.file_uri("test.js"); 113 let content = "const e = process.env; const port = e.PORT;"; 114 workspace.create_file("test.js", content); 115 116 client 117 .open_document(&uri, "javascript", content) 118 .expect("Failed to open document"); 119 thread::sleep(Duration::from_millis(300)); 120 121 let hover = client.hover(&uri, 0, 40).expect("Hover request failed"); 122 123 assert!(!hover.is_null(), "Expected hover result for PORT via alias"); 124 125 let contents = hover.get("contents").expect("Missing contents"); 126 let value = contents 127 .get("value") 128 .expect("Missing value") 129 .as_str() 130 .expect("Value not string"); 131 132 assert!(value.contains("8080"), "Hover should contain PORT value"); 133 134 client.shutdown().expect("Shutdown failed"); 135 } 136 137 #[test] 138 fn test_hover_undefined_returns_null() { 139 let workspace = TempWorkspace::new(); 140 let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP"); 141 client.initialize().expect("Initialize failed"); 142 143 let uri = workspace.file_uri("test.js"); 144 let content = "process.env.UNDEFINED_VAR"; 145 workspace.create_file("test.js", content); 146 147 client 148 .open_document(&uri, "javascript", content) 149 .expect("Failed to open document"); 150 thread::sleep(Duration::from_millis(300)); 151 152 let hover = client.hover(&uri, 0, 15).expect("Hover request failed"); 153 154 assert!(hover.is_null(), "Undefined vars should return null hover"); 155 156 client.shutdown().expect("Shutdown failed"); 157 } 158 159 #[test] 160 fn test_hover_python() { 161 let workspace = TempWorkspace::new(); 162 let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP"); 163 client.initialize().expect("Initialize failed"); 164 165 let uri = workspace.file_uri("test.py"); 166 let content = "import os\ndb = os.environ['DB_URL']"; 167 workspace.create_file("test.py", content); 168 169 client 170 .open_document(&uri, "python", content) 171 .expect("Failed to open document"); 172 thread::sleep(Duration::from_millis(300)); 173 174 let hover = client.hover(&uri, 1, 18).expect("Hover request failed"); 175 176 assert!(!hover.is_null(), "Expected hover result for Python"); 177 178 client.shutdown().expect("Shutdown failed"); 179 } 180 181 #[test] 182 fn test_hover_rust() { 183 let workspace = TempWorkspace::new(); 184 let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP"); 185 client.initialize().expect("Initialize failed"); 186 187 let uri = workspace.file_uri("test.rs"); 188 let content = r#"fn main() { std::env::var("PORT"); }"#; 189 workspace.create_file("test.rs", content); 190 191 client 192 .open_document(&uri, "rust", content) 193 .expect("Failed to open document"); 194 thread::sleep(Duration::from_millis(300)); 195 196 let hover = client.hover(&uri, 0, 28).expect("Hover request failed"); 197 198 assert!(!hover.is_null(), "Expected hover result for Rust"); 199 200 client.shutdown().expect("Shutdown failed"); 201 } 202 203 #[test] 204 fn test_hover_go() { 205 let workspace = TempWorkspace::new(); 206 let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP"); 207 client.initialize().expect("Initialize failed"); 208 209 let uri = workspace.file_uri("test.go"); 210 let content = r#"package main 211 import "os" 212 func main() { os.Getenv("DEBUG") }"#; 213 workspace.create_file("test.go", content); 214 215 client 216 .open_document(&uri, "go", content) 217 .expect("Failed to open document"); 218 thread::sleep(Duration::from_millis(300)); 219 220 let hover = client.hover(&uri, 2, 26).expect("Hover request failed"); 221 222 assert!(!hover.is_null(), "Expected hover result for Go"); 223 224 client.shutdown().expect("Shutdown failed"); 225 } 226 227 #[test] 228 fn test_hover_typescript() { 229 let workspace = TempWorkspace::new(); 230 let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP"); 231 client.initialize().expect("Initialize failed"); 232 233 let uri = workspace.file_uri("test.ts"); 234 let content = "const apiKey: string = process.env.API_KEY!;"; 235 workspace.create_file("test.ts", content); 236 237 client 238 .open_document(&uri, "typescript", content) 239 .expect("Failed to open document"); 240 thread::sleep(Duration::from_millis(300)); 241 242 let hover = client.hover(&uri, 0, 38).expect("Hover request failed"); 243 244 assert!(!hover.is_null(), "Expected hover result for TypeScript"); 245 246 client.shutdown().expect("Shutdown failed"); 247 }