pub mod snapshot_manager;
pub mod snapshot_renderer;
pub use snapshot_manager::*;
pub use snapshot_renderer::*;
use std::collections::{HashMap, BTreeMap};
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, PartialEq)]
pub struct SnapshotMetadata {
pub name: String,
pub version: String,
pub created_at: String,
pub updated_at: String,
pub line_count: usize,
pub size_bytes: usize,
}
#[derive(Debug, Clone)]
pub struct SnapshotComparison {
pub matches: bool,
pub inline: bool,
pub name: String,
pub received: String,
pub expected: Option<String>,
pub diff: Option<String>,
pub added: Vec<String>,
pub removed: Vec<String>,
pub changed: Vec<(String, String, String)>, }
impl SnapshotComparison {
pub fn new_match(name: String, received: String) -> Self {
SnapshotComparison {
matches: true,
inline: false,
name,
received,
expected: None,
diff: None,
added: Vec::new(),
removed: Vec::new(),
changed: Vec::new(),
}
}
pub fn new_mismatch(
name: String,
received: String,
expected: String,
) -> Self {
SnapshotComparison {
matches: false,
inline: false,
name,
received,
expected: Some(expected),
diff: None,
added: Vec::new(),
removed: Vec::new(),
changed: Vec::new(),
}
}
pub fn with_diff(mut self, diff: String) -> Self {
self.diff = Some(diff);
self
}
pub fn with_changes(
mut self,
added: Vec<String>,
removed: Vec<String>,
changed: Vec<(String, String, String)>,
) -> Self {
self.added = added;
self.removed = removed;
self.changed = changed;
self
}
}
pub trait SnapshotSerializer {
fn serialize(&self, value: &dyn std::fmt::Display) -> String;
fn deserialize(&self, snapshot: &str) -> Result<String, SnapshotError>;
}
pub struct JsonSnapshotSerializer {
pub pretty: bool,
}
impl JsonSnapshotSerializer {
pub fn new(pretty: bool) -> Self {
JsonSnapshotSerializer { pretty }
}
}
impl Default for JsonSnapshotSerializer {
fn default() -> Self {
JsonSnapshotSerializer { pretty: true }
}
}
impl SnapshotSerializer for JsonSnapshotSerializer {
fn serialize(&self, value: &dyn std::fmt::Display) -> String {
if let Ok(json_value) = serde_json::from_str::<serde_json::Value>(&value.to_string()) {
if self.pretty {
serde_json::to_string_pretty(&json_value).unwrap_or_else(|_| value.to_string())
} else {
serde_json::to_string(&json_value).unwrap_or_else(|_| value.to_string())
}
} else {
value.to_string()
}
}
fn deserialize(&self, snapshot: &str) -> Result<String, SnapshotError> {
Ok(snapshot.to_string())
}
}
pub struct PlainSnapshotSerializer;
impl PlainSnapshotSerializer {
pub fn new() -> Self {
PlainSnapshotSerializer
}
}
impl Default for PlainSnapshotSerializer {
fn new() -> Self {
Self::new()
}
}
impl SnapshotSerializer for PlainSnapshotSerializer {
fn serialize(&self, value: &dyn std::fmt::Display) -> String {
value.to_string()
}
fn deserialize(&self, snapshot: &str) -> Result<String, SnapshotError> {
Ok(snapshot.to_string())
}
}
#[derive(Debug)]
pub enum SnapshotError {
FileNotFound(String),
IoError(std::io::Error),
ParseError(String),
SerializationError(String),
UpdateMode(String),
}
impl std::fmt::Display for SnapshotError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SnapshotError::FileNotFound(path) => write!(f, "Snapshot file not found: {}", path),
SnapshotError::IoError(err) => write!(f, "I/O error: {}", err),
SnapshotError::ParseError(msg) => write!(f, "Parse error: {}", msg),
SnapshotError::SerializationError(msg) => write!(f, "Serialization error: {}", msg),
SnapshotError::UpdateMode(msg) => write!(f, "Update mode: {}", msg),
}
}
}
impl std::error::Error for SnapshotError {}
impl From<std::io::Error> for SnapshotError {
fn from(err: std::io::Error) -> Self {
SnapshotError::IoError(err)
}
}
#[derive(Debug, Clone)]
pub struct SnapshotConfig {
pub update_snapshots: bool,
pub inline_snapshots: bool,
pub serializer: Box<dyn SnapshotSerializer + Send + Sync>,
pub file_extension: String,
pub pretty_print: bool,
}
impl Default for SnapshotConfig {
fn default() -> Self {
SnapshotConfig {
update_snapshots: false,
inline_snapshots: false,
serializer: Box::new(JsonSnapshotSerializer::default()),
file_extension: ".snap".to_string(),
pretty_print: true,
}
}
}
impl SnapshotConfig {
pub fn new() -> Self {
Self::default()
}
pub fn with_update_mode(mut self, update: bool) -> Self {
self.update_snapshots = update;
self
}
pub fn with_inline_snapshots(mut self, inline: bool) -> Self {
self.inline_snapshots = inline;
self
}
pub fn with_serializer(mut self, serializer: Box<dyn SnapshotSerializer + Send + Sync>) -> Self {
self.serializer = serializer;
self
}
pub fn with_file_extension(mut self, ext: String) -> Self {
self.file_extension = ext;
self
}
pub fn with_pretty_print(mut self, pretty: bool) -> Self {
self.pretty_print = pretty;
self
}
}