use crate::project::index::component_monitor::ComponentIndexingState;
use crate::project::{ProjectScanner, WorkspaceSession};
use crate::test_utils::{DEFAULT_INDEXING_TIMEOUT, integration::TestProject};
use tracing::debug;
#[cfg(feature = "test-logging")]
#[ctor::ctor]
fn init_test_logging() {
crate::test_utils::logging::init();
}
#[tokio::test]
async fn test_indexing_progress_tracking_with_real_clangd() {
let test_project = TestProject::new().await.unwrap();
test_project.cmake_configure().await.unwrap();
let scanner = ProjectScanner::with_default_providers();
let workspace = scanner
.scan_project(&test_project.project_root, 2, None)
.unwrap();
let clangd_path = crate::test_utils::get_test_clangd_path();
let workspace_session = WorkspaceSession::new(workspace, clangd_path).unwrap();
let component_session = workspace_session
.get_component_session(test_project.build_dir.clone())
.await
.unwrap();
let state = component_session.get_index_state().await;
assert_eq!(state.coverage(), 0.0);
let main_cpp_path = test_project.project_root.join("src/main.cpp");
component_session
.ensure_file_ready(&main_cpp_path)
.await
.unwrap();
tokio::time::timeout(DEFAULT_INDEXING_TIMEOUT, async {
component_session
.wait_for_indexing_completion(DEFAULT_INDEXING_TIMEOUT)
.await
})
.await
.expect("Indexing timed out")
.expect("Indexing failed");
let final_state = component_session.get_index_state().await;
let coverage = final_state.coverage();
assert!(
(coverage - 1.0).abs() < 0.001,
"All compilation database files should be indexed, expected coverage = 1.0, got: {}",
coverage
);
}
#[tokio::test]
async fn test_wait_for_indexing_completion_ensures_full_coverage() {
let test_project = TestProject::new().await.unwrap();
test_project.cmake_configure().await.unwrap();
let scanner = ProjectScanner::with_default_providers();
let workspace = scanner
.scan_project(&test_project.project_root, 2, None)
.unwrap();
let clangd_path = crate::test_utils::get_test_clangd_path();
let workspace_session = WorkspaceSession::new(workspace, clangd_path).unwrap();
let _component_session = workspace_session
.get_component_session(test_project.build_dir.clone())
.await
.unwrap();
let component_session = workspace_session
.get_component_session(test_project.build_dir.clone())
.await
.unwrap();
let result = tokio::time::timeout(
DEFAULT_INDEXING_TIMEOUT,
component_session.wait_for_indexing_completion(DEFAULT_INDEXING_TIMEOUT),
)
.await;
match result {
Ok(Ok(())) => {
debug!("wait_for_indexing_completion succeeded");
}
Ok(Err(e)) => {
panic!("wait_for_indexing_completion failed: {}", e);
}
Err(_) => {
panic!("wait_for_indexing_completion timed out after 60s");
}
}
}
#[tokio::test]
async fn test_index_persistence_across_session_restarts() {
const EXPECTED_CDB_FILES: usize = 6;
let test_project = TestProject::new().await.unwrap();
test_project.cmake_configure().await.unwrap();
let scanner = ProjectScanner::with_default_providers();
let workspace = scanner
.scan_project(&test_project.project_root, 2, None)
.unwrap();
let clangd_path = crate::test_utils::get_test_clangd_path();
let workspace_session = WorkspaceSession::new(workspace.clone(), clangd_path.clone()).unwrap();
debug!("Phase 1: Starting initial indexing");
{
let _component_session = workspace_session
.get_component_session(test_project.build_dir.clone())
.await
.unwrap();
tokio::time::timeout(
DEFAULT_INDEXING_TIMEOUT,
_component_session.wait_for_indexing_completion(DEFAULT_INDEXING_TIMEOUT),
)
.await
.expect("Initial indexing timed out")
.expect("Initial indexing failed");
debug!("Phase 1: Initial indexing completed");
let component_state = _component_session.get_index_state().await;
assert_eq!(
component_state.total_cdb_files, EXPECTED_CDB_FILES,
"Test project should have exactly {} CDB files",
EXPECTED_CDB_FILES
);
assert_eq!(
component_state.indexed_cdb_files, EXPECTED_CDB_FILES,
"All {} CDB files should be indexed after completion",
EXPECTED_CDB_FILES
);
assert_eq!(
component_state.state,
ComponentIndexingState::Completed,
"Component should be in Completed state"
);
}
debug!("Phase 2: Cleaning up session and index monitor");
drop(workspace_session);
let workspace_session = WorkspaceSession::new(workspace, clangd_path).unwrap();
debug!("Phase 3: Restarting session and verifying index persistence");
{
let _component_session = workspace_session
.get_component_session(test_project.build_dir.clone())
.await
.unwrap();
tokio::time::timeout(
DEFAULT_INDEXING_TIMEOUT,
_component_session.wait_for_indexing_completion(DEFAULT_INDEXING_TIMEOUT),
)
.await
.expect("Second indexing timed out")
.expect("Second indexing failed");
let component_state = _component_session.get_index_state().await;
debug!("Component state after restart: {:?}", component_state);
assert_eq!(
component_state.state,
ComponentIndexingState::Completed,
"Component should be Completed state from persisted index"
);
assert_eq!(
component_state.total_cdb_files, EXPECTED_CDB_FILES,
"Total CDB files should be detected from disk"
);
assert_eq!(
component_state.indexed_cdb_files, EXPECTED_CDB_FILES,
"All {} CDB files should be detected as indexed from disk",
EXPECTED_CDB_FILES
);
debug!("Phase 3: Index persistence verified - session can read existing index from disk");
}
}
#[tokio::test]
#[cfg(feature = "clangd-integration-tests")]
async fn test_meson_indexing_progress_tracking() {
const EXPECTED_MESON_CDB_FILES: usize = 3;
let test_project = crate::test_utils::integration::TestProject::new_meson()
.await
.unwrap();
test_project.configure().await.unwrap();
let scanner = ProjectScanner::with_default_providers();
let workspace = scanner
.scan_project(&test_project.project_root, 2, None)
.unwrap();
let clangd_path = crate::test_utils::get_test_clangd_path();
let workspace_session = WorkspaceSession::new(workspace, clangd_path).unwrap();
let component_session = workspace_session
.get_component_session(test_project.build_dir.clone())
.await
.unwrap();
let state = component_session.get_index_state().await;
assert_eq!(state.coverage(), 0.0);
let main_cpp_path = test_project.project_root.join("src/main.cpp");
component_session
.ensure_file_ready(&main_cpp_path)
.await
.unwrap();
tokio::time::timeout(DEFAULT_INDEXING_TIMEOUT, async {
component_session
.wait_for_indexing_completion(DEFAULT_INDEXING_TIMEOUT)
.await
})
.await
.expect("Indexing timed out")
.expect("Indexing failed");
let final_state = component_session.get_index_state().await;
let coverage = final_state.coverage();
assert!(
(coverage - 1.0).abs() < 0.001,
"All compilation database files should be indexed, expected coverage = 1.0, got: {}",
coverage
);
assert_eq!(
final_state.total_cdb_files, EXPECTED_MESON_CDB_FILES,
"Meson test project should have exactly {} CDB files",
EXPECTED_MESON_CDB_FILES
);
assert_eq!(
final_state.indexed_cdb_files, EXPECTED_MESON_CDB_FILES,
"All {} CDB files should be indexed after completion",
EXPECTED_MESON_CDB_FILES
);
assert_eq!(
final_state.state,
ComponentIndexingState::Completed,
"Component should be in Completed state"
);
}
#[tokio::test]
#[cfg(feature = "clangd-integration-tests")]
async fn test_meson_index_persistence_across_session_restarts() {
const EXPECTED_MESON_CDB_FILES: usize = 3;
let test_project = crate::test_utils::integration::TestProject::new_meson()
.await
.unwrap();
test_project.configure().await.unwrap();
let scanner = ProjectScanner::with_default_providers();
let workspace = scanner
.scan_project(&test_project.project_root, 2, None)
.unwrap();
let clangd_path = crate::test_utils::get_test_clangd_path();
let workspace_session = WorkspaceSession::new(workspace.clone(), clangd_path.clone()).unwrap();
debug!("Phase 1: Starting initial Meson indexing");
{
let _component_session = workspace_session
.get_component_session(test_project.build_dir.clone())
.await
.unwrap();
tokio::time::timeout(
DEFAULT_INDEXING_TIMEOUT,
_component_session.wait_for_indexing_completion(DEFAULT_INDEXING_TIMEOUT),
)
.await
.expect("Initial Meson indexing timed out")
.expect("Initial Meson indexing failed");
debug!("Phase 1: Initial Meson indexing completed");
let component_state = _component_session.get_index_state().await;
assert_eq!(
component_state.total_cdb_files, EXPECTED_MESON_CDB_FILES,
"Meson test project should have exactly {} CDB files",
EXPECTED_MESON_CDB_FILES
);
assert_eq!(
component_state.indexed_cdb_files, EXPECTED_MESON_CDB_FILES,
"All {} CDB files should be indexed after completion",
EXPECTED_MESON_CDB_FILES
);
assert_eq!(
component_state.state,
ComponentIndexingState::Completed,
"Component should be in Completed state"
);
}
debug!("Phase 2: Cleaning up Meson session and index monitor");
drop(workspace_session);
let workspace_session = WorkspaceSession::new(workspace, clangd_path).unwrap();
debug!("Phase 3: Restarting Meson session and verifying index persistence");
{
let _component_session = workspace_session
.get_component_session(test_project.build_dir.clone())
.await
.unwrap();
tokio::time::timeout(
DEFAULT_INDEXING_TIMEOUT,
_component_session.wait_for_indexing_completion(DEFAULT_INDEXING_TIMEOUT),
)
.await
.expect("Second Meson indexing timed out")
.expect("Second Meson indexing failed");
let component_state = _component_session.get_index_state().await;
debug!("Meson component state after restart: {:?}", component_state);
assert_eq!(
component_state.state,
ComponentIndexingState::Completed,
"Component should be Completed state from persisted index"
);
assert_eq!(
component_state.total_cdb_files, EXPECTED_MESON_CDB_FILES,
"Total CDB files should be detected from disk"
);
assert_eq!(
component_state.indexed_cdb_files, EXPECTED_MESON_CDB_FILES,
"All {} CDB files should be detected as indexed from disk",
EXPECTED_MESON_CDB_FILES
);
debug!(
"Phase 3: Meson index persistence verified - session can read existing index from disk"
);
}
}