use serde::{Deserialize, Serialize}; use crate::progress::ReadingPosition; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(tag = "type")] pub enum ReadingEvent { MaterialOpened { material_id: String, timestamp_ms: i64, }, MaterialClosed { material_id: String, timestamp_ms: i64, active_seconds: u32, }, PositionChanged { material_id: String, position: ReadingPosition, timestamp_ms: i64, }, Heartbeat { material_id: String, active_seconds: u32, position: Option, timestamp_ms: i64, }, MarkedAsRead { material_id: String, timestamp_ms: i64, }, } #[cfg(test)] mod tests { use super::*; #[test] fn test_material_opened_serde() { let e = ReadingEvent::MaterialOpened { material_id: "abc".into(), timestamp_ms: 1000, }; let json = serde_json::to_string(&e).unwrap(); assert!(json.contains("\"type\":\"MaterialOpened\"")); let back: ReadingEvent = serde_json::from_str(&json).unwrap(); assert_eq!(back, e); } #[test] fn test_material_closed_serde() { let e = ReadingEvent::MaterialClosed { material_id: "abc".into(), timestamp_ms: 2000, active_seconds: 120, }; let json = serde_json::to_string(&e).unwrap(); let back: ReadingEvent = serde_json::from_str(&json).unwrap(); assert_eq!(back, e); } #[test] fn test_position_changed_serde() { let e = ReadingEvent::PositionChanged { material_id: "abc".into(), position: ReadingPosition::Markdown { block_id: "h1".into(), scroll_progress: 0.5 }, timestamp_ms: 3000, }; let json = serde_json::to_string(&e).unwrap(); let back: ReadingEvent = serde_json::from_str(&json).unwrap(); assert_eq!(back, e); } #[test] fn test_heartbeat_serde() { let e = ReadingEvent::Heartbeat { material_id: "abc".into(), active_seconds: 15, position: None, timestamp_ms: 4000, }; let json = serde_json::to_string(&e).unwrap(); let back: ReadingEvent = serde_json::from_str(&json).unwrap(); assert_eq!(back, e); } #[test] fn test_heartbeat_with_position_serde() { let e = ReadingEvent::Heartbeat { material_id: "abc".into(), active_seconds: 15, position: Some(ReadingPosition::Pdf { page_number: 3, page_progress: 0.5, overall_progress: 0.1 }), timestamp_ms: 5000, }; let json = serde_json::to_string(&e).unwrap(); let back: ReadingEvent = serde_json::from_str(&json).unwrap(); assert_eq!(back, e); } #[test] fn test_marked_as_read_serde() { let e = ReadingEvent::MarkedAsRead { material_id: "abc".into(), timestamp_ms: 6000, }; let json = serde_json::to_string(&e).unwrap(); let back: ReadingEvent = serde_json::from_str(&json).unwrap(); assert_eq!(back, e); } }