/ tests / services_test.rs
services_test.rs
  1  //! Tests for server/services - EnvService, DocumentService, WorkspaceService
  2  
  3  mod common;
  4  
  5  use common::TestFixture;
  6  
  7  // ============================================================
  8  // EnvService Tests
  9  // ============================================================
 10  
 11  #[tokio::test]
 12  async fn test_env_service_get_workspace_root() {
 13      let fixture = TestFixture::new().await;
 14  
 15      // Create EnvService from the core
 16      let env_service = ecolog_lsp::server::services::EnvService::new(fixture.state.core.clone());
 17  
 18      let root = env_service.get_workspace_root().await;
 19      assert!(root.exists(), "Workspace root should exist");
 20  }
 21  
 22  #[tokio::test]
 23  async fn test_env_service_get_for_file() {
 24      let fixture = TestFixture::new().await;
 25  
 26      let env_service = ecolog_lsp::server::services::EnvService::new(fixture.state.core.clone());
 27  
 28      // DB_URL is defined in the fixture's .env
 29      let result = env_service.get_for_file("DB_URL", &fixture.temp_dir).await;
 30  
 31      assert!(result.is_some(), "Should resolve DB_URL");
 32      let var = result.unwrap();
 33      assert_eq!(var.key.as_str(), "DB_URL");
 34  }
 35  
 36  #[tokio::test]
 37  async fn test_env_service_get_for_file_not_found() {
 38      let fixture = TestFixture::new().await;
 39  
 40      let env_service = ecolog_lsp::server::services::EnvService::new(fixture.state.core.clone());
 41  
 42      let result = env_service
 43          .get_for_file("NONEXISTENT_VAR", &fixture.temp_dir)
 44          .await;
 45  
 46      assert!(result.is_none(), "Should return None for nonexistent var");
 47  }
 48  
 49  #[tokio::test]
 50  async fn test_env_service_all_for_file() {
 51      let fixture = TestFixture::new().await;
 52  
 53      let env_service = ecolog_lsp::server::services::EnvService::new(fixture.state.core.clone());
 54  
 55      let vars = env_service.all_for_file(&fixture.temp_dir).await;
 56  
 57      assert!(!vars.is_empty(), "Should return env vars from .env");
 58      // Check that DB_URL is present
 59      let has_db_url = vars.iter().any(|v| v.key.as_str() == "DB_URL");
 60      assert!(has_db_url, "Should contain DB_URL");
 61  }
 62  
 63  #[tokio::test]
 64  async fn test_env_service_set_active_files() {
 65      let fixture = TestFixture::new().await;
 66  
 67      let env_service = ecolog_lsp::server::services::EnvService::new(fixture.state.core.clone());
 68  
 69      // Set active file filter
 70      env_service.set_active_files(&[".env.local".to_string()]);
 71  
 72      // Clear should work
 73      env_service.clear_active_files();
 74  }
 75  
 76  #[tokio::test]
 77  async fn test_env_service_active_env_files() {
 78      let fixture = TestFixture::new().await;
 79  
 80      let env_service = ecolog_lsp::server::services::EnvService::new(fixture.state.core.clone());
 81  
 82      let files = env_service.active_env_files(&fixture.temp_dir);
 83      // Should find at least the .env file
 84      assert!(!files.is_empty(), "Should find .env file");
 85  }
 86  
 87  #[tokio::test]
 88  async fn test_env_service_refresh() {
 89      let fixture = TestFixture::new().await;
 90  
 91      let env_service = ecolog_lsp::server::services::EnvService::new(fixture.state.core.clone());
 92  
 93      // Refresh should not panic
 94      env_service
 95          .refresh(abundantis::RefreshOptions::default())
 96          .await;
 97  }
 98  
 99  #[tokio::test]
