use things3_core::{
models::{
CreateAreaRequest, CreateProjectRequest, ProjectChildHandling, UpdateAreaRequest,
UpdateProjectRequest,
},
ThingsDatabase,
};
#[cfg(feature = "test-utils")]
use things3_core::test_utils::{create_test_database, TaskRequestBuilder};
#[cfg(feature = "test-utils")]
use tempfile::NamedTempFile;
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_create_project_success() {
let temp_file = NamedTempFile::new().unwrap();
let db_path = temp_file.path();
create_test_database(db_path).await.unwrap();
let db = ThingsDatabase::new(db_path).await.unwrap();
let request = CreateProjectRequest {
title: "Test Project".to_string(),
notes: Some("Project notes".to_string()),
area_uuid: None,
start_date: None,
deadline: None,
tags: Some(vec!["test".to_string()]),
};
let uuid = db.create_project(request).await.unwrap();
assert!(!uuid.as_str().is_empty());
let task = db.get_task_by_uuid(&uuid).await.unwrap();
assert!(task.is_some());
let task = task.unwrap();
assert_eq!(task.title, "Test Project");
assert_eq!(task.task_type, things3_core::models::TaskType::Project);
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_create_project_with_area() {
let temp_file = NamedTempFile::new().unwrap();
let db_path = temp_file.path();
create_test_database(db_path).await.unwrap();
let db = ThingsDatabase::new(db_path).await.unwrap();
let area_request = CreateAreaRequest {
title: "Work".to_string(),
};
let area_uuid = db.create_area(area_request).await.unwrap();
let request = CreateProjectRequest {
title: "Work Project".to_string(),
notes: None,
area_uuid: Some(area_uuid.clone()),
start_date: None,
deadline: None,
tags: None,
};
let project_uuid = db.create_project(request).await.unwrap();
let task = db.get_task_by_uuid(&project_uuid).await.unwrap().unwrap();
assert_eq!(task.area_uuid, Some(area_uuid));
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_update_project_success() {
let temp_file = NamedTempFile::new().unwrap();
let db_path = temp_file.path();
create_test_database(db_path).await.unwrap();
let db = ThingsDatabase::new(db_path).await.unwrap();
let create_request = CreateProjectRequest {
title: "Original Title".to_string(),
notes: None,
area_uuid: None,
start_date: None,
deadline: None,
tags: None,
};
let uuid = db.create_project(create_request).await.unwrap();
let update_request = UpdateProjectRequest {
uuid: uuid.clone(),
title: Some("Updated Title".to_string()),
notes: Some("New notes".to_string()),
area_uuid: None,
start_date: None,
deadline: None,
tags: None,
};
db.update_project(update_request).await.unwrap();
let task = db.get_task_by_uuid(&uuid).await.unwrap().unwrap();
assert_eq!(task.title, "Updated Title");
assert_eq!(task.notes, Some("New notes".to_string()));
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_complete_project_success() {
let temp_file = NamedTempFile::new().unwrap();
let db_path = temp_file.path();
create_test_database(db_path).await.unwrap();
let db = ThingsDatabase::new(db_path).await.unwrap();
let request = CreateProjectRequest {
title: "Project to Complete".to_string(),
notes: None,
area_uuid: None,
start_date: None,
deadline: None,
tags: None,
};
let uuid = db.create_project(request).await.unwrap();
db.complete_project(&uuid, ProjectChildHandling::Error)
.await
.unwrap();
let task = db.get_task_by_uuid(&uuid).await.unwrap().unwrap();
assert_eq!(task.status, things3_core::models::TaskStatus::Completed);
assert!(task.stop_date.is_some());
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_complete_project_with_children_cascade() {
let temp_file = NamedTempFile::new().unwrap();
let db_path = temp_file.path();
create_test_database(db_path).await.unwrap();
let db = ThingsDatabase::new(db_path).await.unwrap();
let project_request = CreateProjectRequest {
title: "Project with Tasks".to_string(),
notes: None,
area_uuid: None,
start_date: None,
deadline: None,
tags: None,
};
let project_uuid = db.create_project(project_request).await.unwrap();
let task_request = TaskRequestBuilder::new()
.title("Child Task")
.project(project_uuid.clone())
.build();
let task_uuid = db.create_task(task_request).await.unwrap();
db.complete_project(&project_uuid, ProjectChildHandling::Cascade)
.await
.unwrap();
let project = db.get_task_by_uuid(&project_uuid).await.unwrap().unwrap();
assert_eq!(project.status, things3_core::models::TaskStatus::Completed);
let task = db.get_task_by_uuid(&task_uuid).await.unwrap().unwrap();
assert_eq!(task.status, things3_core::models::TaskStatus::Completed);
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_delete_project_with_children_error() {
let temp_file = NamedTempFile::new().unwrap();
let db_path = temp_file.path();
create_test_database(db_path).await.unwrap();
let db = ThingsDatabase::new(db_path).await.unwrap();
let project_request = CreateProjectRequest {
title: "Project with Tasks".to_string(),
notes: None,
area_uuid: None,
start_date: None,
deadline: None,
tags: None,
};
let project_uuid = db.create_project(project_request).await.unwrap();
let task_request = TaskRequestBuilder::new()
.title("Child Task")
.project(project_uuid.clone())
.build();
db.create_task(task_request).await.unwrap();
let result = db
.delete_project(&project_uuid, ProjectChildHandling::Error)
.await;
assert!(result.is_err());
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_delete_project_with_children_orphan() {
let temp_file = NamedTempFile::new().unwrap();
let db_path = temp_file.path();
create_test_database(db_path).await.unwrap();
let db = ThingsDatabase::new(db_path).await.unwrap();
let project_request = CreateProjectRequest {
title: "Project with Tasks".to_string(),
notes: None,
area_uuid: None,
start_date: None,
deadline: None,
tags: None,
};
let project_uuid = db.create_project(project_request).await.unwrap();
let task_request = TaskRequestBuilder::new()
.title("Child Task")
.project(project_uuid.clone())
.build();
let task_uuid = db.create_task(task_request).await.unwrap();
db.delete_project(&project_uuid, ProjectChildHandling::Orphan)
.await
.unwrap();
let project = db.get_task_by_uuid(&project_uuid).await.unwrap();
assert!(project.is_none());
let task = db.get_task_by_uuid(&task_uuid).await.unwrap().unwrap();
assert_eq!(task.project_uuid, None);
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_create_area_success() {
let temp_file = NamedTempFile::new().unwrap();
let db_path = temp_file.path();
create_test_database(db_path).await.unwrap();
let db = ThingsDatabase::new(db_path).await.unwrap();
let request = CreateAreaRequest {
title: "Personal".to_string(),
};
let uuid = db.create_area(request).await.unwrap();
assert!(!uuid.as_str().is_empty());
let areas = db.get_all_areas().await.unwrap();
assert!(areas
.iter()
.any(|a| a.uuid == uuid && a.title == "Personal"));
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_update_area_success() {
let temp_file = NamedTempFile::new().unwrap();
let db_path = temp_file.path();
create_test_database(db_path).await.unwrap();
let db = ThingsDatabase::new(db_path).await.unwrap();
let create_request = CreateAreaRequest {
title: "Original Area".to_string(),
};
let uuid = db.create_area(create_request).await.unwrap();
let update_request = UpdateAreaRequest {
uuid: uuid.clone(),
title: "Updated Area".to_string(),
};
db.update_area(update_request).await.unwrap();
let areas = db.get_all_areas().await.unwrap();
let area = areas.iter().find(|a| a.uuid == uuid).unwrap();
assert_eq!(area.title, "Updated Area");
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_delete_area_with_projects() {
let temp_file = NamedTempFile::new().unwrap();
let db_path = temp_file.path();
create_test_database(db_path).await.unwrap();
let db = ThingsDatabase::new(db_path).await.unwrap();
let area_request = CreateAreaRequest {
title: "Area to Delete".to_string(),
};
let area_uuid = db.create_area(area_request).await.unwrap();
let project_request = CreateProjectRequest {
title: "Project in Area".to_string(),
notes: None,
area_uuid: Some(area_uuid.clone()),
start_date: None,
deadline: None,
tags: None,
};
let project_uuid = db.create_project(project_request).await.unwrap();
db.delete_area(&area_uuid).await.unwrap();
let areas = db.get_all_areas().await.unwrap();
assert!(!areas.iter().any(|a| a.uuid == area_uuid));
let project = db.get_task_by_uuid(&project_uuid).await.unwrap().unwrap();
assert_eq!(project.area_uuid, None);
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_delete_area_empty() {
let temp_file = NamedTempFile::new().unwrap();
let db_path = temp_file.path();
create_test_database(db_path).await.unwrap();
let db = ThingsDatabase::new(db_path).await.unwrap();
let request = CreateAreaRequest {
title: "Empty Area".to_string(),
};
let uuid = db.create_area(request).await.unwrap();
db.delete_area(&uuid).await.unwrap();
let areas = db.get_all_areas().await.unwrap();
assert!(!areas.iter().any(|a| a.uuid == uuid));
}