json_state 0.1.0

A simple Rust library for managing states using json with file persistence.
Documentation
pub mod state;

#[cfg(test)]
mod tests {
    use super::*;
    use serde_json::json;
    use std::path::Path;
    use std::io;
    use uuid::Uuid;
    use state::{State, StateManager};
    
    // Helper function to create a clean test environment
    fn setup_test_env(dir_name: &str) -> io::Result<()> {
        // Clean up the directory to ensure tests start fresh
        if Path::new(dir_name).exists() {
            std::fs::remove_dir_all(dir_name)?;
        }
        std::fs::create_dir_all(dir_name)?;
        Ok(())
    }
    
    #[test]
    fn test_state_creation() {
        let payload = json!({"name": "Test State", "value": 42});
        let state = state::State::new(payload.clone());
        
        assert_ne!(*state.get_id(), Uuid::nil(), "State ID should not be nil");
        assert_eq!(*state.get_payload(), payload, "Payload should match the input");
    }
    
    #[test]
    fn test_state_manager_creation() {
        let dir = "test_manager_creation".to_string();
        let _ = setup_test_env(&dir);
        
        let manager = StateManager::new(dir.clone());
        
        assert_eq!(manager.dir, dir, "Directory path should match");
        assert!(manager.states.is_empty(), "States should be empty initially");
    }
    
    #[test]
    fn test_save_and_load_state() -> io::Result<()> {
        let dir = "test_save_load".to_string();
        let _ = setup_test_env(&dir);
        
        let mut manager = StateManager::new(dir);
        
        // Create and save a state
        let payload = json!({"name": "John", "age": 30});
        let state = State::new(payload);
        let state_id = state.get_id().clone();
        
        manager.save(state.clone())?;
        
        // Verify state is in memory
        assert!(manager.states.contains_key(&state_id), "State should be in memory");
        
        // Verify state file exists
        let file_path = format!("{}/{}.json", manager.dir, state_id);
        assert!(Path::new(&file_path).exists(), "State file should exist");
        
        // Load the state
        match manager.load(&state_id)? {
            Some(loaded_state) => {
                assert_eq!(*loaded_state.get_id(), state_id, "Loaded state ID should match");
                assert_eq!(*loaded_state.get_payload(), *state.get_payload(), "Loaded payload should match");
            },
            None => panic!("Failed to load state"),
        }
        
        Ok(())
    }
    
    #[test]
    fn test_delete_state() -> io::Result<()> {
        let dir = "test_delete".to_string();
        let _ = setup_test_env(&dir);
        
        let mut manager = StateManager::new(dir);
        
        // Create and save a state
        let state = State::new(json!({"test": "delete"}));
        let state_id = state.get_id().clone();
        
        manager.save(state)?;
        
        // Verify state exists
        assert!(manager.states.contains_key(&state_id), "State should be in memory before deletion");
        
        // Delete the state
        manager.delete(&state_id)?;
        
        // Verify state is removed from memory
        assert!(!manager.states.contains_key(&state_id), "State should be removed from memory");
        
        // Verify state file is deleted
        let file_path = format!("{}/{}.json", manager.dir, state_id);
        assert!(!Path::new(&file_path).exists(), "State file should be deleted");
        
        // Attempt to load deleted state
        assert!(manager.load(&state_id)?.is_none(), "Deleted state should not be loadable");
        
        Ok(())
    }
    
