use std::sync::{Arc, Mutex};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum TodoStatus {
Pending,
InProgress,
Completed,
Cancelled,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Todo {
pub id: String,
pub content: String,
pub status: TodoStatus,
}
pub type SharedTodos = Arc<Mutex<Vec<Todo>>>;
#[must_use]
pub fn new_shared_todos() -> SharedTodos {
Arc::new(Mutex::new(Vec::new()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn todo_roundtrips_through_serde_json() {
let original = Todo {
id: "1".into(),
content: "do the thing".into(),
status: TodoStatus::InProgress,
};
let json = serde_json::to_string(&original).unwrap();
assert!(json.contains("\"in_progress\""));
let parsed: Todo = serde_json::from_str(&json).unwrap();
assert_eq!(parsed, original);
}
#[test]
fn status_uses_snake_case() {
for (status, expected) in [
(TodoStatus::Pending, "\"pending\""),
(TodoStatus::InProgress, "\"in_progress\""),
(TodoStatus::Completed, "\"completed\""),
(TodoStatus::Cancelled, "\"cancelled\""),
] {
let s = serde_json::to_string(&status).unwrap();
assert_eq!(s, expected, "status {status:?}");
}
}
#[test]
fn shared_todos_can_be_shared_across_clones() {
let a = new_shared_todos();
let b = Arc::clone(&a);
b.lock().unwrap().push(Todo {
id: "x".into(),
content: "shared".into(),
status: TodoStatus::Pending,
});
assert_eq!(a.lock().unwrap().len(), 1);
}
}