#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod coverage_tests {
use super::*;
use std::path::PathBuf;
#[test]
fn test_rust_strategy_new() {
let strategy = RustStrategy::new();
assert_eq!(strategy.language(), Language::Rust);
}
#[test]
fn test_rust_strategy_default() {
let strategy = RustStrategy::default();
assert_eq!(strategy.language(), Language::Rust);
}
#[test]
fn test_can_parse_rs_file() {
let strategy = RustStrategy::new();
assert!(strategy.can_parse(Path::new("test.rs")));
assert!(strategy.can_parse(Path::new("/path/to/module.rs")));
assert!(strategy.can_parse(Path::new("lib.rs")));
}
#[test]
fn test_can_parse_non_rust_files() {
let strategy = RustStrategy::new();
assert!(!strategy.can_parse(Path::new("test.py")));
assert!(!strategy.can_parse(Path::new("test.ts")));
assert!(!strategy.can_parse(Path::new("test.js")));
assert!(!strategy.can_parse(Path::new("test.c")));
assert!(!strategy.can_parse(Path::new("test")));
assert!(!strategy.can_parse(Path::new("")));
}
#[test]
fn test_can_parse_no_extension() {
let strategy = RustStrategy::new();
assert!(!strategy.can_parse(Path::new("Makefile")));
assert!(!strategy.can_parse(Path::new("README")));
}
#[test]
fn test_parse_syn_file_simple_function() {
let strategy = RustStrategy::new();
let code = "fn main() {}";
let result = strategy.parse_syn_file(code);
assert!(result.is_ok());
}
#[test]
fn test_parse_syn_file_async_function() {
let strategy = RustStrategy::new();
let code = "async fn async_main() {}";
let result = strategy.parse_syn_file(code);
assert!(result.is_ok());
}
#[test]
fn test_parse_syn_file_struct() {
let strategy = RustStrategy::new();
let code = "struct MyStruct { field: i32 }";
let result = strategy.parse_syn_file(code);
assert!(result.is_ok());
}
#[test]
fn test_parse_syn_file_enum() {
let strategy = RustStrategy::new();
let code = "enum Color { Red, Green, Blue }";
let result = strategy.parse_syn_file(code);
assert!(result.is_ok());
}
#[test]
fn test_parse_syn_file_trait() {
let strategy = RustStrategy::new();
let code = "trait Printable { fn print(&self); }";
let result = strategy.parse_syn_file(code);
assert!(result.is_ok());
}
#[test]
fn test_parse_syn_file_impl() {
let strategy = RustStrategy::new();
let code = r#"
struct Foo;
impl Foo {
fn new() -> Self { Foo }
}
"#;
let result = strategy.parse_syn_file(code);
assert!(result.is_ok());
}
#[test]
fn test_parse_syn_file_invalid_syntax() {
let strategy = RustStrategy::new();
let code = "fn main( { }"; let result = strategy.parse_syn_file(code);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Rust parse error"));
}
#[test]
fn test_convert_to_dag_function() {
let strategy = RustStrategy::new();
let code = "fn main() {}";
let syn_file = strategy.parse_syn_file(code).unwrap();
let dag = strategy.convert_to_dag(&syn_file);
assert!(!dag.nodes.is_empty());
}
#[test]
fn test_convert_to_dag_async_function() {
let strategy = RustStrategy::new();
let code = "async fn fetch_data() {}";
let syn_file = strategy.parse_syn_file(code).unwrap();
let dag = strategy.convert_to_dag(&syn_file);
assert!(!dag.nodes.is_empty());
let has_async = dag.nodes.iter().any(|node| {
matches!(node.kind, AstKind::Function(_)) && node.flags.has(NodeFlags::ASYNC)
});
assert!(has_async, "Should have an async function node");
}
#[test]
fn test_convert_to_dag_struct() {
let strategy = RustStrategy::new();
let code = "struct Point { x: i32, y: i32 }";
let syn_file = strategy.parse_syn_file(code).unwrap();
let dag = strategy.convert_to_dag(&syn_file);
let has_struct = dag
.nodes
.iter()
.any(|node| matches!(node.kind, AstKind::Class(ClassKind::Struct)));
assert!(has_struct, "Should have a struct node");
}
#[test]
fn test_convert_to_dag_enum() {
let strategy = RustStrategy::new();
let code = "enum Direction { Up, Down, Left, Right }";
let syn_file = strategy.parse_syn_file(code).unwrap();
let dag = strategy.convert_to_dag(&syn_file);
let has_enum = dag
.nodes
.iter()
.any(|node| matches!(node.kind, AstKind::Class(ClassKind::Enum)));
assert!(has_enum, "Should have an enum node");
}
#[test]
fn test_convert_to_dag_trait() {
let strategy = RustStrategy::new();
let code = "trait Drawable { fn draw(&self); }";
let syn_file = strategy.parse_syn_file(code).unwrap();
let dag = strategy.convert_to_dag(&syn_file);
let has_trait = dag
.nodes
.iter()
.any(|node| matches!(node.kind, AstKind::Class(ClassKind::Trait)));
assert!(has_trait, "Should have a trait node");
}
#[test]
fn test_convert_to_dag_impl_block() {
let strategy = RustStrategy::new();
let code = r#"
struct Counter;
impl Counter {
fn increment(&mut self) {}
}
"#;
let syn_file = strategy.parse_syn_file(code).unwrap();
let dag = strategy.convert_to_dag(&syn_file);
let node_count = dag.nodes.len();
assert!(node_count >= 2, "Should have multiple nodes");
}
#[tokio::test]
async fn test_parse_file_success() {
let strategy = RustStrategy::new();
let path = PathBuf::from("test.rs");
let code = "fn hello() { println!(\"Hello!\"); }";
let result = strategy.parse_file(&path, code).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_parse_file_error() {
let strategy = RustStrategy::new();
let path = PathBuf::from("test.rs");
let code = "fn invalid syntax {";
let result = strategy.parse_file(&path, code).await;
assert!(result.is_err());
}
#[test]
fn test_extract_imports_empty() {
let strategy = RustStrategy::new();
let dag = AstDag::new();
let imports = strategy.extract_imports(&dag);
assert!(imports.is_empty());
}
#[test]
fn test_extract_imports_with_import_flag() {
let strategy = RustStrategy::new();
let mut dag = AstDag::new();
let mut node = UnifiedAstNode::new(
AstKind::Import(crate::ast::core::ImportKind::Module),
Language::Rust,
);
node.flags.set(NodeFlags::IMPORT);
dag.add_node(node);
let imports = strategy.extract_imports(&dag);
assert_eq!(imports.len(), 1);
assert!(imports[0].starts_with("import_"));
}
#[tokio::test]
async fn test_extract_functions() {
let strategy = RustStrategy::new();
let path = PathBuf::from("test.rs");
let code = r#"
fn foo() {}
fn bar() {}
async fn baz() {}
"#;
let dag = strategy.parse_file(&path, code).await.unwrap();
let functions = strategy.extract_functions(&dag);
assert_eq!(functions.len(), 3);
}
#[test]
fn test_extract_functions_empty_dag() {
let strategy = RustStrategy::new();
let dag = AstDag::new();
let functions = strategy.extract_functions(&dag);
assert!(functions.is_empty());
}
#[tokio::test]
async fn test_extract_types() {
let strategy = RustStrategy::new();
let path = PathBuf::from("test.rs");
let code = r#"
struct MyStruct {}
enum MyEnum { A, B }
trait MyTrait {}
"#;
let dag = strategy.parse_file(&path, code).await.unwrap();
let types = strategy.extract_types(&dag);
assert_eq!(types.len(), 3);
}
#[test]
fn test_extract_types_empty_dag() {
let strategy = RustStrategy::new();
let dag = AstDag::new();
let types = strategy.extract_types(&dag);
assert!(types.is_empty());
}
#[test]
fn test_calculate_complexity_empty_dag() {
let strategy = RustStrategy::new();
let dag = AstDag::new();
let (cyclomatic, cognitive) = strategy.calculate_complexity(&dag);
assert_eq!(cyclomatic, 1); assert_eq!(cognitive, 0);
}
#[test]
fn test_calculate_complexity_with_control_flow() {
let strategy = RustStrategy::new();
let mut dag = AstDag::new();
let mut node1 = UnifiedAstNode::new(
AstKind::Statement(crate::ast::core::StmtKind::If),
Language::Rust,
);
node1.flags.set(NodeFlags::CONTROL_FLOW);
dag.add_node(node1);
let mut node2 = UnifiedAstNode::new(
AstKind::Statement(crate::ast::core::StmtKind::For),
Language::Rust,
);
node2.flags.set(NodeFlags::CONTROL_FLOW);
dag.add_node(node2);
let (cyclomatic, cognitive) = strategy.calculate_complexity(&dag);
assert_eq!(cyclomatic, 3); assert_eq!(cognitive, 2);
}
#[test]
fn test_rust_visitor_add_node() {
let mut dag = AstDag::new();
let mut visitor = RustAstVisitor::new(&mut dag);
let key = visitor.add_node(AstKind::Function(FunctionKind::Regular));
assert_eq!(key, 0);
assert_eq!(dag.nodes.len(), 1);
}
#[test]
fn test_rust_visitor_with_parent() {
let mut dag = AstDag::new();
let mut visitor = RustAstVisitor::new(&mut dag);
let parent_key = visitor.add_node(AstKind::Class(ClassKind::Struct));
visitor.current_parent = Some(parent_key);
let child_key = visitor.add_node(AstKind::Function(FunctionKind::Method));
let child_node = dag.nodes.get(child_key).unwrap();
assert_eq!(child_node.parent, parent_key);
}
#[tokio::test]
async fn test_parse_complex_rust_code() {
let strategy = RustStrategy::new();
let path = PathBuf::from("test.rs");
let code = r#"
use std::collections::HashMap;
pub struct Config {
name: String,
values: HashMap<String, i32>,
}
impl Config {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
values: HashMap::new(),
}
}
pub async fn load(&mut self) -> Result<(), std::io::Error> {
Ok(())
}
}
pub trait Configurable {
fn configure(&self);
}
impl Configurable for Config {
fn configure(&self) {
println!("{}", self.name);
}
}
pub enum State {
Active,
Inactive,
Pending { reason: String },
}
"#;
let result = strategy.parse_file(&path, code).await;
assert!(result.is_ok());
let dag = result.unwrap();
let _functions = strategy.extract_functions(&dag);
let types = strategy.extract_types(&dag);
assert!(
types.len() >= 3,
"Should find struct, trait, enum, and impl blocks"
);
}
}