diff --git a/crates/application/src/use_cases/check_freshness.rs b/crates/application/src/use_cases/check_freshness.rs index d640b4d..615a993 100644 --- a/crates/application/src/use_cases/check_freshness.rs +++ b/crates/application/src/use_cases/check_freshness.rs @@ -1,18 +1,17 @@ use archlens_domain::{DomainError, NormalizedGraph, ports::DiagramRenderer}; -/// Compares the current rendered output against an on-disk file. +/// Compares the current rendered output against provided file content. /// Returns `Ok(true)` if up to date, `Ok(false)` if stale. pub struct CheckFreshness<'a> { pub graph: &'a NormalizedGraph, pub renderer: &'a dyn DiagramRenderer, - pub existing_path: &'a std::path::Path, + pub existing_content: &'a str, } impl<'a> CheckFreshness<'a> { pub fn execute(&self) -> Result { let rendered = self.renderer.render(self.graph.as_graph())?; let current = rendered.files().first().map(|f| f.content()).unwrap_or(""); - let existing = std::fs::read_to_string(self.existing_path).unwrap_or_default(); - Ok(current == existing) + Ok(current == self.existing_content) } } diff --git a/crates/application/src/use_cases/diff_diagram.rs b/crates/application/src/use_cases/diff_diagram.rs index 31dd518..6ae4b37 100644 --- a/crates/application/src/use_cases/diff_diagram.rs +++ b/crates/application/src/use_cases/diff_diagram.rs @@ -12,22 +12,21 @@ impl DiffResult { } } -/// Compares the rendered current graph against an existing diagram file and +/// Compares the rendered current graph against provided diagram content and /// returns which lines were added or removed. pub struct DiffDiagram<'a> { pub graph: &'a NormalizedGraph, pub renderer: &'a dyn DiagramRenderer, - pub existing_path: &'a std::path::Path, + pub existing_content: &'a str, } impl<'a> DiffDiagram<'a> { pub fn execute(&self) -> Result { let rendered = self.renderer.render(self.graph.as_graph())?; let current = rendered.files().first().map(|f| f.content()).unwrap_or(""); - let existing = std::fs::read_to_string(self.existing_path).unwrap_or_default(); let current_lines: std::collections::HashSet<&str> = current.lines().collect(); - let existing_lines: std::collections::HashSet<&str> = existing.lines().collect(); + let existing_lines: std::collections::HashSet<&str> = self.existing_content.lines().collect(); let added: Vec = current_lines .difference(&existing_lines) diff --git a/crates/application/tests/check_freshness_tests.rs b/crates/application/tests/check_freshness_tests.rs new file mode 100644 index 0000000..08a1458 --- /dev/null +++ b/crates/application/tests/check_freshness_tests.rs @@ -0,0 +1,43 @@ +mod fakes; + +use archlens_domain::{CodeGraph, NormalizedGraph, ports::DiagramRenderer}; +use archlens_application::use_cases::check_freshness::CheckFreshness; +use fakes::FakeDiagramRenderer; + +fn empty_graph() -> NormalizedGraph { + NormalizedGraph::from_project(CodeGraph::new()) +} + +#[test] +fn returns_true_when_content_matches() { + let graph = empty_graph(); + let renderer = FakeDiagramRenderer::new(); + let rendered = renderer.render(graph.as_graph()).unwrap(); + let existing = rendered.files().first().unwrap().content().to_string(); + + let result = CheckFreshness { + graph: &graph, + renderer: &renderer, + existing_content: &existing, + } + .execute() + .unwrap(); + + assert!(result); +} + +#[test] +fn returns_false_when_content_differs() { + let graph = empty_graph(); + let renderer = FakeDiagramRenderer::new(); + + let result = CheckFreshness { + graph: &graph, + renderer: &renderer, + existing_content: "stale content that does not match", + } + .execute() + .unwrap(); + + assert!(!result); +} diff --git a/crates/application/tests/diff_diagram_tests.rs b/crates/application/tests/diff_diagram_tests.rs new file mode 100644 index 0000000..6aab1db --- /dev/null +++ b/crates/application/tests/diff_diagram_tests.rs @@ -0,0 +1,44 @@ +mod fakes; + +use archlens_domain::{CodeGraph, NormalizedGraph, ports::DiagramRenderer}; +use archlens_application::use_cases::diff_diagram::DiffDiagram; +use fakes::FakeDiagramRenderer; + +fn empty_graph() -> NormalizedGraph { + NormalizedGraph::from_project(CodeGraph::new()) +} + +#[test] +fn no_diff_when_content_matches() { + let graph = empty_graph(); + let renderer = FakeDiagramRenderer::new(); + let rendered = renderer.render(graph.as_graph()).unwrap(); + let existing = rendered.files().first().unwrap().content().to_string(); + + let result = DiffDiagram { + graph: &graph, + renderer: &renderer, + existing_content: &existing, + } + .execute() + .unwrap(); + + assert!(result.is_empty()); +} + +#[test] +fn detects_added_lines() { + let graph = empty_graph(); + let renderer = FakeDiagramRenderer::new(); + + let result = DiffDiagram { + graph: &graph, + renderer: &renderer, + existing_content: "old line that will be removed", + } + .execute() + .unwrap(); + + assert!(!result.added.is_empty()); + assert!(!result.removed.is_empty()); +} diff --git a/crates/presentation/src/lib.rs b/crates/presentation/src/lib.rs index 1b0b37e..4449f3a 100644 --- a/crates/presentation/src/lib.rs +++ b/crates/presentation/src/lib.rs @@ -46,10 +46,12 @@ pub fn run(args: Cli) -> Result<()> { let existing_path = args.output.as_ref().ok_or_else(|| { anyhow::anyhow!("--check requires --output to specify the file to check against") })?; + let existing_content = std::fs::read_to_string(existing_path) + .map_err(|e| anyhow::anyhow!("cannot read {existing_path}: {e}"))?; let up_to_date = CheckFreshness { graph: &graph, renderer: &*renderer, - existing_path: std::path::Path::new(existing_path), + existing_content: &existing_content, } .execute()?; if up_to_date { @@ -222,10 +224,12 @@ fn run_diff(args: &Cli, existing_path: &std::path::Path) -> Result<()> { let graph = build_graph(args, level)?; let renderer = create_renderer(&args.format, level, !args.no_weights)?; + let existing_content = std::fs::read_to_string(existing_path) + .map_err(|e| anyhow::anyhow!("cannot read {}: {e}", existing_path.display()))?; let diff = DiffDiagram { graph: &graph, renderer: &*renderer, - existing_path, + existing_content: &existing_content, } .execute()?;