100  async fn test_env_service_clone() {
101      let fixture = TestFixture::new().await;
102  
103      let env_service = ecolog_lsp::server::services::EnvService::new(fixture.state.core.clone());
104      let cloned = env_service.clone();
105  
106      // Both should return the same workspace root
107      let root1 = env_service.get_workspace_root().await;
108      let root2 = cloned.get_workspace_root().await;
109      assert_eq!(root1, root2);
110  }
111  
112  #[tokio::test]
113  async fn test_env_service_registered_file_paths() {
114      let fixture = TestFixture::new().await;
115  
116      let env_service = ecolog_lsp::server::services::EnvService::new(fixture.state.core.clone());
117  
118      let paths = env_service.registered_file_paths();
119      // Should have at least the .env file registered
120      assert!(!paths.is_empty(), "Should have registered .env file");
121  }
122  
123  #[tokio::test]
124  async fn test_env_service_context_for_file() {
125      let fixture = TestFixture::new().await;
126  
127      let env_service = ecolog_lsp::server::services::EnvService::new(fixture.state.core.clone());
128  
129      // Create a test file path
130      let test_file = fixture.temp_dir.join("test.js");
131      std::fs::write(&test_file, "const x = 1;").unwrap();
132  
133      let context = env_service.get_context_for_file(&test_file);
134      assert!(
135          context.is_some(),
136          "Should get context for file in workspace"
137      );
138  }
139  
140  // ============================================================
141  // DocumentService Tests
142  // ============================================================
143  
144  #[tokio::test]
145  async fn test_document_service_open_and_get() {
146      let fixture = TestFixture::new().await;
147      let uri = fixture.create_file("test.js", "const x = process.env.DB_URL;");
148  
149      fixture
150          .state
151          .document_manager
152          .open(
153              uri.clone(),
154              "javascript".into(),
155              "const x = process.env.DB_URL;".into(),
156              1,
157          )
158          .await;
159  
160      let doc = fixture.state.document_manager.get(&uri);
161      assert!(doc.is_some(), "Should retrieve opened document");
162  }
163  
164  #[tokio::test]
165  async fn test_document_service_document_exists_after_open() {
166      let fixture = TestFixture::new().await;
167      let uri = fixture.create_file("test.js", "const x = 1;");
168  
169      // Before opening
170      assert!(fixture.state.document_manager.get(&uri).is_none());
171  
172      fixture
173          .state
174          .document_manager
175          .open(uri.clone(), "javascript".into(), "const x = 1;".into(), 1)
176          .await;
177  
178      // After opening
179      assert!(fixture.state.document_manager.get(&uri).is_some());
180  }
181  
182  #[tokio::test]
183  async fn test_document_service_close() {
184      let fixture = TestFixture::new().await;
185      let uri = fixture.create_file("test.js", "const x = 1;");
186  
187      fixture
188          .state
189          .document_manager
190          .open(uri.clone(), "javascript".into(), "const x = 1;".into(), 1)
191          .await;
192  
193      assert!(fixture.state.document_manager.get(&uri).is_some());
194  
195      fixture.state.document_manager.close(&uri);
196  
197      assert!(fixture.state.document_manager.get(&uri).is_none());
198  }
199  
200  #[tokio::test]
201  async fn test_document_service_change() {
202      use tower_lsp::lsp_types::{Position, Range, TextDocumentContentChangeEvent};
203  
204      let fixture = TestFixture::new().await;
205      let uri = fixture.create_file("test.js", "const x = 1;");
206  
207      fixture
208          .state
209          .document_manager
210          .open(uri.clone(), "javascript".into(), "const x = 1;".into(), 1)
211          .await;
212  
213      // Full document replacement via ranged incremental change
214      let changes = vec![TextDocumentContentChangeEvent {
215          range: Some(Range::new(Position::new(0, 0), Position::new(0, 12))),
216          range_length: None,
217          text: "const y = 2;".to_string(),
218      }];
219      fixture
220          .state
221          .document_manager
222          .change(&uri, changes, 2)
223          .await;
224  
225      let doc = fixture.state.document_manager.get(&uri).unwrap();
226      assert_eq!(doc.content.as_str(), "const y = 2;");
227      assert_eq!(doc.version, 2);
228  }
229  
230  #[tokio::test]
231  async fn test_document_service_all_uris() {
232      let fixture = TestFixture::new().await;
233      let uri1 = fixture.create_file("a.js", "const a = 1;");
234      let uri2 = fixture.create_file("b.js", "const b = 2;");
235  
236      fixture
237          .state
238          .document_manager
239          .open(uri1.clone(), "javascript".into(), "const a = 1;".into(), 1)
240          .await;
241      fixture
242          .state
243          .document_manager
244          .open(uri2.clone(), "javascript".into(), "const b = 2;".into(), 1)
245          .await;
246  
247      let uris = fixture.state.document_manager.all_uris();
248      assert_eq!(uris.len(), 2);
249      assert!(uris.contains(&uri1));
250      assert!(uris.contains(&uri2));
251  }
252  
253  #[tokio::test]
254  async fn test_document_service_document_count() {
255      let fixture = TestFixture::new().await;
256      let uri = fixture.create_file("test.js", "const x = 1;");
257  
258      assert_eq!(fixture.state.document_manager.document_count(), 0);
259  
260      fixture
261          .state
262          .document_manager
263          .open(uri.clone(), "javascript".into(), "const x = 1;".into(), 1)
264          .await;
265  
266      assert_eq!(fixture.state.document_manager.document_count(), 1);
267  }
268  
269  // ============================================================
270  // WorkspaceService Tests
271  // ============================================================
272  
273  #[tokio::test]
274  async fn test_workspace_index_stats() {
275      let fixture = TestFixture::new().await;
276      fixture.index_workspace().await;
277  
278      let stats = fixture.state.workspace_index.stats();
279      // Verify stats can be retrieved without panic
280      let _ = stats.total_files;
281  }
282  
283  #[tokio::test]
284  async fn test_workspace_index_files_for_env_var() {
285      let fixture = TestFixture::new().await;
286  
287      // Create a file that references DB_URL
288      fixture.create_file("test.js", "const db = process.env.DB_URL;");
289      fixture.index_workspace().await;
290  
291      let files = fixture.state.workspace_index.files_for_env_var("DB_URL");
292      // May or may not find files depending on indexing
293      // Verify operation doesn't panic
294      let _ = files.len();
295  }
296  
297  #[tokio::test]
298  async fn test_workspace_index_all_env_vars() {
299      let fixture = TestFixture::new().await;
300      fixture.create_file("test.js", "const db = process.env.DB_URL;");
301      fixture.index_workspace().await;
302  
303      let env_vars = fixture.state.workspace_index.all_env_vars();
304      // Should find at least DB_URL from the indexed file
305      // Verify operation doesn't panic
306      let _ = env_vars.len();
307  }