rust-todo-cli 0.2.3-beta.3

A CLI tool for managing to-do lists
use std::fmt;

use crate::time::to_local_time;
use chrono::{DateTime, Utc};
use clap::ValueEnum;
use serde::{Deserialize, Serialize};

#[derive(
    Debug, ValueEnum, Serialize, Deserialize, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord,
)]
pub enum Priority {
    #[value(alias = "1")]
    High,
    #[value(alias = "2")]
    Medium,
    #[value(alias = "3")]
    #[default]
    Low,
}

impl fmt::Display for Priority {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Priority::High => write!(f, "High"),
            Priority::Medium => write!(f, "Medium"),
            Priority::Low => write!(f, "Low"),
        }
    }
}

#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub struct Task {
    id: usize,
    content: String,
    #[serde(default)]
    description: Option<String>,
    completed: bool,
    #[serde(default)]
    deadline: Option<DateTime<Utc>>,
    #[serde(default)]
    priority: Priority,
}

impl Task {
    pub fn new(
        id: usize,
        content: String,
        description: Option<String>,
        deadline: Option<DateTime<Utc>>,
        priority: Priority,
    ) -> Task {
        Task {
            id,
            content,
            description,
            completed: false,
            deadline,
            priority,
        }
    }

    pub fn id(&self) -> usize {
        self.id
    }

    pub fn _content(&self) -> &str {
        &self.content
    }

    pub fn description(&self) -> Option<String> {
        self.description.clone()
    }

    pub fn _completed(&self) -> bool {
        self.completed
    }

    pub fn deadline(&self) -> Option<DateTime<Utc>> {
        self.deadline
    }

    pub fn priority(&self) -> Priority {
        self.priority
    }

    pub fn complete(&mut self) {
        self.completed = true;
    }

    pub fn incomplete(&mut self) {
        self.completed = false;
    }

    pub fn set_content(&mut self, content: String) {
        self.content = content;
    }

    pub fn set_description(&mut self, description: Option<String>) {
        self.description = description;
    }

    pub fn set_deadline(&mut self, deadline: Option<DateTime<Utc>>) {
        self.deadline = deadline;
    }

    pub fn set_priority(&mut self, priority: Priority) {
        self.priority = priority;
    }
}

pub struct TaskRow<'a> {
    pub task: &'a Task,
    pub no: usize,
}

impl TaskRow<'_> {
    pub fn to_table(&self) -> Vec<String> {
        let task = self.task;
        let status: &str = if task.completed { "" } else { " " };
        let deadline = match task.deadline {
            None => String::from("No"),
            Some(t) => to_local_time(&t).to_string(),
        };
        let more = if task.description.is_some() {
            String::from("Show desc")
        } else {
            String::new()
        };
        vec![
            status.to_string(),
            self.no.to_string(),
            task.priority.to_string(),
            deadline,
            task.content.clone(),
            more,
        ]
    }
}

#[cfg(test)]
mod task_test {
    use super::*;

    #[test]
    fn test_task() {
        let id: usize = 1001;
        let content: String = String::from("test_content1");
        let deadline1: DateTime<Utc> = "2000-01-01T12:00:00+00:00".parse().unwrap();
        let description = Some(String::from("test_description1"));
        let priority = Priority::default();
        let mut task: Task = Task::new(id, content, description, Some(deadline1), priority);

        assert_eq!(task.id(), 1001);
        assert_eq!(task._content(), "test_content1".to_string());
        assert_eq!(task.description(), Some("test_description1".to_string()));
        assert_eq!(task.priority(), Priority::Low);
        assert!(!task._completed());

        let expected = "2000-01-01T12:00:00+00:00".parse().unwrap();
        assert_eq!(task.deadline(), Some(expected));

        task.set_content("test_content2".to_string());
        assert_eq!(task._content(), "test_content2".to_string());
        task.set_description(Some("test_description2".to_string()));
        assert_eq!(task.description(), Some("test_description2".to_string()));
        task.set_description(None);
        assert!(task.description().is_none());
        task.complete();
        assert!(task._completed());
        task.incomplete();
        assert!(!task._completed());
        task.set_priority(Priority::High);
        assert_eq!(task.priority(), Priority::High);

        let deadline2: DateTime<Utc> = "2000-01-02T12:00:00+00:00".parse().unwrap();
        task.set_deadline(Some(deadline2));
        let expected = "2000-01-02T12:00:00+00:00".parse().unwrap();
        assert_eq!(task.deadline(), Some(expected));
        task.set_deadline(None);
        assert!(task.deadline().is_none());
    }
}