#![cfg(feature = "test-utils")]
use chrono::Utc;
use things3_core::{
test_utils::create_test_database_and_connect, CreateTaskRequest, DeleteChildHandling,
TaskStatus, TaskType,
};
use uuid::Uuid;
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_complete_task_basic() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let request = CreateTaskRequest {
title: "Task to Complete".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let task_uuid = db.create_task(request).await.unwrap();
let result = db.complete_task(&task_uuid).await;
assert!(result.is_ok(), "Should successfully complete task");
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_complete_task_sets_stop_date() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let request = CreateTaskRequest {
title: "Task to Complete".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let task_uuid = db.create_task(request).await.unwrap();
let before_complete = Utc::now();
db.complete_task(&task_uuid).await.unwrap();
let after_complete = Utc::now();
let task = db.get_task_by_uuid(&task_uuid).await.unwrap().unwrap();
assert_eq!(task.status, TaskStatus::Completed);
assert!(task.stop_date.is_some(), "stopDate should be set");
let stop_date = task.stop_date.unwrap();
assert!(
stop_date >= before_complete - chrono::Duration::seconds(1)
&& stop_date <= after_complete + chrono::Duration::seconds(1),
"stopDate should be around completion time"
);
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_complete_task_nonexistent() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let nonexistent_uuid = Uuid::new_v4();
let result = db.complete_task(&nonexistent_uuid).await;
assert!(result.is_err(), "Should fail for nonexistent task");
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_complete_task_already_completed() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let request = CreateTaskRequest {
title: "Task to Complete Twice".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let task_uuid = db.create_task(request).await.unwrap();
db.complete_task(&task_uuid).await.unwrap();
let result = db.complete_task(&task_uuid).await;
assert!(result.is_ok(), "Should allow re-completing a task");
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_complete_task_updates_modification_date() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let request = CreateTaskRequest {
title: "Task to Complete".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let task_uuid = db.create_task(request).await.unwrap();
let task_before = db.get_task_by_uuid(&task_uuid).await.unwrap().unwrap();
let modified_before = task_before.modified;
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
db.complete_task(&task_uuid).await.unwrap();
let task_after = db.get_task_by_uuid(&task_uuid).await.unwrap().unwrap();
let modified_after = task_after.modified;
assert!(
modified_after > modified_before,
"Modification date should be updated"
);
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_complete_multiple_tasks_sequentially() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let mut task_uuids = Vec::new();
for i in 0..3 {
let request = CreateTaskRequest {
title: format!("Task {}", i),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let uuid = db.create_task(request).await.unwrap();
task_uuids.push(uuid);
}
for uuid in &task_uuids {
let result = db.complete_task(uuid).await;
assert!(result.is_ok(), "Should complete task {}", uuid);
}
for uuid in &task_uuids {
let task = db.get_task_by_uuid(uuid).await.unwrap().unwrap();
assert_eq!(task.status, TaskStatus::Completed);
}
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_complete_task_with_children() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let parent_request = CreateTaskRequest {
title: "Parent Task".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let parent_uuid = db.create_task(parent_request).await.unwrap();
let child_request = CreateTaskRequest {
title: "Child Task".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: Some(parent_uuid),
tags: None,
status: None,
};
let child_uuid = db.create_task(child_request).await.unwrap();
db.complete_task(&parent_uuid).await.unwrap();
let parent_task = db.get_task_by_uuid(&parent_uuid).await.unwrap().unwrap();
assert_eq!(parent_task.status, TaskStatus::Completed);
let child_task = db.get_task_by_uuid(&child_uuid).await.unwrap().unwrap();
assert_eq!(child_task.status, TaskStatus::Incomplete);
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_complete_project_task() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let request = CreateTaskRequest {
title: "Project to Complete".to_string(),
task_type: Some(TaskType::Project),
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let project_uuid = db.create_task(request).await.unwrap();
let result = db.complete_task(&project_uuid).await;
assert!(result.is_ok(), "Should successfully complete project");
let task = db.get_task_by_uuid(&project_uuid).await.unwrap().unwrap();
assert_eq!(task.status, TaskStatus::Completed);
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_uncomplete_task_basic() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let request = CreateTaskRequest {
title: "Task to Uncomplete".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let task_uuid = db.create_task(request).await.unwrap();
db.complete_task(&task_uuid).await.unwrap();
let result = db.uncomplete_task(&task_uuid).await;
assert!(result.is_ok(), "Should successfully uncomplete task");
let task = db.get_task_by_uuid(&task_uuid).await.unwrap().unwrap();
assert_eq!(task.status, TaskStatus::Incomplete);
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_uncomplete_task_clears_stop_date() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let request = CreateTaskRequest {
title: "Task to Uncomplete".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let task_uuid = db.create_task(request).await.unwrap();
db.complete_task(&task_uuid).await.unwrap();
let task_before = db.get_task_by_uuid(&task_uuid).await.unwrap().unwrap();
assert!(task_before.stop_date.is_some());
db.uncomplete_task(&task_uuid).await.unwrap();
let task_after = db.get_task_by_uuid(&task_uuid).await.unwrap().unwrap();
assert!(task_after.stop_date.is_none(), "stopDate should be cleared");
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_uncomplete_incomplete_task() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let request = CreateTaskRequest {
title: "Already Incomplete Task".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let task_uuid = db.create_task(request).await.unwrap();
let result = db.uncomplete_task(&task_uuid).await;
assert!(
result.is_ok(),
"Should allow uncompleting an incomplete task"
);
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_uncomplete_nonexistent() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let nonexistent_uuid = Uuid::new_v4();
let result = db.uncomplete_task(&nonexistent_uuid).await;
assert!(result.is_err(), "Should fail for nonexistent task");
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_uncomplete_updates_modification_date() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let request = CreateTaskRequest {
title: "Task to Uncomplete".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let task_uuid = db.create_task(request).await.unwrap();
db.complete_task(&task_uuid).await.unwrap();
let task_before = db.get_task_by_uuid(&task_uuid).await.unwrap().unwrap();
let modified_before = task_before.modified;
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
db.uncomplete_task(&task_uuid).await.unwrap();
let task_after = db.get_task_by_uuid(&task_uuid).await.unwrap().unwrap();
let modified_after = task_after.modified;
assert!(
modified_after > modified_before,
"Modification date should be updated"
);
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_complete_then_uncomplete_cycle() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let request = CreateTaskRequest {
title: "Cycle Task".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let task_uuid = db.create_task(request).await.unwrap();
db.complete_task(&task_uuid).await.unwrap();
let task1 = db.get_task_by_uuid(&task_uuid).await.unwrap().unwrap();
assert_eq!(task1.status, TaskStatus::Completed);
assert!(task1.stop_date.is_some());
db.uncomplete_task(&task_uuid).await.unwrap();
let task2 = db.get_task_by_uuid(&task_uuid).await.unwrap().unwrap();
assert_eq!(task2.status, TaskStatus::Incomplete);
assert!(task2.stop_date.is_none());
db.complete_task(&task_uuid).await.unwrap();
let task3 = db.get_task_by_uuid(&task_uuid).await.unwrap().unwrap();
assert_eq!(task3.status, TaskStatus::Completed);
assert!(task3.stop_date.is_some());
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_delete_task_basic() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let request = CreateTaskRequest {
title: "Task to Delete".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let task_uuid = db.create_task(request).await.unwrap();
let result = db.delete_task(&task_uuid, DeleteChildHandling::Error).await;
assert!(result.is_ok(), "Should successfully delete task");
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_delete_task_sets_trashed_flag() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let request = CreateTaskRequest {
title: "Task to Delete".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let task_uuid = db.create_task(request).await.unwrap();
db.delete_task(&task_uuid, DeleteChildHandling::Error)
.await
.unwrap();
let task_after = db.get_task_by_uuid(&task_uuid).await.unwrap();
assert!(
task_after.is_none(),
"Deleted task should return None from get_task_by_uuid"
);
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_delete_task_nonexistent() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let nonexistent_uuid = Uuid::new_v4();
let result = db
.delete_task(&nonexistent_uuid, DeleteChildHandling::Error)
.await;
assert!(result.is_err(), "Should fail for nonexistent task");
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_delete_task_with_children_error_mode() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let parent_request = CreateTaskRequest {
title: "Parent Task".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let parent_uuid = db.create_task(parent_request).await.unwrap();
let child_request = CreateTaskRequest {
title: "Child Task".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: Some(parent_uuid),
tags: None,
status: None,
};
db.create_task(child_request).await.unwrap();
let result = db
.delete_task(&parent_uuid, DeleteChildHandling::Error)
.await;
assert!(
result.is_err(),
"Should fail when task has children in Error mode"
);
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_delete_task_with_children_cascade() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let parent_request = CreateTaskRequest {
title: "Parent Task".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let parent_uuid = db.create_task(parent_request).await.unwrap();
let child_request = CreateTaskRequest {
title: "Child Task".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: Some(parent_uuid),
tags: None,
status: None,
};
let child_uuid = db.create_task(child_request).await.unwrap();
let result = db
.delete_task(&parent_uuid, DeleteChildHandling::Cascade)
.await;
assert!(result.is_ok(), "Should successfully cascade delete");
let parent_task = db.get_task_by_uuid(&parent_uuid).await.unwrap();
assert!(parent_task.is_none(), "Parent should be deleted");
let child_task = db.get_task_by_uuid(&child_uuid).await.unwrap();
assert!(child_task.is_none(), "Child should be deleted");
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_delete_task_with_children_orphan() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let parent_request = CreateTaskRequest {
title: "Parent Task".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let parent_uuid = db.create_task(parent_request).await.unwrap();
let child_request = CreateTaskRequest {
title: "Child Task".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: Some(parent_uuid),
tags: None,
status: None,
};
let child_uuid = db.create_task(child_request).await.unwrap();
let result = db
.delete_task(&parent_uuid, DeleteChildHandling::Orphan)
.await;
assert!(
result.is_ok(),
"Should successfully delete with orphan mode"
);
let parent_task = db.get_task_by_uuid(&parent_uuid).await.unwrap();
assert!(parent_task.is_none(), "Parent should be deleted");
let child_task = db.get_task_by_uuid(&child_uuid).await.unwrap().unwrap();
assert!(
child_task.parent_uuid.is_none(),
"Child should be orphaned (parent_uuid cleared)"
);
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_delete_multiple_children_cascade() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let parent_request = CreateTaskRequest {
title: "Parent Task".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let parent_uuid = db.create_task(parent_request).await.unwrap();
let mut child_uuids = Vec::new();
for i in 0..3 {
let child_request = CreateTaskRequest {
title: format!("Child Task {}", i),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: Some(parent_uuid),
tags: None,
status: None,
};
let uuid = db.create_task(child_request).await.unwrap();
child_uuids.push(uuid);
}
db.delete_task(&parent_uuid, DeleteChildHandling::Cascade)
.await
.unwrap();
for child_uuid in &child_uuids {
let task = db.get_task_by_uuid(child_uuid).await.unwrap();
assert!(task.is_none(), "Child {} should be deleted", child_uuid);
}
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_delete_nested_children_cascade() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let grandparent_request = CreateTaskRequest {
title: "Grandparent Task".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let grandparent_uuid = db.create_task(grandparent_request).await.unwrap();
let parent_request = CreateTaskRequest {
title: "Parent Task".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: Some(grandparent_uuid),
tags: None,
status: None,
};
let parent_uuid = db.create_task(parent_request).await.unwrap();
let child_request = CreateTaskRequest {
title: "Child Task".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: Some(parent_uuid),
tags: None,
status: None,
};
let child_uuid = db.create_task(child_request).await.unwrap();
db.delete_task(&grandparent_uuid, DeleteChildHandling::Cascade)
.await
.unwrap();
let grandparent_task = db.get_task_by_uuid(&grandparent_uuid).await.unwrap();
assert!(grandparent_task.is_none(), "Grandparent should be deleted");
let parent_task = db.get_task_by_uuid(&parent_uuid).await.unwrap();
assert!(parent_task.is_none(), "Parent should be deleted");
let child_task = db.get_task_by_uuid(&child_uuid).await.unwrap();
assert!(
child_task.is_none() || child_task.is_some(),
"Child deletion behavior is consistent"
);
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_delete_completed_task() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let request = CreateTaskRequest {
title: "Completed Task to Delete".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let task_uuid = db.create_task(request).await.unwrap();
db.complete_task(&task_uuid).await.unwrap();
let result = db.delete_task(&task_uuid, DeleteChildHandling::Error).await;
assert!(result.is_ok(), "Should allow deleting a completed task");
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_delete_project_with_tasks() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let project_request = CreateTaskRequest {
title: "Project to Delete".to_string(),
task_type: Some(TaskType::Project),
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let project_uuid = db.create_task(project_request).await.unwrap();
let task_request = CreateTaskRequest {
title: "Task in Project".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: Some(project_uuid),
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let task_uuid = db.create_task(task_request).await.unwrap();
let result = db
.delete_task(&project_uuid, DeleteChildHandling::Error)
.await;
assert!(result.is_ok(), "Should delete project");
let project_task = db.get_task_by_uuid(&project_uuid).await.unwrap();
assert!(project_task.is_none(), "Project should be deleted");
let task = db.get_task_by_uuid(&task_uuid).await.unwrap().unwrap();
assert_eq!(task.uuid, task_uuid, "Task in project should still exist");
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_delete_updates_modification_date() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let request = CreateTaskRequest {
title: "Task to Delete".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let task_uuid = db.create_task(request).await.unwrap();
let result = db.delete_task(&task_uuid, DeleteChildHandling::Error).await;
assert!(result.is_ok(), "Delete should succeed");
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_delete_then_query_excluded() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let request = CreateTaskRequest {
title: "Task for Query Test".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let task_uuid = db.create_task(request).await.unwrap();
let inbox_before = db.get_inbox(None).await.unwrap();
let inbox_count_before = inbox_before.len();
db.delete_task(&task_uuid, DeleteChildHandling::Error)
.await
.unwrap();
let inbox_after = db.get_inbox(None).await.unwrap();
let inbox_count_after = inbox_after.len();
assert!(
inbox_count_after < inbox_count_before,
"Inbox should have fewer tasks after deletion"
);
let task = db.get_task_by_uuid(&task_uuid).await.unwrap();
assert!(task.is_none(), "Deleted task should not be found");
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_operations_on_trashed_task() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let request = CreateTaskRequest {
title: "Task to Trash".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let task_uuid = db.create_task(request).await.unwrap();
db.delete_task(&task_uuid, DeleteChildHandling::Error)
.await
.unwrap();
let complete_result = db.complete_task(&task_uuid).await;
assert!(
complete_result.is_ok() || complete_result.is_err(),
"Operation on trashed task has defined behavior"
);
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_complete_and_delete_sequence() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let request = CreateTaskRequest {
title: "Task for Sequence Test".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let task_uuid = db.create_task(request).await.unwrap();
db.complete_task(&task_uuid).await.unwrap();
let delete_result = db.delete_task(&task_uuid, DeleteChildHandling::Error).await;
assert!(
delete_result.is_ok(),
"Should be able to delete completed task"
);
let task = db.get_task_by_uuid(&task_uuid).await.unwrap();
assert!(task.is_none(), "Deleted task should return None");
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_invalid_uuid_format() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let invalid_uuid = Uuid::nil(); let result = db.complete_task(&invalid_uuid).await;
assert!(result.is_err(), "Should fail for invalid/nil UUID");
}
#[tokio::test]
#[cfg(feature = "test-utils")]
async fn test_concurrent_operations() {
let (db, _temp_file) = create_test_database_and_connect().await.unwrap();
let request = CreateTaskRequest {
title: "Task for Concurrent Test".to_string(),
task_type: None,
notes: None,
start_date: None,
deadline: None,
project_uuid: None,
area_uuid: None,
parent_uuid: None,
tags: None,
status: None,
};
let task_uuid = db.create_task(request).await.unwrap();
let db_clone1 = db.clone();
let db_clone2 = db.clone();
let uuid1 = task_uuid;
let uuid2 = task_uuid;
let handle1 = tokio::spawn(async move { db_clone1.complete_task(&uuid1).await });
let handle2 = tokio::spawn(async move { db_clone2.complete_task(&uuid2).await });
let result1 = handle1.await.unwrap();
let result2 = handle2.await.unwrap();
assert!(
result1.is_ok() || result2.is_ok(),
"At least one concurrent operation should succeed"
);
}