use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq)]
pub struct Checkpoint {
name: String,
state_data: HashMap<String, String>,
timestamp: std::time::SystemTime,
}
impl Checkpoint {
pub fn new(name: String) -> Self {
Self {
name,
state_data: HashMap::new(),
timestamp: std::time::SystemTime::now(),
}
}
pub fn with_state(name: String, state_data: HashMap<String, String>) -> Self {
Self {
name,
state_data,
timestamp: std::time::SystemTime::now(),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn state_data(&self) -> &HashMap<String, String> {
&self.state_data
}
pub fn variable_count(&self) -> usize {
self.state_data.len()
}
pub fn has_variable(&self, name: &str) -> bool {
self.state_data.contains_key(name)
}
pub fn get_variable(&self, name: &str) -> Option<&String> {
self.state_data.get(name)
}
pub fn timestamp(&self) -> std::time::SystemTime {
self.timestamp
}
pub fn is_empty(&self) -> bool {
self.state_data.is_empty()
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum TransactionResult<T> {
Success(T),
RolledBack { error: String },
}
impl<T> TransactionResult<T> {
pub fn is_success(&self) -> bool {
matches!(self, TransactionResult::Success(_))
}
pub fn is_rolled_back(&self) -> bool {
matches!(self, TransactionResult::RolledBack { .. })
}
pub fn success_value(self) -> Option<T> {
match self {
TransactionResult::Success(value) => Some(value),
TransactionResult::RolledBack { .. } => None,
}
}
pub fn error(&self) -> Option<&str> {
match self {
TransactionResult::Success(_) => None,
TransactionResult::RolledBack { error } => Some(error),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_notebook_003_checkpoint_creation() {
let checkpoint = Checkpoint::new("test_checkpoint".to_string());
assert_eq!(checkpoint.name(), "test_checkpoint");
assert_eq!(checkpoint.variable_count(), 0);
assert!(checkpoint.is_empty());
}
#[test]
fn test_notebook_003_checkpoint_with_state() {
let mut state = HashMap::new();
state.insert("x".to_string(), "42".to_string());
state.insert("y".to_string(), "100".to_string());
let checkpoint = Checkpoint::with_state("state1".to_string(), state);
assert_eq!(checkpoint.name(), "state1");
assert_eq!(checkpoint.variable_count(), 2);
assert!(!checkpoint.is_empty());
assert!(checkpoint.has_variable("x"));
assert!(checkpoint.has_variable("y"));
}
#[test]
fn test_notebook_003_checkpoint_get_variable() {
let mut state = HashMap::new();
state.insert("test_var".to_string(), "test_value".to_string());
let checkpoint = Checkpoint::with_state("cp".to_string(), state);
assert_eq!(
checkpoint.get_variable("test_var"),
Some(&"test_value".to_string())
);
assert_eq!(checkpoint.get_variable("nonexistent"), None);
}
#[test]
fn test_notebook_003_checkpoint_has_variable() {
let mut state = HashMap::new();
state.insert("exists".to_string(), "value".to_string());
let checkpoint = Checkpoint::with_state("cp".to_string(), state);
assert!(checkpoint.has_variable("exists"));
assert!(!checkpoint.has_variable("missing"));
}
#[test]
fn test_notebook_003_checkpoint_timestamp() {
let before = std::time::SystemTime::now();
let checkpoint = Checkpoint::new("timed".to_string());
let after = std::time::SystemTime::now();
let timestamp = checkpoint.timestamp();
assert!(timestamp >= before);
assert!(timestamp <= after);
}
#[test]
fn test_notebook_003_checkpoint_clone() {
let mut state = HashMap::new();
state.insert("data".to_string(), "value".to_string());
let original = Checkpoint::with_state("original".to_string(), state);
let cloned = original.clone();
assert_eq!(original, cloned);
assert_eq!(cloned.name(), "original");
assert_eq!(cloned.variable_count(), 1);
}
#[test]
fn test_notebook_003_checkpoint_debug() {
let checkpoint = Checkpoint::new("debug_test".to_string());
let debug_str = format!("{checkpoint:?}");
assert!(debug_str.contains("Checkpoint"));
assert!(debug_str.contains("debug_test"));
}
#[test]
fn test_notebook_003_transaction_success() {
let result = TransactionResult::Success(42);
assert!(result.is_success());
assert!(!result.is_rolled_back());
assert!(result.error().is_none());
let result2 = TransactionResult::Success(42);
assert_eq!(result2.success_value(), Some(42));
}
#[test]
fn test_notebook_003_transaction_rolled_back() {
let result: TransactionResult<i32> = TransactionResult::RolledBack {
error: "Parse error".to_string(),
};
assert!(!result.is_success());
assert!(result.is_rolled_back());
assert_eq!(result.error(), Some("Parse error"));
let result2: TransactionResult<i32> = TransactionResult::RolledBack {
error: "Parse error".to_string(),
};
assert_eq!(result2.success_value(), None);
}
#[test]
fn test_notebook_003_transaction_result_clone() {
let result = TransactionResult::Success("data".to_string());
let cloned = result.clone();
assert_eq!(result, cloned);
assert!(cloned.is_success());
}
#[test]
fn test_notebook_003_transaction_result_debug() {
let success = TransactionResult::Success(100);
let debug_str = format!("{success:?}");
assert!(debug_str.contains("Success"));
assert!(debug_str.contains("100"));
let failure: TransactionResult<i32> = TransactionResult::RolledBack {
error: "error message".to_string(),
};
let debug_str = format!("{failure:?}");
assert!(debug_str.contains("RolledBack"));
assert!(debug_str.contains("error message"));
}
#[test]
fn test_notebook_003_checkpoint_empty_state() {
let checkpoint = Checkpoint::new("empty".to_string());
assert!(checkpoint.is_empty());
assert_eq!(checkpoint.variable_count(), 0);
assert_eq!(checkpoint.state_data().len(), 0);
}
#[test]
fn test_notebook_003_checkpoint_large_state() {
let mut state = HashMap::new();
for i in 0..100 {
state.insert(format!("var_{i}"), format!("value_{i}"));
}
let checkpoint = Checkpoint::with_state("large".to_string(), state);
assert_eq!(checkpoint.variable_count(), 100);
assert!(!checkpoint.is_empty());
assert!(checkpoint.has_variable("var_0"));
assert!(checkpoint.has_variable("var_99"));
}
#[test]
fn test_notebook_003_checkpoint_unicode_names() {
let mut state = HashMap::new();
state.insert("変数".to_string(), "値".to_string());
state.insert("переменная".to_string(), "значение".to_string());
let checkpoint = Checkpoint::with_state("unicode_test".to_string(), state);
assert!(checkpoint.has_variable("変数"));
assert!(checkpoint.has_variable("переменная"));
assert_eq!(checkpoint.get_variable("変数"), Some(&"値".to_string()));
}
#[test]
fn test_notebook_003_checkpoint_equality() {
let mut state1 = HashMap::new();
state1.insert("x".to_string(), "1".to_string());
let mut state2 = HashMap::new();
state2.insert("x".to_string(), "1".to_string());
let cp1 = Checkpoint::with_state("test".to_string(), state1.clone());
let cp2 = Checkpoint::with_state("test".to_string(), state2);
let cp3 = Checkpoint::with_state("different".to_string(), state1);
assert_eq!(cp1.name(), cp2.name());
assert_eq!(cp1.variable_count(), cp2.variable_count());
assert_ne!(cp1.name(), cp3.name());
}
}