mod fakes; use std::path::Path; use archlens_application::queries::AnalyzeCodebase; use archlens_application::use_cases::generate_diagram::GenerateDiagram; use archlens_domain::{ AnalysisConfig, AnalysisResult, BoundaryRule, CodeElement, CodeElementKind, CodeGraph, FilePath, Language, ModuleName, NormalizedGraph, Relationship, RelationshipKind, SourceFile, }; use fakes::{FakeDiagramRenderer, FakeFileDiscovery, FakeSourceAnalyzer}; fn empty_graph() -> NormalizedGraph { NormalizedGraph::from_project(CodeGraph::new()) } fn graph_with_one_module() -> NormalizedGraph { let files = vec![SourceFile::new( FilePath::new("/p/src/orders/order.rs").unwrap(), Language::Rust, )]; let discovery = FakeFileDiscovery::new(files); let analyzer = FakeSourceAnalyzer::new().with_result( "/p/src/orders/order.rs", AnalysisResult::new( vec![ CodeElement::new( "Order", CodeElementKind::Struct, FilePath::new("/p/src/orders/order.rs").unwrap(), 1, ) .unwrap(), ], vec![], vec![], ), ); AnalyzeCodebase::new(discovery, analyzer) .execute(Path::new("/p"), &AnalysisConfig::default()) .unwrap() .graph() .clone() } fn graph_with_violation() -> NormalizedGraph { let mut cg = CodeGraph::new(); let a = CodeElement::new( "A", CodeElementKind::Struct, FilePath::new("a.rs").unwrap(), 1, ) .unwrap() .with_module(ModuleName::new("Alpha").unwrap()); let b = CodeElement::new( "B", CodeElementKind::Struct, FilePath::new("b.rs").unwrap(), 1, ) .unwrap() .with_module(ModuleName::new("Beta").unwrap()); cg.add_element(a); cg.add_element(b); cg.add_relationship(Relationship::new("A", "B", RelationshipKind::Composition).unwrap()); NormalizedGraph::from_project(cg) } #[test] fn execute_returns_render_output_without_writing_files() { let use_case = GenerateDiagram { graph: empty_graph(), renderer: Box::new(FakeDiagramRenderer::new()), allow_rules: vec![], deny_rules: vec![], split_by_module: false, }; let result = use_case.execute().unwrap(); assert!(!result.output.files().is_empty()); } #[test] fn execute_returns_empty_violations_when_no_rules_set() { let use_case = GenerateDiagram { graph: empty_graph(), renderer: Box::new(FakeDiagramRenderer::new()), allow_rules: vec![], deny_rules: vec![], split_by_module: false, }; let result = use_case.execute().unwrap(); assert!(result.violations.is_empty()); } #[test] fn execute_returns_violations_as_rule_violation_type() { let deny = vec![BoundaryRule::parse("Alpha --> Beta").unwrap()]; let use_case = GenerateDiagram { graph: graph_with_violation(), renderer: Box::new(FakeDiagramRenderer::new()), allow_rules: vec![], deny_rules: deny, split_by_module: false, }; let result = use_case.execute().unwrap(); assert_eq!(result.violations.len(), 1); assert!(result.violations[0].message().contains("Alpha")); assert!(result.violations[0].message().contains("Beta")); } #[test] fn split_by_module_returns_multiple_rendered_files() { let use_case = GenerateDiagram { graph: graph_with_one_module(), renderer: Box::new(FakeDiagramRenderer::new()), allow_rules: vec![], deny_rules: vec![], split_by_module: true, }; let result = use_case.execute().unwrap(); // overview + at least one module file assert!(result.output.files().len() >= 2); }