#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
use chrono::TimeZone;
use tempfile::tempdir;
#[test]
fn test_task_status_emoji_conversion() {
assert_eq!(TaskStatus::Planned.to_emoji(), "\u{1f4cb}");
assert_eq!(TaskStatus::InProgress.to_emoji(), "\u{1f6a7}");
assert_eq!(TaskStatus::Completed.to_emoji(), "\u{2705}");
assert_eq!(TaskStatus::Blocked.to_emoji(), "\u{1f6ab}");
assert_eq!(TaskStatus::Deferred.to_emoji(), "\u{23f8}\u{fe0f}");
}
#[test]
fn test_task_status_from_emoji() {
assert_eq!(
TaskStatus::from_emoji("\u{1f4cb}"),
Some(TaskStatus::Planned)
);
assert_eq!(
TaskStatus::from_emoji("\u{1f6a7}"),
Some(TaskStatus::InProgress)
);
assert_eq!(
TaskStatus::from_emoji("\u{2705}"),
Some(TaskStatus::Completed)
);
assert_eq!(
TaskStatus::from_emoji("\u{1f6ab}"),
Some(TaskStatus::Blocked)
);
assert_eq!(
TaskStatus::from_emoji("\u{23f8}\u{fe0f}"),
Some(TaskStatus::Deferred)
);
assert_eq!(TaskStatus::from_emoji("\u{274c}"), None);
}
#[test]
fn test_complexity_from_str() {
use std::str::FromStr;
assert_eq!(
Complexity::from_str("low").expect("internal error"),
Complexity::Low
);
assert_eq!(
Complexity::from_str("LOW").expect("internal error"),
Complexity::Low
);
assert_eq!(
Complexity::from_str("medium").expect("internal error"),
Complexity::Medium
);
assert_eq!(
Complexity::from_str("high").expect("internal error"),
Complexity::High
);
assert!(Complexity::from_str("invalid").is_err());
}
#[test]
fn test_complexity_to_string() {
assert_eq!(Complexity::Low.to_string(), "low");
assert_eq!(Complexity::Medium.to_string(), "medium");
assert_eq!(Complexity::High.to_string(), "high");
}
#[test]
fn test_priority_from_str() {
use std::str::FromStr;
assert_eq!(
Priority::from_str("P0").expect("internal error"),
Priority::P0
);
assert_eq!(
Priority::from_str("p0").expect("internal error"),
Priority::P0
);
assert_eq!(
Priority::from_str("P1").expect("internal error"),
Priority::P1
);
assert_eq!(
Priority::from_str("P2").expect("internal error"),
Priority::P2
);
assert!(Priority::from_str("P3").is_err());
}
#[test]
fn test_task_seed_generation() {
let task = Task {
id: "PMAT-1234".to_string(),
description: "Test task".to_string(),
status: TaskStatus::Planned,
complexity: Complexity::Medium,
priority: Priority::P1,
assignee: None,
started_at: None,
completed_at: None,
};
assert_eq!(task.seed(), 1234);
let task_invalid = Task {
id: "INVALID-ID".to_string(),
description: "Test task".to_string(),
status: TaskStatus::Planned,
complexity: Complexity::Medium,
priority: Priority::P1,
assignee: None,
started_at: None,
completed_at: None,
};
assert_eq!(task_invalid.seed(), 42); }
#[test]
fn test_roadmap_save_and_load() {
let dir = tempdir().expect("internal error");
let roadmap_path = dir.path().join("test_roadmap.md");
let mut roadmap = Roadmap {
current_sprint: Some("v2.46.0".to_string()),
sprints: HashMap::new(),
backlog: vec![],
completed_sprints: vec![],
};
let sprint = Sprint {
version: "v2.46.0".to_string(),
title: "Test Sprint".to_string(),
start_date: Utc.with_ymd_and_hms(2025, 1, 1, 0, 0, 0).unwrap(),
end_date: Utc.with_ymd_and_hms(2025, 1, 7, 0, 0, 0).unwrap(),
priority: Priority::P0,
tasks: vec![],
definition_of_done: vec!["All tests pass".to_string()],
quality_gates: vec!["Coverage > 80%".to_string()],
};
roadmap.sprints.insert("v2.46.0".to_string(), sprint);
roadmap.to_file(&roadmap_path).expect("internal error");
let loaded = Roadmap::from_file(&roadmap_path).expect("internal error");
assert_eq!(loaded.current_sprint, Some("v2.46.0".to_string()));
assert!(loaded.sprints.contains_key("v2.46.0"));
}
#[test]
fn test_roadmap_get_sprint() {
let mut roadmap = Roadmap {
current_sprint: None,
sprints: HashMap::new(),
backlog: vec![],
completed_sprints: vec![],
};
let sprint = Sprint {
version: "v2.46.0".to_string(),
title: "Test Sprint".to_string(),
start_date: Utc::now(),
end_date: Utc::now(),
priority: Priority::P0,
tasks: vec![],
definition_of_done: vec![],
quality_gates: vec![],
};
roadmap.sprints.insert("v2.46.0".to_string(), sprint);
assert!(roadmap.get_sprint("v2.46.0").is_some());
assert!(roadmap.get_sprint("v2.47.0").is_none());
}
#[test]
fn test_roadmap_get_task() {
let mut roadmap = Roadmap {
current_sprint: None,
sprints: HashMap::new(),
backlog: vec![],
completed_sprints: vec![],
};
let task = Task {
id: "PMAT-0001".to_string(),
description: "Test task".to_string(),
status: TaskStatus::Planned,
complexity: Complexity::Medium,
priority: Priority::P1,
assignee: None,
started_at: None,
completed_at: None,
};
let sprint = Sprint {
version: "v2.46.0".to_string(),
title: "Test Sprint".to_string(),
start_date: Utc::now(),
end_date: Utc::now(),
priority: Priority::P0,
tasks: vec![task.clone()],
definition_of_done: vec![],
quality_gates: vec![],
};
roadmap.sprints.insert("v2.46.0".to_string(), sprint);
assert!(roadmap.get_task("PMAT-0001").is_some());
assert!(roadmap.get_task("PMAT-9999").is_none());
let backlog_task = Task {
id: "PMAT-0002".to_string(),
description: "Backlog task".to_string(),
status: TaskStatus::Planned,
complexity: Complexity::Low,
priority: Priority::P2,
assignee: None,
started_at: None,
completed_at: None,
};
roadmap.backlog.push(backlog_task);
assert!(roadmap.get_task("PMAT-0002").is_some());
}
#[test]
fn test_roadmap_update_task_status() {
let mut roadmap = Roadmap {
current_sprint: None,
sprints: HashMap::new(),
backlog: vec![],
completed_sprints: vec![],
};
let task = Task {
id: "PMAT-0001".to_string(),
description: "Test task".to_string(),
status: TaskStatus::Planned,
complexity: Complexity::Medium,
priority: Priority::P1,
assignee: None,
started_at: None,
completed_at: None,
};
let sprint = Sprint {
version: "v2.46.0".to_string(),
title: "Test Sprint".to_string(),
start_date: Utc::now(),
end_date: Utc::now(),
priority: Priority::P0,
tasks: vec![task],
definition_of_done: vec![],
quality_gates: vec![],
};
roadmap.sprints.insert("v2.46.0".to_string(), sprint);
roadmap
.update_task_status("PMAT-0001", TaskStatus::InProgress)
.expect("internal error");
let task = roadmap.get_task("PMAT-0001").expect("internal error");
assert_eq!(task.status, TaskStatus::InProgress);
roadmap
.update_task_status("PMAT-0001", TaskStatus::Completed)
.expect("internal error");
let task = roadmap.get_task("PMAT-0001").expect("internal error");
assert_eq!(task.status, TaskStatus::Completed);
assert!(roadmap
.update_task_status("PMAT-9999", TaskStatus::Completed)
.is_err());
}
#[test]
fn test_roadmap_config_defaults() {
let config = RoadmapConfig::default();
assert!(config.enabled);
assert_eq!(config.path, PathBuf::from("docs/execution/roadmap.md"));
assert!(config.auto_generate_todos);
assert!(config.enforce_quality_gates);
assert!(config.require_task_ids);
assert_eq!(config.task_id_pattern, "PMAT-[0-9]{4}");
}
#[test]
fn test_quality_gate_config_defaults() {
let config = QualityGateConfig::default();
assert_eq!(config.complexity_max, 20);
assert_eq!(config.coverage_min, 80);
assert!(config.documentation_required);
assert_eq!(config.satd_tolerance, 0);
assert!(config.lint_compliance);
}
#[test]
fn test_git_config_defaults() {
let config = GitConfig::default();
assert!(!config.create_branches);
assert_eq!(config.branch_pattern, "feature/{task_id}");
assert_eq!(config.commit_pattern, "{task_id}: {message}");
assert!(config.require_quality_check);
}
#[test]
fn test_tracking_config_defaults() {
let config = TrackingConfig::default();
assert!(config.velocity_tracking);
assert!(config.burndown_charts);
assert!(config.quality_metrics);
assert_eq!(config.export_format, "markdown");
}
#[test]
fn test_update_task_status_timestamps() {
let mut roadmap = Roadmap {
current_sprint: None,
sprints: HashMap::new(),
backlog: vec![],
completed_sprints: vec![],
};
let task = Task {
id: "PMAT-0001".to_string(),
description: "Test task".to_string(),
status: TaskStatus::Planned,
complexity: Complexity::Medium,
priority: Priority::P1,
assignee: None,
started_at: None,
completed_at: None,
};
let sprint = Sprint {
version: "v2.46.0".to_string(),
title: "Test Sprint".to_string(),
start_date: Utc::now(),
end_date: Utc::now(),
priority: Priority::P0,
tasks: vec![task],
definition_of_done: vec![],
quality_gates: vec![],
};
roadmap.sprints.insert("v2.46.0".to_string(), sprint);
roadmap
.update_task_status("PMAT-0001", TaskStatus::InProgress)
.expect("internal error");
if let Some(sprint) = roadmap.sprints.get("v2.46.0") {
if let Some(task) = sprint.tasks.iter().find(|t| t.id == "PMAT-0001") {
assert!(task.started_at.is_some());
assert!(task.completed_at.is_none());
}
}
roadmap
.update_task_status("PMAT-0001", TaskStatus::Completed)
.expect("internal error");
if let Some(sprint) = roadmap.sprints.get("v2.46.0") {
if let Some(task) = sprint.tasks.iter().find(|t| t.id == "PMAT-0001") {
assert!(task.started_at.is_some());
assert!(task.completed_at.is_some());
}
}
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod property_tests {
use proptest::prelude::*;
proptest! {
#[test]
fn basic_property_stability(_input in ".*") {
prop_assert!(true);
}
#[test]
fn module_consistency_check(_x in 0u32..1000) {
prop_assert!(_x < 1001);
}
}
}