Skip to main content

turbovault_parser/
models.rs

1use serde::{Deserialize, Serialize};
2
3/// Obsidian task checkbox states
4#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
5pub enum TaskStatus {
6    /// `[ ]` — pending/incomplete
7    Pending,
8    /// `[x]` or `[X]` — completed/done
9    Done,
10    /// `[/]` — in progress
11    InProgress,
12    /// `[-]` — cancelled
13    Cancelled,
14}
15
16impl TaskStatus {
17    pub fn is_completed(&self) -> bool {
18        matches!(self, TaskStatus::Done)
19    }
20
21    pub fn from_marker(c: char) -> Self {
22        match c {
23            'x' | 'X' => TaskStatus::Done,
24            '/' => TaskStatus::InProgress,
25            '-' => TaskStatus::Cancelled,
26            _ => TaskStatus::Pending,
27        }
28    }
29}
30
31#[cfg(test)]
32mod tests {
33    use super::*;
34
35    #[test]
36    fn test_from_marker_done() {
37        assert_eq!(TaskStatus::from_marker('x'), TaskStatus::Done);
38        assert_eq!(TaskStatus::from_marker('X'), TaskStatus::Done);
39    }
40
41    #[test]
42    fn test_from_marker_in_progress() {
43        assert_eq!(TaskStatus::from_marker('/'), TaskStatus::InProgress);
44    }
45
46    #[test]
47    fn test_from_marker_cancelled() {
48        assert_eq!(TaskStatus::from_marker('-'), TaskStatus::Cancelled);
49    }
50
51    #[test]
52    fn test_from_marker_pending() {
53        assert_eq!(TaskStatus::from_marker(' '), TaskStatus::Pending);
54    }
55
56    #[test]
57    fn test_from_marker_unknown_defaults_pending() {
58        assert_eq!(TaskStatus::from_marker('?'), TaskStatus::Pending);
59        assert_eq!(TaskStatus::from_marker('a'), TaskStatus::Pending);
60    }
61
62    #[test]
63    fn test_is_completed() {
64        assert!(TaskStatus::Done.is_completed());
65        assert!(!TaskStatus::Pending.is_completed());
66        assert!(!TaskStatus::InProgress.is_completed());
67        assert!(!TaskStatus::Cancelled.is_completed());
68    }
69
70    #[test]
71    fn test_serde_roundtrip() {
72        let variants = [
73            TaskStatus::Pending,
74            TaskStatus::Done,
75            TaskStatus::InProgress,
76            TaskStatus::Cancelled,
77        ];
78
79        for variant in &variants {
80            let json = serde_json::to_string(variant)
81                .unwrap_or_else(|e| panic!("serialize {:?} failed: {}", variant, e));
82            let roundtripped: TaskStatus = serde_json::from_str(&json).unwrap_or_else(|e| {
83                panic!("deserialize {:?} from {:?} failed: {}", variant, json, e)
84            });
85            assert_eq!(
86                variant, &roundtripped,
87                "roundtrip mismatch for {:?}: serialized to {:?}",
88                variant, json
89            );
90        }
91    }
92}