xacli_testing/assert/
snapshot.rs1use std::{env, fs, path::PathBuf};
6
7use crate::TestingError;
8
9pub struct SnapshotManager {
11 snapshot_dir: PathBuf,
13 update_mode: bool,
15}
16
17impl SnapshotManager {
18 pub fn new() -> Self {
20 let snapshot_dir = env::var("CARGO_MANIFEST_DIR")
22 .map(|p| PathBuf::from(p).join("snapshots"))
23 .unwrap_or_else(|_| PathBuf::from("snapshots"));
24
25 let update_mode = env::var("UPDATE_SNAPSHOTS")
26 .map(|v| v == "1" || v.to_lowercase() == "true")
27 .unwrap_or(false);
28
29 Self {
30 snapshot_dir,
31 update_mode,
32 }
33 }
34
35 pub fn with_dir(mut self, dir: impl Into<PathBuf>) -> Self {
37 self.snapshot_dir = dir.into();
38 self
39 }
40
41 pub fn compare_or_create(&self, name: &str, actual: &str) -> Result<bool, TestingError> {
48 let snapshot_path = self.snapshot_dir.join(name);
49
50 if let Some(parent) = snapshot_path.parent() {
52 fs::create_dir_all(parent)?;
53 }
54
55 if snapshot_path.exists() {
56 let expected = fs::read_to_string(&snapshot_path)?;
57
58 if expected == actual {
59 Ok(true)
60 } else if self.update_mode {
61 fs::write(&snapshot_path, actual)?;
63 Ok(true)
64 } else {
65 Ok(false)
67 }
68 } else {
69 fs::write(&snapshot_path, actual)?;
71 Ok(true)
72 }
73 }
74
75 pub fn diff(&self, name: &str, actual: &str) -> Result<Option<String>, TestingError> {
77 let snapshot_path = self.snapshot_dir.join(name);
78
79 if !snapshot_path.exists() {
80 return Ok(Some(format!("Snapshot '{}' does not exist", name)));
81 }
82
83 let expected = fs::read_to_string(&snapshot_path)?;
84
85 if expected == actual {
86 Ok(None)
87 } else {
88 Ok(Some(format!(
89 "Snapshot mismatch:\n--- Expected ---\n{}\n--- Actual ---\n{}",
90 expected, actual
91 )))
92 }
93 }
94}
95
96impl Default for SnapshotManager {
97 fn default() -> Self {
98 Self::new()
99 }
100}