use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use super::record::DeliverableId;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct MilestoneId(pub Uuid);
impl MilestoneId {
pub fn new() -> Self {
Self(Uuid::new_v4())
}
}
impl Default for MilestoneId {
fn default() -> Self {
Self::new()
}
}
impl std::fmt::Display for MilestoneId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl std::str::FromStr for MilestoneId {
type Err = uuid::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(Uuid::parse_str(s)?))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum MilestoneStatus {
#[default]
Proposed,
InProgress,
Complete,
Shipped,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Milestone {
pub id: MilestoneId,
pub project_name: String,
pub name: String,
#[serde(default)]
pub description: String,
pub target_date: DateTime<Utc>,
#[serde(default)]
pub status: MilestoneStatus,
#[serde(default)]
pub deliverables: Vec<DeliverableId>,
pub created_at: DateTime<Utc>,
}
#[cfg(test)]
mod tests {
use super::*;
fn sample() -> Milestone {
Milestone {
id: MilestoneId::new(),
project_name: "trusty-tools".into(),
name: "v1.0 Alpha".into(),
description: "first alpha".into(),
target_date: Utc::now(),
status: MilestoneStatus::Proposed,
deliverables: vec![DeliverableId::new(), DeliverableId::new()],
created_at: Utc::now(),
}
}
#[test]
fn milestone_serde_round_trip() {
let m = sample();
let json = serde_json::to_string(&m).unwrap();
let back: Milestone = serde_json::from_str(&json).unwrap();
assert_eq!(m, back);
}
#[test]
fn milestone_id_round_trip() {
let id = MilestoneId::new();
let parsed: MilestoneId = id.to_string().parse().unwrap();
assert_eq!(id, parsed);
}
#[test]
fn milestone_status_wire_format() {
assert_eq!(
serde_json::to_string(&MilestoneStatus::InProgress).unwrap(),
"\"in-progress\""
);
assert_eq!(
serde_json::to_string(&MilestoneStatus::Shipped).unwrap(),
"\"shipped\""
);
assert_eq!(MilestoneStatus::default(), MilestoneStatus::Proposed);
}
}