use saorsa_gossip_types::PeerId;
use x0x::crdt::{TaskId, TaskItem, TaskList, TaskListId, TaskMetadata};
use x0x::identity::AgentId;
fn test_agent_id(n: u8) -> AgentId {
AgentId([n; 32])
}
fn test_peer_id(n: u8) -> PeerId {
let mut bytes = [0u8; 32];
bytes[0] = n;
PeerId::new(bytes)
}
fn test_task_id(n: u8) -> TaskId {
let mut bytes = [0u8; 32];
bytes[0] = n;
TaskId::from_bytes(bytes)
}
fn test_task_list_id(n: u8) -> TaskListId {
let mut bytes = [0u8; 32];
bytes[0] = n;
TaskListId::new(bytes)
}
fn test_metadata(title: &str, creator: u8) -> TaskMetadata {
TaskMetadata {
title: title.to_string(),
description: format!("Test task: {}", title),
priority: 128,
created_by: test_agent_id(creator),
owner: None,
created_at: 1000 + creator as u64,
tags: vec!["test".to_string()],
}
}
#[test]
fn test_task_list_creation() {
let list_id = test_task_list_id(1);
let peer_id = test_peer_id(1);
let task_list = TaskList::new(list_id, "My Tasks".to_string(), peer_id);
assert_eq!(task_list.name(), "My Tasks");
assert_eq!(task_list.version(), 0);
assert_eq!(task_list.tasks_ordered().len(), 0);
}
#[test]
fn test_task_list_add_task() {
let list_id = test_task_list_id(1);
let task_id = test_task_id(1);
let peer_id = test_peer_id(1);
let agent_id = test_agent_id(1);
let mut task_list = TaskList::new(list_id, "Sprint".to_string(), peer_id);
let metadata = test_metadata("Implement feature", agent_id.as_bytes()[0]);
let task = TaskItem::new(task_id, metadata, peer_id);
let result = task_list.add_task(task, peer_id, 1);
assert!(result.is_ok());
assert_eq!(task_list.tasks_ordered().len(), 1);
}
#[test]
fn test_task_list_claim_task() {
let list_id = test_task_list_id(1);
let task_id = test_task_id(1);
let peer_id = test_peer_id(1);
let agent_id = test_agent_id(1);
let mut task_list = TaskList::new(list_id, "Sprint".to_string(), peer_id);
let metadata = test_metadata("Write code", agent_id.as_bytes()[0]);
let task = TaskItem::new(task_id, metadata, peer_id);
task_list
.add_task(task, peer_id, 1)
.expect("Failed to add task");
let claim_result = task_list.claim_task(&task_id, agent_id, peer_id, 2);
assert!(claim_result.is_ok());
let task = task_list.get_task(&task_id).expect("Task should exist");
assert!(task.current_state().is_claimed());
}
#[test]
fn test_task_list_complete_task() {
let list_id = test_task_list_id(1);
let task_id = test_task_id(1);
let peer_id = test_peer_id(1);
let agent_id = test_agent_id(1);
let mut task_list = TaskList::new(list_id, "Sprint".to_string(), peer_id);
let metadata = test_metadata("Test code", agent_id.as_bytes()[0]);
let task = TaskItem::new(task_id, metadata, peer_id);
task_list
.add_task(task, peer_id, 1)
.expect("Failed to add task");
task_list
.claim_task(&task_id, agent_id, peer_id, 2)
.expect("Failed to claim task");
let complete_result = task_list.complete_task(&task_id, agent_id, peer_id, 3);
assert!(complete_result.is_ok());
let task = task_list.get_task(&task_id).expect("Task should exist");
assert!(task.current_state().is_done());
}
#[test]
fn test_task_list_remove_task() {
let list_id = test_task_list_id(1);
let task_id = test_task_id(1);
let peer_id = test_peer_id(1);
let agent_id = test_agent_id(1);
let mut task_list = TaskList::new(list_id, "Sprint".to_string(), peer_id);
let metadata = test_metadata("Cleanup", agent_id.as_bytes()[0]);
let task = TaskItem::new(task_id, metadata, peer_id);
task_list
.add_task(task, peer_id, 1)
.expect("Failed to add task");
assert_eq!(task_list.tasks_ordered().len(), 1);
let remove_result = task_list.remove_task(&task_id);
assert!(remove_result.is_ok());
assert_eq!(task_list.tasks_ordered().len(), 0);
}
#[test]
fn test_task_list_reorder() {
let list_id = test_task_list_id(1);
let peer_id = test_peer_id(1);
let agent_id = test_agent_id(1);
let mut task_list = TaskList::new(list_id, "Sprint".to_string(), peer_id);
let task_ids: Vec<TaskId> = vec![test_task_id(1), test_task_id(2), test_task_id(3)];
for (i, task_id) in task_ids.iter().enumerate() {
let metadata = test_metadata(&format!("Task {}", i), agent_id.as_bytes()[0]);
let task = TaskItem::new(*task_id, metadata, peer_id);
task_list
.add_task(task, peer_id, (i + 1) as u64)
.expect("Failed to add task");
}
assert_eq!(task_list.tasks_ordered().len(), 3);
let new_order = vec![task_ids[2], task_ids[1], task_ids[0]];
let reorder_result = task_list.reorder(new_order.clone(), peer_id);
assert!(reorder_result.is_ok());
let ordered = task_list.tasks_ordered();
assert_eq!(ordered[0].id(), &task_ids[2]);
assert_eq!(ordered[1].id(), &task_ids[1]);
assert_eq!(ordered[2].id(), &task_ids[0]);
}
#[test]
fn test_task_list_merge() {
let list_id = test_task_list_id(1);
let peer_id_a = test_peer_id(1);
let peer_id_b = test_peer_id(2);
let agent_id_a = test_agent_id(1);
let _agent_id_b = test_agent_id(2);
let mut task_list_a = TaskList::new(list_id, "Sprint".to_string(), peer_id_a);
let task_id = test_task_id(1);
let metadata = test_metadata("Sync test", agent_id_a.as_bytes()[0]);
let task = TaskItem::new(task_id, metadata, peer_id_a);
task_list_a
.add_task(task, peer_id_a, 1)
.expect("Failed to add");
let mut task_list_b = TaskList::new(list_id, "Sprint".to_string(), peer_id_b);
let merge_result = task_list_a.merge(&task_list_b);
assert!(merge_result.is_ok());
assert_eq!(task_list_a.tasks_ordered().len(), 1);
let merge_result = task_list_b.merge(&task_list_a);
assert!(merge_result.is_ok());
assert_eq!(task_list_b.tasks_ordered().len(), 1);
assert_eq!(
task_list_a.tasks_ordered().len(),
task_list_b.tasks_ordered().len()
);
}
#[test]
fn test_concurrent_claims() {
let list_id = test_task_list_id(1);
let task_id = test_task_id(1);
let peer_id_a = test_peer_id(1);
let peer_id_b = test_peer_id(2);
let agent_id_a = test_agent_id(1);
let _agent_id_b = test_agent_id(2);
let mut task_list = TaskList::new(list_id, "Sprint".to_string(), peer_id_a);
let metadata = test_metadata("Claim test", agent_id_a.as_bytes()[0]);
let task = TaskItem::new(task_id, metadata, peer_id_a);
task_list
.add_task(task, peer_id_a, 1)
.expect("Failed to add");
task_list
.claim_task(&task_id, agent_id_a, peer_id_a, 2)
.expect("A should claim");
task_list
.claim_task(&task_id, _agent_id_b, peer_id_b, 2)
.expect("B should claim");
let task = task_list.get_task(&task_id).expect("Task should exist");
assert!(task.current_state().is_claimed());
}
#[test]
fn test_delta_generation() {
let list_id = test_task_list_id(1);
let task_id = test_task_id(1);
let peer_id = test_peer_id(1);
let agent_id = test_agent_id(1);
let mut task_list = TaskList::new(list_id, "Sprint".to_string(), peer_id);
let metadata = test_metadata("Delta test", agent_id.as_bytes()[0]);
let task = TaskItem::new(task_id, metadata, peer_id);
task_list.add_task(task, peer_id, 1).expect("Failed to add");
let delta = task_list.delta(0);
assert!(delta.is_some());
let delta = delta.unwrap();
assert!(!delta.added_tasks.is_empty());
}
#[test]
fn test_delta_apply() {
let list_id = test_task_list_id(1);
let task_id = test_task_id(1);
let peer_id = test_peer_id(1);
let agent_id = test_agent_id(1);
let mut task_list_1 = TaskList::new(list_id, "Sprint".to_string(), peer_id);
let metadata = test_metadata("Delta apply test", agent_id.as_bytes()[0]);
let task = TaskItem::new(task_id, metadata, peer_id);
task_list_1
.add_task(task, peer_id, 1)
.expect("Failed to add");
let mut task_list_2 = TaskList::new(list_id, "Sprint".to_string(), peer_id);
let apply_result = task_list_2.merge(&task_list_1);
assert!(apply_result.is_ok());
assert_eq!(task_list_2.tasks_ordered().len(), 1);
}
#[test]
fn test_version_tracking() {
let list_id = test_task_list_id(1);
let peer_id = test_peer_id(1);
let agent_id = test_agent_id(1);
let mut task_list = TaskList::new(list_id, "Sprint".to_string(), peer_id);
let initial_version = task_list.version();
let task_id = test_task_id(1);
let metadata = test_metadata("Version test", agent_id.as_bytes()[0]);
let task = TaskItem::new(task_id, metadata, peer_id);
task_list.add_task(task, peer_id, 1).expect("Failed to add");
let version_after_add = task_list.version();
assert!(version_after_add >= initial_version);
task_list
.claim_task(&task_id, agent_id, peer_id, 2)
.expect("Failed to claim");
let version_after_claim = task_list.version();
assert!(version_after_claim >= version_after_add);
}
#[test]
fn test_update_task_list_name_single() {
let list_id = test_task_list_id(1);
let task_id = test_task_id(1);
let peer_id = test_peer_id(1);
let agent_id = test_agent_id(1);
let mut task_list = TaskList::new(list_id, "Original Sprint".to_string(), peer_id);
let metadata = test_metadata("Test task", agent_id.as_bytes()[0]);
let task = TaskItem::new(task_id, metadata, peer_id);
task_list.add_task(task, peer_id, 1).expect("Failed to add");
task_list.update_name("Updated Sprint".to_string(), peer_id);
assert_eq!(task_list.name(), "Updated Sprint");
}
#[test]
fn test_invalid_state_transitions() {
let list_id = test_task_list_id(1);
let task_id = test_task_id(1);
let peer_id = test_peer_id(1);
let agent_id = test_agent_id(1);
let mut task_list = TaskList::new(list_id, "Sprint".to_string(), peer_id);
let metadata = test_metadata("State test", agent_id.as_bytes()[0]);
let task = TaskItem::new(task_id, metadata, peer_id);
task_list.add_task(task, peer_id, 1).expect("Failed to add");
let result = task_list.complete_task(&task_id, agent_id, peer_id, 2);
assert!(result.is_err());
}
#[test]
fn test_merge_conflict_resolution() {
let list_id = test_task_list_id(1);
let task_id = test_task_id(1);
let peer_id_a = test_peer_id(1);
let peer_id_b = test_peer_id(2);
let agent_id_a = test_agent_id(1);
let agent_id_b = test_agent_id(2);
let mut task_list_a = TaskList::new(list_id, "Sprint A".to_string(), peer_id_a);
let metadata_a = test_metadata("Title A", agent_id_a.as_bytes()[0]);
let task_a = TaskItem::new(task_id, metadata_a, peer_id_a);
task_list_a
.add_task(task_a, peer_id_a, 1)
.expect("Failed to add");
let mut task_list_b = TaskList::new(list_id, "Sprint B".to_string(), peer_id_b);
let metadata_b = test_metadata("Title B", agent_id_b.as_bytes()[0]);
let task_b = TaskItem::new(task_id, metadata_b, peer_id_b);
task_list_b
.add_task(task_b, peer_id_b, 1)
.expect("Failed to add");
let merge_result = task_list_a.merge(&task_list_b);
assert!(merge_result.is_ok());
assert_eq!(task_list_a.tasks_ordered().len(), 1);
}
#[test]
fn test_large_task_list() {
let list_id = test_task_list_id(1);
let peer_id = test_peer_id(1);
let agent_id = test_agent_id(1);
let mut task_list = TaskList::new(list_id, "Large Sprint".to_string(), peer_id);
let task_count = 100;
for i in 0..task_count {
let task_id = TaskId::from_bytes({
let mut bytes = [0u8; 32];
bytes[0..4].copy_from_slice(&(i as u32).to_le_bytes());
bytes
});
let metadata = test_metadata(&format!("Task {}", i), agent_id.as_bytes()[0]);
let task = TaskItem::new(task_id, metadata, peer_id);
let add_result = task_list.add_task(task, peer_id, (i + 1) as u64);
assert!(add_result.is_ok(), "Failed to add task {}", i);
}
assert_eq!(task_list.tasks_ordered().len(), task_count);
let ordered = task_list.tasks_ordered();
assert!(ordered.len() >= 50);
}
#[test]
fn test_update_task_list_name_conflict() {
let list_id = test_task_list_id(1);
let peer_id_a = test_peer_id(1);
let peer_id_b = test_peer_id(2);
let mut task_list_a = TaskList::new(list_id, "Sprint A".to_string(), peer_id_a);
let mut task_list_b = TaskList::new(list_id, "Sprint B".to_string(), peer_id_b);
task_list_a.update_name("Updated A".to_string(), peer_id_a);
task_list_b.update_name("Updated B".to_string(), peer_id_b);
task_list_a.merge(&task_list_b).expect("Merge should work");
let name = task_list_a.name();
assert!(name == "Updated A" || name == "Updated B");
}