    #[test]
    fn test_load_from_dir() -> io::Result<()> {
        let dir = "test_load_dir".to_string();
        let _ = setup_test_env(&dir);
        
        // Create initial manager and save some states
        let mut initial_manager = StateManager::new(dir.clone());
        
        let state1 = State::new(json!({"name": "State 1"}));
        let state2 = State::new(json!({"name": "State 2"}));
        let state3 = State::new(json!({"name": "State 3"}));
        
        let id1 = state1.get_id().clone();
        let id2 = state2.get_id().clone();
        let id3 = state3.get_id().clone();
        
        initial_manager.save(state1)?;
        initial_manager.save(state2)?;
        initial_manager.save(state3)?;
        
        // Create a new manager and load states from directory
        let loaded_manager = StateManager::load_from_dir(&dir)?;
        
        // Verify all states were loaded
        assert_eq!(loaded_manager.states.len(), 3, "Should load all 3 states");
        assert!(loaded_manager.states.contains_key(&id1), "Should contain state 1");
        assert!(loaded_manager.states.contains_key(&id2), "Should contain state 2");
        assert!(loaded_manager.states.contains_key(&id3), "Should contain state 3");
        
        Ok(())
    }
    
    #[test]
    fn test_empty_directory() -> io::Result<()> {
        let dir = "test_empty_dir".to_string();
        let _ = setup_test_env(&dir);
        
        // Load from an empty directory
        let manager = StateManager::load_from_dir(&dir)?;
        
        assert!(manager.states.is_empty(), "States should be empty when loading from empty directory");
        
        Ok(())
    }
    
    #[test]
    fn test_nonexistent_directory() -> io::Result<()> {
        let nonexistent_dir = "test_nonexistent_dir".to_string();
        
        // Ensure directory doesn't exist
        if Path::new(&nonexistent_dir).exists() {
            std::fs::remove_dir_all(&nonexistent_dir)?;
        }
        
        assert!(!Path::new(&nonexistent_dir).exists(), "Test directory should not exist initially");
        
        // Load from nonexistent directory (should create it)
        let manager = StateManager::load_from_dir(&nonexistent_dir)?;
        
        // Verify directory was created
        assert!(Path::new(&nonexistent_dir).exists(), "Directory should be created");
        assert!(manager.states.is_empty(), "States should be empty");
        
        Ok(())
    }
    
    #[test]
    fn test_load_nonexistent_state() -> io::Result<()> {
        let dir = "test_load_nonexistent".to_string();
        let _ = setup_test_env(&dir);
        
        let manager = StateManager::new(dir);
        
        let nonexistent_id = Uuid::new_v4();
        assert!(manager.load(&nonexistent_id)?.is_none(), "Should return None for nonexistent state");
        
        Ok(())
    }
    
    #[test]
    fn test_full_workflow() -> io::Result<()> {
        // This test mimics the workflow from the main.rs example
        let dir = "test_workflow".to_string();
        let _ = setup_test_env(&dir);
        
        // Create a manager
        let mut manager = StateManager::new(dir.clone());
        
        // Create and save a state
        let payload = json!({"name": "John", "age": 30});
        let state = State::new(payload);
        let state_id = state.get_id().clone();
        
        manager.save(state.clone())?;
        
        // Load the manager from directory
        let loaded_manager = StateManager::load_from_dir(&dir)?;
        assert_eq!(loaded_manager.states.len(), 1, "Should load the saved state");
        
        // Load the specific state
        let loaded_state = manager.load(&state_id)?.expect("Failed to load state");
        assert_eq!(*loaded_state.get_payload(), *state.get_payload(), "Loaded payload should match original");
        
        // Delete the state
        manager.delete(&state_id)?;
        
        // Verify state is deleted
        assert!(manager.load(&state_id)?.is_none(), "State should be deleted");
        
        Ok(())
    }
    
    #[test]
    fn test_clear_dir() -> io::Result<()> {
        let dir = "test_clear_dir".to_string();
        let _ = setup_test_env(&dir);
        
        // Create a manager and save some states
        let mut manager = StateManager::new(dir.clone());
        manager.save(State::new(json!({"test": "clear1"})))?;
        manager.save(State::new(json!({"test": "clear2"})))?;
        
        // Clear the directory
        StateManager::clear_dir(&dir)?;
        
        // Verify directory is empty
        let loaded_manager = StateManager::load_from_dir(&dir)?;
        assert!(loaded_manager.states.is_empty(), "Directory should be empty after clearing");
        
        Ok(())
    }
}