use archlens_domain::{ CodeElementKind, FilePath, Language, RelationshipKind, SourceFile, ports::SourceAnalyzer, }; use archlens_tree_sitter::TreeSitterAnalyzer; fn analyze_rust(source: &str, filename: &str) -> archlens_domain::AnalysisResult { let dir = tempfile::tempdir().unwrap(); let file_path = dir.path().join(filename); std::fs::write(&file_path, source).unwrap(); let analyzer = TreeSitterAnalyzer::new(); let source_file = SourceFile::new( FilePath::new(file_path.to_str().unwrap()).unwrap(), Language::Rust, ); analyzer.analyze_file(&source_file).unwrap() } #[test] fn extracts_rust_struct() { let result = analyze_rust("pub struct Order {\n id: u64,\n}", "order.rs"); assert_eq!(result.elements().len(), 1); assert_eq!(result.elements()[0].name(), "Order"); assert_eq!(result.elements()[0].kind(), CodeElementKind::Struct); } #[test] fn extracts_rust_enum() { let result = analyze_rust( "pub enum Status {\n Active,\n Inactive,\n}", "status.rs", ); assert_eq!(result.elements().len(), 1); assert_eq!(result.elements()[0].name(), "Status"); assert_eq!(result.elements()[0].kind(), CodeElementKind::Enum); } #[test] fn extracts_rust_trait() { let result = analyze_rust("pub trait Repository {\n fn find(&self);\n}", "repo.rs"); assert_eq!(result.elements().len(), 1); assert_eq!(result.elements()[0].name(), "Repository"); assert_eq!(result.elements()[0].kind(), CodeElementKind::Trait); } #[test] fn extracts_composition_from_struct_fields() { let source = "pub struct Order {\n id: u64,\n}\npub struct OrderService {\n order: Order,\n}"; let result = analyze_rust(source, "service.rs"); assert_eq!(result.elements().len(), 2); assert_eq!(result.relationships().len(), 1); assert_eq!(result.relationships()[0].source(), "OrderService"); assert_eq!(result.relationships()[0].target(), "Order"); assert_eq!( result.relationships()[0].kind(), RelationshipKind::Composition ); } #[test] fn extracts_inheritance_from_trait_impl() { let source = "pub trait Printable {}\npub struct Order {}\nimpl Printable for Order {}"; let result = analyze_rust(source, "order.rs"); let inheritance: Vec<_> = result .relationships() .iter() .filter(|r| r.kind() == RelationshipKind::Inheritance) .collect(); assert_eq!(inheritance.len(), 1); assert_eq!(inheritance[0].source(), "Order"); assert_eq!(inheritance[0].target(), "Printable"); } #[test] fn extracts_use_imports() { let source = "use crate::domain::Order;\nuse crate::ports::Repository;\n\npub struct Service {}"; let result = analyze_rust(source, "service.rs"); let imports: Vec<_> = result .relationships() .iter() .filter(|r| r.kind() == RelationshipKind::Import) .collect(); assert!(imports.iter().any(|r| r.target() == "crate::domain::Order")); assert!( imports .iter() .any(|r| r.target() == "crate::ports::Repository") ); } #[test] fn filters_std_and_external_crate_imports() { let source = "use std::collections::HashMap;\nuse serde::Serialize;\nuse crate::models::Order;\n"; let result = analyze_rust(source, "lib.rs"); let imports: Vec<_> = result .relationships() .iter() .filter(|r| r.kind() == RelationshipKind::Import) .collect(); assert_eq!(imports.len(), 1); assert_eq!(imports[0].target(), "crate::models::Order"); } #[test] fn extracts_mod_declarations() { let source = "mod models;\nmod services;\npub struct App {}"; let result = analyze_rust(source, "lib.rs"); let imports: Vec<_> = result .relationships() .iter() .filter(|r| r.kind() == RelationshipKind::Import) .collect(); assert!(imports.iter().any(|r| r.target() == "crate::models")); assert!(imports.iter().any(|r| r.target() == "crate::services")); } #[test] fn extracts_rust_method_with_typed_params() { let source = r#" pub struct OrderService; impl OrderService { pub fn process(&self, order: Order, count: u64) {} } "#; let result = analyze_rust(source, "service.rs"); let element = result .elements() .iter() .find(|e| e.name() == "OrderService") .unwrap(); assert!( element .methods() .iter() .any(|m| m.contains("order: Order") && m.contains("count: u64")), "expected typed params in method, got: {:?}", element.methods() ); } #[test] fn extracts_rust_method_return_type() { let source = r#" pub struct OrderService; impl OrderService { pub fn get(&self) -> Order {} } "#; let result = analyze_rust(source, "service.rs"); let element = result .elements() .iter() .find(|e| e.name() == "OrderService") .unwrap(); assert!( element.methods().iter().any(|m| m.contains("-> Order")), "expected return type in method, got: {:?}", element.methods() ); } #[test] fn extracts_rust_method_params_and_return() { let source = r#" pub struct OrderService; impl OrderService { pub fn process(&self, order: Order) -> Result<(), Error> {} } "#; let result = analyze_rust(source, "service.rs"); let element = result .elements() .iter() .find(|e| e.name() == "OrderService") .unwrap(); let method = element .methods() .iter() .find(|m| m.contains("process")) .unwrap(); assert!(method.contains("order: Order"), "missing param: {method}"); assert!(method.contains("->"), "missing return arrow: {method}"); } #[test] fn extracts_rust_static_method_params() { let source = r#" pub struct Finder; impl Finder { pub fn detect(path: &str, count: usize) -> bool { false } } "#; let result = analyze_rust(source, "finder.rs"); let element = result .elements() .iter() .find(|e| e.name() == "Finder") .unwrap(); let method = element .methods() .iter() .find(|m| m.contains("detect")) .unwrap(); assert!(method.contains("path"), "missing path param: {method}"); assert!(method.contains("count"), "missing count param: {method}"); } #[test] fn extracts_rust_private_method_params() { let source = r#" pub struct WalkdirDiscovery; impl WalkdirDiscovery { fn detect_language(path: &std::path::Path) -> Option { None } } "#; let result = analyze_rust(source, "discovery.rs"); let element = result .elements() .iter() .find(|e| e.name() == "WalkdirDiscovery") .unwrap(); let method = element .methods() .iter() .find(|m| m.contains("detect_language")) .unwrap(); assert!(method.contains("path"), "missing path param: {method}"); } #[test] fn extracts_rust_method_reference_param() { let source = r#" use std::path::Path; pub struct WalkdirDiscovery; impl WalkdirDiscovery { fn detect_language(path: &Path) -> Option { None } } "#; let result = analyze_rust(source, "discovery.rs"); let element = result .elements() .iter() .find(|e| e.name() == "WalkdirDiscovery") .unwrap(); let method = element .methods() .iter() .find(|m| m.contains("detect_language")) .unwrap(); assert!(method.contains("path"), "missing path param: {method}"); }