#[test]
fn test_project_context_creation() {
let context = ProjectContext {
project_type: "rust".to_string(),
files: vec![],
graph: None,
summary: ProjectSummary {
total_files: 0,
total_functions: 0,
total_structs: 0,
total_enums: 0,
total_traits: 0,
total_impls: 0,
dependencies: vec![],
},
};
assert_eq!(context.project_type, "rust");
assert!(context.files.is_empty());
assert_eq!(context.summary.total_files, 0);
}
#[test]
fn test_file_context_creation() {
let file_ctx = FileContext {
path: "src/main.rs".to_string(),
language: "rust".to_string(),
items: vec![],
complexity_metrics: None,
};
assert_eq!(file_ctx.path, "src/main.rs");
assert_eq!(file_ctx.language, "rust");
assert!(file_ctx.items.is_empty());
assert!(file_ctx.complexity_metrics.is_none());
}
#[test]
fn test_ast_item_function() {
let func = AstItem::Function {
name: "test_func".to_string(),
visibility: "pub".to_string(),
is_async: true,
line: 42,
};
assert_eq!(func.display_name(), "test_func");
if let AstItem::Function { name, is_async, .. } = func {
assert_eq!(name, "test_func");
assert!(is_async);
}
}
#[test]
fn test_ast_item_struct() {
let struct_item = AstItem::Struct {
name: "MyStruct".to_string(),
visibility: "pub".to_string(),
fields_count: 3,
derives: vec!["Debug".to_string(), "Clone".to_string()],
line: 10,
};
assert_eq!(struct_item.display_name(), "MyStruct");
if let AstItem::Struct {
fields_count,
derives,
..
} = struct_item
{
assert_eq!(fields_count, 3);
assert_eq!(derives.len(), 2);
}
}
#[test]
fn test_ast_item_enum() {
let enum_item = AstItem::Enum {
name: "MyEnum".to_string(),
visibility: "pub".to_string(),
variants_count: 5,
line: 20,
};
assert_eq!(enum_item.display_name(), "MyEnum");
if let AstItem::Enum { variants_count, .. } = enum_item {
assert_eq!(variants_count, 5);
}
}
#[test]
fn test_ast_item_trait() {
let trait_item = AstItem::Trait {
name: "MyTrait".to_string(),
visibility: "pub".to_string(),
line: 30,
};
assert_eq!(trait_item.display_name(), "MyTrait");
}
#[test]
fn test_ast_item_impl() {
let impl_item = AstItem::Impl {
type_name: "MyStruct".to_string(),
trait_name: Some("Display".to_string()),
line: 40,
};
assert_eq!(impl_item.display_name(), "MyStruct");
if let AstItem::Impl { trait_name, .. } = impl_item {
assert_eq!(trait_name, Some("Display".to_string()));
}
}
#[test]
fn test_ast_item_module() {
let mod_item = AstItem::Module {
name: "utils".to_string(),
visibility: "pub".to_string(),
line: 50,
};
assert_eq!(mod_item.display_name(), "utils");
}
#[test]
fn test_ast_item_use() {
let use_item = AstItem::Use {
path: "std::collections::HashMap".to_string(),
line: 1,
};
assert_eq!(use_item.display_name(), "std::collections::HashMap");
}
#[test]
fn test_ast_item_import() {
let import = AstItem::Import {
module: "numpy".to_string(),
items: vec![],
alias: Some("np".to_string()),
line: 2,
};
assert_eq!(import.display_name(), "numpy");
if let AstItem::Import { alias, .. } = import {
assert_eq!(alias, Some("np".to_string()));
}
}
#[test]
fn test_ast_item_struct_fields_and_derives() {
let struct_item = AstItem::Struct {
name: "MyStruct".to_string(),
visibility: "pub".to_string(),
fields_count: 3,
derives: vec!["Debug".to_string(), "Clone".to_string()],
line: 10,
};
assert_eq!(struct_item.display_name(), "MyStruct");
if let AstItem::Struct {
fields_count,
derives,
..
} = struct_item
{
assert_eq!(fields_count, 3);
assert_eq!(derives.len(), 2);
}
}
#[test]
fn test_project_summary_totals() {
let summary = ProjectSummary {
total_files: 10,
total_functions: 50,
total_structs: 15,
total_enums: 5,
total_traits: 8,
total_impls: 20,
dependencies: vec!["serde".to_string(), "tokio".to_string()],
};
assert_eq!(summary.total_files, 10);
assert_eq!(summary.total_functions, 50);
assert_eq!(summary.dependencies.len(), 2);
assert!(summary.dependencies.contains(&"serde".to_string()));
}
#[tokio::test]
async fn test_analyze_rust_file_simple() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("test.rs");
fs::write(
&file_path,
r#"
/// Hello.
pub fn hello() {
println!("Hello, world!");
}
/// Test struct.
pub struct TestStruct {
field: String,
}
/// Test enum.
pub enum TestEnum {
Variant1,
Variant2,
}
"#,
)
.unwrap();
let result = analyze_rust_file(&file_path).await;
assert!(result.is_ok());
let context = result.unwrap();
assert!(context.path.ends_with("test.rs"));
assert_eq!(context.language, "rust");
let func_count = context
.items
.iter()
.filter(|item| matches!(item, AstItem::Function { .. }))
.count();
let struct_count = context
.items
.iter()
.filter(|item| matches!(item, AstItem::Struct { .. }))
.count();
let enum_count = context
.items
.iter()
.filter(|item| matches!(item, AstItem::Enum { .. }))
.count();
assert_eq!(func_count, 1);
assert_eq!(struct_count, 1);
assert_eq!(enum_count, 1);
}
#[test]
fn test_format_context_as_markdown() {
let context = ProjectContext {
project_type: "rust".to_string(),
files: vec![FileContext {
path: "src/main.rs".to_string(),
language: "rust".to_string(),
items: vec![AstItem::Function {
name: "main".to_string(),
visibility: "pub".to_string(),
is_async: false,
line: 1,
}],
complexity_metrics: None,
}],
graph: None,
summary: ProjectSummary {
total_files: 1,
total_functions: 1,
total_structs: 0,
total_enums: 0,
total_traits: 0,
total_impls: 0,
dependencies: vec![],
},
};
let markdown = format_context_as_markdown(&context);
assert!(markdown.contains("# Project Context"));
assert!(markdown.contains("rust Project"));
assert!(markdown.contains("Files analyzed: 1"));
assert!(markdown.contains("Functions: 1"));
assert!(markdown.contains("src/main.rs"));
assert!(markdown.contains("main"));
}
#[test]
fn test_format_deep_context_as_markdown() {
}
#[test]
fn test_rust_visitor_struct() {
use syn::parse_str;
let code = r#"
/// Test struct.
pub struct TestStruct {
field1: String,
field2: i32,
}
"#;
let syntax = parse_str::<syn::File>(code).unwrap();
let mut visitor = RustVisitor::new(code.to_string());
visitor.visit_file(&syntax);
assert_eq!(visitor.items.len(), 1);
if let AstItem::Struct {
name, fields_count, ..
} = &visitor.items[0]
{
assert_eq!(name, "TestStruct");
assert_eq!(*fields_count, 2);
} else {
panic!("Expected struct item");
}
}
#[test]
fn test_rust_visitor_function() {
use syn::parse_str;
let code = r#"
pub async fn test_function(param: String) -> Result<(), Error> {
Ok(())
}
"#;
let syntax = parse_str::<syn::File>(code).unwrap();
let mut visitor = RustVisitor::new(code.to_string());
visitor.visit_file(&syntax);
assert_eq!(visitor.items.len(), 1);
if let AstItem::Function { name, is_async, .. } = &visitor.items[0] {
assert_eq!(name, "test_function");
assert!(*is_async);
} else {
panic!("Expected function item");
}
}
#[test]
fn test_rust_visitor_enum() {
use syn::parse_str;
let code = r#"
#[derive(Debug, Clone)]
/// Test enum.
pub enum TestEnum {
Variant1,
Variant2(String),
Variant3 { field: i32 },
}
"#;
let syntax = parse_str::<syn::File>(code).unwrap();
let mut visitor = RustVisitor::new(code.to_string());
visitor.visit_file(&syntax);
assert_eq!(visitor.items.len(), 1);
if let AstItem::Enum {
name,
variants_count,
..
} = &visitor.items[0]
{
assert_eq!(name, "TestEnum");
assert_eq!(*variants_count, 3);
} else {
panic!("Expected enum item");
}
}
#[test]
fn test_rust_visitor_trait() {
use syn::parse_str;
let code = r#"
/// Trait defining Test trait behavior.
pub trait TestTrait {
fn method(&self);
}
"#;
let syntax = parse_str::<syn::File>(code).unwrap();
let mut visitor = RustVisitor::new(code.to_string());
visitor.visit_file(&syntax);
assert_eq!(visitor.items.len(), 1);
if let AstItem::Trait { name, .. } = &visitor.items[0] {
assert_eq!(name, "TestTrait");
} else {
panic!("Expected trait item");
}
}
#[test]
fn test_rust_visitor_impl() {
use syn::parse_str;
let code = r#"
impl Display for TestStruct {
fn fmt(&self, f: &mut Formatter) -> Result {
Ok(())
}
}
"#;
let syntax = parse_str::<syn::File>(code).unwrap();
let mut visitor = RustVisitor::new(code.to_string());
visitor.visit_file(&syntax);
assert_eq!(visitor.items.len(), 1);
if let AstItem::Impl {
type_name,
trait_name,
..
} = &visitor.items[0]
{
assert_eq!(type_name, "TestStruct");
assert_eq!(trait_name, &Some("Display".to_string()));
} else {
panic!("Expected impl item");
}
}
#[tokio::test]
async fn test_context_graph_integration() {
let temp_dir = TempDir::new().unwrap();
let file_path = temp_dir.path().join("test.rs");
fs::write(
&file_path,
r#"
/// Hello.
pub fn hello() {
println!("Hello!");
}
/// Test struct.
pub struct TestStruct {
field: String,
}
"#,
)
.unwrap();
let result = analyze_project_with_cache(temp_dir.path(), "rust", None).await;
assert!(result.is_ok());
let context = result.unwrap();
assert!(context.graph.is_some());
let graph = context.graph.as_ref().unwrap();
if context.files.is_empty() {
assert_eq!(graph.num_nodes(), 0);
return;
}
assert!(graph.num_nodes() >= 1);
let hello_item = graph.get_item("hello");
assert!(hello_item.is_some());
let struct_item = graph.get_item("TestStruct");
assert!(struct_item.is_some());
}