#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use crate::graph::{ContextAnnotation, GraphContextAnnotator};
use anyhow::Result;
use std::path::PathBuf;
use tempfile::TempDir;
#[tokio::test]
async fn test_context_command_uses_graph_annotator() -> Result<()> {
let temp_dir = create_test_workspace().await?;
let project_path = temp_dir.path().to_path_buf();
let output_path = temp_dir.path().join("deep_context.md");
let result = execute_context_command_with_graph(
project_path,
Some(output_path.clone()),
true, )
.await;
assert!(
result.is_ok(),
"Context command should succeed with graph analysis"
);
assert!(output_path.exists(), "Output file should be created");
let content = std::fs::read_to_string(&output_path)?;
assert!(
content.contains("# Graph Context Analysis"),
"Should contain graph analysis header"
);
assert!(
content.contains("## File Importance Rankings"),
"Should contain PageRank rankings"
);
assert!(
content.contains("## Community Clusters"),
"Should contain community detection results"
);
Ok(())
}
#[tokio::test]
async fn test_deep_context_includes_graph_annotations() -> Result<()> {
let temp_dir = create_complex_test_workspace().await?;
let output_path = temp_dir.path().join("deep_context.md");
let result = execute_deep_context_command(
temp_dir.path().to_path_buf(),
Some(output_path.clone()),
true, )
.await;
assert!(result.is_ok(), "Deep context command should succeed");
let content = std::fs::read_to_string(&output_path)?;
assert!(
content.contains("## Dependency Graph Analysis"),
"Should include dependency analysis"
);
assert!(
content.contains("PageRank Score:"),
"Should include PageRank scores"
);
assert!(
content.contains("Community ID:"),
"Should include community assignments"
);
assert!(
content.contains("Related Files:"),
"Should include related file suggestions"
);
Ok(())
}
#[tokio::test]
async fn test_graph_annotation_complexity_classification() -> Result<()> {
let temp_dir = create_complexity_test_workspace().await?;
let annotations = generate_graph_annotations(temp_dir.path()).await?;
assert!(!annotations.is_empty(), "Should generate annotations");
for annotation in &annotations {
assert!(
["Low", "Medium", "High", "Very High"]
.contains(&annotation.complexity_rank.as_str()),
"Complexity rank should be valid: {}",
annotation.complexity_rank
);
}
Ok(())
}
#[tokio::test]
#[ignore = "PageRank hub-spoke scoring needs investigation after trueno-graph migration"]
async fn test_pagerank_identifies_central_files() -> Result<()> {
let temp_dir = create_hub_and_spoke_workspace().await?;
let annotations = generate_graph_annotations(temp_dir.path()).await?;
let hub_annotation = annotations
.iter()
.find(|a| a.file_path.contains("hub.rs"))
.expect("Hub file should be found");
let max_score = annotations
.iter()
.map(|a| a.importance_score)
.fold(0.0, f64::max);
assert_eq!(
hub_annotation.importance_score, max_score,
"Hub file should have highest PageRank score"
);
Ok(())
}
#[tokio::test]
async fn test_community_detection_groups_related_files() -> Result<()> {
let temp_dir = create_modular_test_workspace().await?;
let annotations = generate_graph_annotations(temp_dir.path()).await?;
let annotator = GraphContextAnnotator::new();
let _clusters = annotator.get_community_clusters(&annotations);
let module_a_files: Vec<_> = annotations
.iter()
.filter(|a| a.file_path.contains("module_a"))
.collect();
if !module_a_files.is_empty() {
assert!(
module_a_files.iter().all(|f| f.community_id < usize::MAX),
"Module A files should have valid community IDs"
);
}
Ok(())
}
#[tokio::test]
async fn test_graph_integration_quality_standards() -> Result<()> {
let temp_dir = create_test_workspace().await?;
let result =
execute_context_command_with_graph(temp_dir.path().to_path_buf(), None, true).await;
assert!(result.is_ok(), "Should maintain error handling standards");
let error_result =
execute_context_command_with_graph(PathBuf::from("/nonexistent/path"), None, true)
.await;
assert!(
error_result.is_err(),
"Should properly handle invalid paths"
);
Ok(())
}
async fn create_test_workspace() -> Result<TempDir> {
let temp_dir = tempfile::tempdir()?;
std::fs::write(
temp_dir.path().join("main.rs"),
"use utils::helper;\nfn main() { helper(); }",
)?;
std::fs::write(
temp_dir.path().join("utils.rs"),
"pub fn helper() { println!(\"Hello\"); }",
)?;
Ok(temp_dir)
}
async fn create_complex_test_workspace() -> Result<TempDir> {
let temp_dir = tempfile::tempdir()?;
std::fs::create_dir_all(temp_dir.path().join("src"))?;
std::fs::create_dir_all(temp_dir.path().join("src/modules"))?;
std::fs::write(
temp_dir.path().join("src/main.rs"),
"use crate::modules::{auth, db};\nfn main() { auth::login(); db::connect(); }",
)?;
std::fs::write(
temp_dir.path().join("src/modules/auth.rs"),
"use super::db;\npub fn login() { db::validate_user(); }",
)?;
std::fs::write(
temp_dir.path().join("src/modules/db.rs"),
"pub fn connect() {}\npub fn validate_user() {}",
)?;
Ok(temp_dir)
}
async fn create_complexity_test_workspace() -> Result<TempDir> {
let temp_dir = tempfile::tempdir()?;
std::fs::write(
temp_dir.path().join("simple.rs"),
"pub fn add(a: i32, b: i32) -> i32 { a + b }",
)?;
let complex_code = r#"
/// Complex function.
pub fn complex_function(data: &[i32]) -> Vec<i32> {
let mut result = Vec::new();
for i in 0..data.len() {
if data[i] > 0 {
for j in 0..data[i] {
if j % 2 == 0 {
if j > 5 {
result.push(j * 2);
} else {
result.push(j);
}
} else {
result.push(j + 1);
}
}
}
}
result
}
"#;
std::fs::write(temp_dir.path().join("complex.rs"), complex_code)?;
Ok(temp_dir)
}
async fn create_hub_and_spoke_workspace() -> Result<TempDir> {
let temp_dir = tempfile::tempdir()?;
std::fs::write(
temp_dir.path().join("hub.rs"),
"pub fn core_function() {}\npub struct CoreStruct;",
)?;
for i in 1..=5 {
std::fs::write(
temp_dir.path().join(format!("spoke_{}.rs", i)),
format!("use crate::hub::{{core_function, CoreStruct}};\npub fn func_{}() {{ core_function(); }}", i)
)?;
}
Ok(temp_dir)
}
async fn create_modular_test_workspace() -> Result<TempDir> {
let temp_dir = tempfile::tempdir()?;
std::fs::create_dir_all(temp_dir.path().join("module_a"))?;
std::fs::create_dir_all(temp_dir.path().join("module_b"))?;
std::fs::write(
temp_dir.path().join("module_a/core.rs"),
"use super::utils;\npub fn process() { utils::helper(); }",
)?;
std::fs::write(
temp_dir.path().join("module_a/utils.rs"),
"pub fn helper() {}",
)?;
std::fs::write(
temp_dir.path().join("module_b/service.rs"),
"use super::client;\npub fn serve() { client::connect(); }",
)?;
std::fs::write(
temp_dir.path().join("module_b/client.rs"),
"pub fn connect() {}",
)?;
std::fs::write(
temp_dir.path().join("main.rs"),
"mod module_a;\nmod module_b;\nfn main() { module_a::core::process(); module_b::service::serve(); }"
)?;
Ok(temp_dir)
}
async fn execute_context_command_with_graph(
project_path: PathBuf,
output: Option<PathBuf>,
enable_graph: bool,
) -> Result<()> {
use crate::graph::{DependencyGraphBuilder, GraphContextAnnotator};
if !project_path.exists() {
return Err(anyhow::anyhow!("Project path does not exist"));
}
if enable_graph {
let builder = DependencyGraphBuilder::from_workspace(&project_path)?;
let graph = builder.build()?;
let annotator = GraphContextAnnotator::new();
let annotations = annotator.annotate_context(&graph);
let content = generate_context_markdown(&annotations);
if let Some(output_path) = output {
std::fs::write(&output_path, content)?;
}
}
Ok(())
}
async fn execute_deep_context_command(
project_path: PathBuf,
output: Option<PathBuf>,
full: bool,
) -> Result<()> {
use crate::graph::{DependencyGraphBuilder, GraphContextAnnotator};
if !project_path.exists() {
return Err(anyhow::anyhow!("Project path does not exist"));
}
let builder = DependencyGraphBuilder::from_workspace(&project_path)?;
let graph = builder.build()?;
let annotator = GraphContextAnnotator::new();
let annotations = annotator.annotate_context(&graph);
let content = generate_deep_context_markdown(&annotations, full);
if let Some(output_path) = output {
std::fs::write(&output_path, content)?;
}
Ok(())
}
async fn generate_graph_annotations(
workspace_path: &std::path::Path,
) -> Result<Vec<ContextAnnotation>> {
use crate::graph::{DependencyGraphBuilder, GraphContextAnnotator};
let builder = DependencyGraphBuilder::from_workspace(workspace_path)?;
let graph = builder.build()?;
let annotator = GraphContextAnnotator::new();
let annotations = annotator.annotate_context(&graph);
Ok(annotations)
}
fn generate_context_markdown(annotations: &[ContextAnnotation]) -> String {
let mut content = String::new();
content.push_str("# Graph Context Analysis\n\n");
content.push_str("## File Importance Rankings\n\n");
for annotation in annotations.iter().take(10) {
content.push_str(&format!(
"- {} (PageRank: {:.3})\n",
annotation.file_path, annotation.importance_score
));
}
content.push_str("\n## Community Clusters\n\n");
content.push_str("Files grouped by dependency communities...\n");
content
}
fn generate_deep_context_markdown(annotations: &[ContextAnnotation], full: bool) -> String {
let mut content = String::new();
content.push_str("# Deep Context Analysis\n\n");
content.push_str("## Dependency Graph Analysis\n\n");
for annotation in annotations {
content.push_str(&format!("### {}\n\n", annotation.file_path));
content.push_str(&format!(
"- PageRank Score: {:.3}\n",
annotation.importance_score
));
content.push_str(&format!("- Community ID: {}\n", annotation.community_id));
content.push_str(&format!("- Complexity: {}\n", annotation.complexity_rank));
if full {
content.push_str("- Related Files:\n");
for related in &annotation.related_files {
content.push_str(&format!(" - {}\n", related));
}
}
content.push('\n');
}
content
}
}