/ tests / e2e / error_test.rs
error_test.rs
  1  use crate::harness::{LspTestClient, TempWorkspace};
  2  use serde_json::json;
  3  use std::thread;
  4  use std::time::Duration;
  5  
  6  #[test]
  7  fn test_invalid_params() {
  8      let workspace = TempWorkspace::new();
  9      let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP");
 10      client.initialize().expect("Initialize failed");
 11  
 12      let result = client.request(
 13          "textDocument/hover",
 14          Some(json!({
 15              "invalid": "params"
 16          })),
 17      );
 18  
 19      assert!(
 20          result.is_err() || result.as_ref().map(|v| v.is_null()).unwrap_or(false),
 21          "Invalid params should fail gracefully"
 22      );
 23  
 24      client.shutdown().expect("Shutdown failed");
 25  }
 26  
 27  #[test]
 28  fn test_document_not_open() {
 29      let workspace = TempWorkspace::new();
 30      let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP");
 31      client.initialize().expect("Initialize failed");
 32  
 33      let hover = client
 34          .hover("file:///nonexistent.js", 0, 0)
 35          .expect("Request should not fail");
 36  
 37      assert!(
 38          hover.is_null(),
 39          "Hover on unopened document should return null"
 40      );
 41  
 42      client.shutdown().expect("Shutdown failed");
 43  }
 44  
 45  #[test]
 46  fn test_position_out_of_bounds() {
 47      let workspace = TempWorkspace::new();
 48      let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP");
 49      client.initialize().expect("Initialize failed");
 50  
 51      let uri = workspace.file_uri("test.js");
 52      workspace.create_file("test.js", "a");
 53  
 54      client
 55          .open_document(&uri, "javascript", "a")
 56          .expect("Failed to open document");
 57      thread::sleep(Duration::from_millis(200));
 58  
 59      let hover = client
 60          .hover(&uri, 100, 100)
 61          .expect("Request should not fail");
 62  
 63      assert!(hover.is_null(), "Out of bounds position should return null");
 64  
 65      client.shutdown().expect("Shutdown failed");
 66  }
 67  
 68  #[test]
 69  fn test_malformed_uri() {
 70      let workspace = TempWorkspace::new();
 71      let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP");
 72      client.initialize().expect("Initialize failed");
 73  
 74      let result = client.hover("not-a-valid-uri", 0, 0);
 75  
 76      match result {
 77          Ok(hover) => assert!(hover.is_null(), "Malformed URI should return null"),
 78          Err(e) => {
 79              let err_msg = e.to_string();
 80              assert!(
 81                  err_msg.contains("-32602")
 82                      || err_msg.contains("invalid")
 83                      || err_msg.contains("URL"),
 84                  "Should be an invalid params error: {}",
 85                  err_msg
 86              );
 87          }
 88      }
 89  
 90      client.shutdown().expect("Shutdown failed");
 91  }
 92  
 93  #[test]
 94  fn test_empty_document() {
 95      let workspace = TempWorkspace::new();
 96      let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP");
 97      client.initialize().expect("Initialize failed");
 98  
 99      let uri = workspace.file_uri("empty.js");
100      workspace.create_file("empty.js", "");
101  
102      client
103          .open_document(&uri, "javascript", "")
104          .expect("Failed to open document");
105      thread::sleep(Duration::from_millis(200));
106  
107      let hover = client.hover(&uri, 0, 0).expect("Request should not fail");
108      assert!(hover.is_null());
109  
110      let completion = client
111          .completion(&uri, 0, 0)
112          .expect("Request should not fail");
113      assert!(completion.is_null() || completion.as_array().map(|a| a.is_empty()).unwrap_or(false));
114  
115      client.shutdown().expect("Shutdown failed");
116  }
117  
118  #[test]
119  fn test_binary_file_content() {
120      let workspace = TempWorkspace::new();
121      let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP");
122      client.initialize().expect("Initialize failed");
123  
124      let uri = workspace.file_uri("binary.js");
125  
126      workspace.create_file("binary.js", "\0\0\0");
127  
128      client
129          .open_document(&uri, "javascript", "\0\0\0")
130          .expect("Failed to open document");
131      thread::sleep(Duration::from_millis(200));
132  
133      let _hover = client.hover(&uri, 0, 0).expect("Request should not fail");
134  
135      client.shutdown().expect("Shutdown failed");
136  }
137  
138  #[test]
139  fn test_very_long_line() {
140      let workspace = TempWorkspace::new();
141      let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP");
142      client.initialize().expect("Initialize failed");
143  
144      let uri = workspace.file_uri("long.js");
145      let long_line = "a".repeat(100_000);
146      workspace.create_file("long.js", &long_line);
147  
148      client
149          .open_document(&uri, "javascript", &long_line)
150          .expect("Failed to open document");
151      thread::sleep(Duration::from_millis(300));
152  
153      let _hover = client
154          .hover(&uri, 0, 99999)
155          .expect("Request should not fail");
156  
157      client.shutdown().expect("Shutdown failed");
158  }
159  
160  #[test]
161  fn test_rapid_document_changes() {
162      let workspace = TempWorkspace::new();
163      let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP");
164      client.initialize().expect("Initialize failed");
165  
166      let uri = workspace.file_uri("rapid.js");
167      workspace.create_file("rapid.js", "");
168  
169      client
170          .open_document(&uri, "javascript", "")
171          .expect("Failed to open document");
172  
173      for i in 1..=20 {
174          let content = format!("process.env.VAR_{}", i);
175          client
176              .change_document(&uri, i, &content)
177              .expect("Change should not fail");
178      }
179  
180      thread::sleep(Duration::from_millis(500));
181  
182      let _hover = client
183          .hover(&uri, 0, 15)
184          .expect("Hover should work after rapid changes");
185  
186      client.shutdown().expect("Shutdown failed");
187  }
188  
189  #[test]
190  fn test_unicode_in_document() {
191      let workspace = TempWorkspace::new();
192      let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP");
193      client.initialize().expect("Initialize failed");
194  
195      let uri = workspace.file_uri("unicode.js");
196      let content = "// 日本語コメント\nconst api = process.env.API_KEY;";
197      workspace.create_file("unicode.js", content);
198  
199      client
200          .open_document(&uri, "javascript", content)
201          .expect("Failed to open document");
202      thread::sleep(Duration::from_millis(300));
203  
204      let _hover = client.hover(&uri, 1, 15).expect("Request should not fail");
205  
206      client.shutdown().expect("Shutdown failed");
207  }
208  
209  #[test]
210  fn test_deeply_nested_code() {
211      let workspace = TempWorkspace::new();
212      let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP");
213      client.initialize().expect("Initialize failed");
214  
215      let uri = workspace.file_uri("nested.js");
216  
217      let mut content = String::new();
218      for _ in 0..50 {
219          content.push_str("if (true) { ");
220      }
221      content.push_str("process.env.DB_URL");
222      for _ in 0..50 {
223          content.push_str(" }");
224      }
225  
226      workspace.create_file("nested.js", &content);
227      client
228          .open_document(&uri, "javascript", &content)
229          .expect("Failed to open document");
230      thread::sleep(Duration::from_millis(500));
231  
232      let _hover = client.hover(&uri, 0, 600).expect("Request should not fail");
233  
234      client.shutdown().expect("Shutdown failed");
235  }
236  
237  #[test]
238  fn test_command_with_wrong_arg_types() {
239      let workspace = TempWorkspace::new();
240      let client = LspTestClient::spawn(workspace.root.clone()).expect("Failed to spawn LSP");
241      client.initialize().expect("Initialize failed");
242  
243      let result = client.execute_command("ecolog.file.setActive", vec![json!(12345)]);
244  
245      assert!(
246          result.is_ok(),
247          "Command should not crash with wrong arg types"
248      );
249  
250      client.shutdown().expect("Shutdown failed");
251  }