#![cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use crate::models::unified_ast::{AstDag, AstKind, FunctionKind, Language, UnifiedAstNode};
use crate::services::dead_code_analyzer::{DeadCodeAnalyzer, ReferenceEdge, ReferenceType};
#[test]
fn verify_entry_point_detection() {
let mut analyzer = DeadCodeAnalyzer::new(1000);
analyzer.add_entry_point(1); analyzer.add_entry_point(2);
let dag = AstDag::new();
let _report = analyzer.analyze(&dag);
}
#[test]
fn verify_cross_language_references() {
let mut analyzer = DeadCodeAnalyzer::new(1000);
let mut dag = AstDag::new();
let node1 = UnifiedAstNode::new(AstKind::Function(FunctionKind::Regular), Language::Rust);
let node2 = UnifiedAstNode::new(
AstKind::Function(FunctionKind::Regular),
Language::TypeScript,
);
dag.add_node(node1);
dag.add_node(node2);
analyzer.add_reference(ReferenceEdge {
from: 1, to: 0, reference_type: ReferenceType::DirectCall,
confidence: 0.95,
});
analyzer.add_entry_point(1);
let report = analyzer.analyze(&dag);
assert_eq!(
report.dead_functions.len(),
0,
"Functions with cross-language references should not be marked as dead"
);
}
#[test]
fn verify_dead_code_detection() {
let mut analyzer = DeadCodeAnalyzer::new(100);
let mut dag = AstDag::new();
for _i in 0..4 {
let node =
UnifiedAstNode::new(AstKind::Function(FunctionKind::Regular), Language::Rust);
dag.add_node(node);
}
analyzer.add_reference(ReferenceEdge {
from: 0,
to: 1,
reference_type: ReferenceType::DirectCall,
confidence: 0.95,
});
analyzer.add_reference(ReferenceEdge {
from: 1,
to: 2,
reference_type: ReferenceType::DirectCall,
confidence: 0.95,
});
analyzer.add_entry_point(0);
let report = analyzer.analyze(&dag);
eprintln!("Total nodes: 4");
eprintln!("Dead functions found: {}", report.dead_functions.len());
eprintln!(
"Dead function keys: {:?}",
report
.dead_functions
.iter()
.map(|f| f.node_key)
.collect::<Vec<_>>()
);
let dead_function_keys: Vec<u32> = report
.dead_functions
.iter()
.map(|item| item.node_key)
.collect();
assert!(
dead_function_keys.contains(&3),
"Unreachable function (node 3) should be marked as dead. Found dead nodes: {dead_function_keys:?}"
);
}
#[test]
fn verify_zero_dead_code_edge_cases() {
let mut analyzer = DeadCodeAnalyzer::new(100);
let mut dag = AstDag::new();
for _ in 0..2 {
let node =
UnifiedAstNode::new(AstKind::Function(FunctionKind::Regular), Language::Rust);
dag.add_node(node);
}
analyzer.add_reference(ReferenceEdge {
from: 0,
to: 1,
reference_type: ReferenceType::DirectCall,
confidence: 0.95,
});
analyzer.add_entry_point(0);
let report = analyzer.analyze(&dag);
assert_eq!(
report.dead_functions.len(),
0,
"Simple project with all functions called should have zero dead code"
);
}
#[test]
fn verify_closure_and_dynamic_dispatch() {
let mut analyzer = DeadCodeAnalyzer::new(100);
let mut dag = AstDag::new();
for _ in 0..3 {
let node =
UnifiedAstNode::new(AstKind::Function(FunctionKind::Regular), Language::Rust);
dag.add_node(node);
}
analyzer.add_reference(ReferenceEdge {
from: 0,
to: 1,
reference_type: ReferenceType::DirectCall,
confidence: 0.95,
});
analyzer.add_reference(ReferenceEdge {
from: 1,
to: 2,
reference_type: ReferenceType::DirectCall,
confidence: 0.95,
});
analyzer.add_entry_point(0);
let report = analyzer.analyze(&dag);
let dead_function_keys: Vec<u32> = report
.dead_functions
.iter()
.map(|item| item.node_key)
.collect();
assert!(
!dead_function_keys.contains(&2),
"Function called from closure should not be marked as dead"
);
}
#[test]
fn test_coverage_integration() {
use crate::services::dead_code_analyzer::CoverageData;
use std::collections::{HashMap, HashSet};
let mut covered_lines = HashMap::new();
let mut lines = HashSet::new();
lines.insert(10);
lines.insert(20);
lines.insert(30);
covered_lines.insert("test.rs".to_string(), lines);
let mut execution_counts = HashMap::new();
let mut counts = HashMap::new();
counts.insert(10, 5);
counts.insert(20, 3);
counts.insert(30, 1);
execution_counts.insert("test.rs".to_string(), counts);
let coverage = CoverageData {
covered_lines,
execution_counts,
};
let mut analyzer = DeadCodeAnalyzer::new(100).with_coverage(coverage);
let dag = AstDag::new();
let _report = analyzer.analyze(&dag);
}
}