use serde_json::{json, Value};
use things3_cli::mcp::test_harness::McpTestHarness;
fn create_harness() -> McpTestHarness {
McpTestHarness::new()
}
fn parse_tool_result(result: &things3_cli::mcp::CallToolResult) -> Value {
if result.is_error {
match &result.content[0] {
things3_cli::mcp::Content::Text { text } => {
serde_json::from_str(text).unwrap_or(json!({"error": text}))
}
}
} else {
match &result.content[0] {
things3_cli::mcp::Content::Text { text } => {
serde_json::from_str(text).unwrap_or(json!({"text": text}))
}
}
}
}
#[tokio::test]
async fn test_create_task_mcp_date_validation_error() {
let harness = create_harness();
let result = harness
.call_tool_with_fallback(
"create_task",
Some(json!({
"title": "Invalid dates task",
"start_date": "2024-12-31",
"deadline": "2024-01-01"
})),
)
.await;
assert!(result.is_error, "Expected error result for invalid dates");
let response = parse_tool_result(&result);
let error_msg = response.to_string().to_lowercase();
assert!(
error_msg.contains("deadline") || error_msg.contains("date"),
"Error message should mention date validation issue: {error_msg}"
);
}
#[tokio::test]
async fn test_update_task_mcp_date_validation_error() {
let harness = create_harness();
let create_result = harness
.call_tool(
"create_task",
Some(json!({
"title": "Test task"
})),
)
.await;
assert!(!create_result.is_error, "Task creation should succeed");
let create_response = parse_tool_result(&create_result);
let task_uuid = create_response["uuid"]
.as_str()
.expect("Should have UUID in response");
let result = harness
.call_tool_with_fallback(
"update_task",
Some(json!({
"uuid": task_uuid,
"start_date": "2024-12-31",
"deadline": "2024-01-01"
})),
)
.await;
assert!(result.is_error, "Expected error result for invalid dates");
let response = parse_tool_result(&result);
let error_msg = response.to_string().to_lowercase();
assert!(
error_msg.contains("deadline") || error_msg.contains("date"),
"Error message should mention date validation issue: {error_msg}"
);
}
#[tokio::test]
async fn test_create_project_mcp_date_validation() {
let harness = create_harness();
let result = harness
.call_tool_with_fallback(
"create_project",
Some(json!({
"title": "Invalid dates project",
"start_date": "2024-12-31",
"deadline": "2024-01-01"
})),
)
.await;
assert!(result.is_error, "Expected error result for invalid dates");
let response = parse_tool_result(&result);
let error_msg = response.to_string().to_lowercase();
assert!(
error_msg.contains("deadline") || error_msg.contains("date"),
"Error message should mention date validation issue: {error_msg}"
);
}
#[tokio::test]
async fn test_date_error_messages_are_clear() {
let harness = create_harness();
let result = harness
.call_tool_with_fallback(
"create_task",
Some(json!({
"title": "Test task",
"start_date": "2024-06-15",
"deadline": "2024-01-01" })),
)
.await;
assert!(result.is_error, "Expected error for invalid dates");
let response = parse_tool_result(&result);
let error_msg = response.to_string();
assert!(
error_msg.contains("2024-06-15") || error_msg.contains("2024-01-01"),
"Error message should include the actual dates: {error_msg}"
);
assert!(
error_msg.contains("before") || error_msg.contains("after"),
"Error message should explain the relationship: {error_msg}"
);
}
#[tokio::test]
async fn test_create_task_with_valid_dates_mcp() {
let harness = create_harness();
let result = harness
.call_tool(
"create_task",
Some(json!({
"title": "Valid dates task",
"start_date": "2024-01-01",
"deadline": "2024-12-31"
})),
)
.await;
assert!(
!result.is_error,
"Task creation with valid dates should succeed"
);
let response = parse_tool_result(&result);
assert!(
response["uuid"].is_string(),
"Should return task UUID on success"
);
}
#[tokio::test]
async fn test_update_task_dates_mcp() {
let harness = create_harness();
let create_result = harness
.call_tool(
"create_task",
Some(json!({
"title": "Test task"
})),
)
.await;
assert!(!create_result.is_error, "Task creation should succeed");
let create_response = parse_tool_result(&create_result);
let task_uuid = create_response["uuid"]
.as_str()
.expect("Should have UUID in response");
let result = harness
.call_tool(
"update_task",
Some(json!({
"uuid": task_uuid,
"start_date": "2024-01-01",
"deadline": "2024-12-31"
})),
)
.await;
assert!(
!result.is_error,
"Task update with valid dates should succeed"
);
}
#[tokio::test]
async fn test_same_date_for_start_and_deadline_is_valid() {
let harness = create_harness();
let result = harness
.call_tool(
"create_task",
Some(json!({
"title": "Same date task",
"start_date": "2024-06-15",
"deadline": "2024-06-15"
})),
)
.await;
assert!(
!result.is_error,
"Task creation with same start and deadline date should succeed"
);
}
#[tokio::test]
async fn test_only_deadline_no_start_date_is_valid() {
let harness = create_harness();
let result = harness
.call_tool(
"create_task",
Some(json!({
"title": "Only deadline task",
"deadline": "2024-12-31"
})),
)
.await;
assert!(
!result.is_error,
"Task creation with only deadline should succeed"
);
}
#[tokio::test]
async fn test_only_start_date_no_deadline_is_valid() {
let harness = create_harness();
let result = harness
.call_tool(
"create_task",
Some(json!({
"title": "Only start date task",
"start_date": "2024-01-01"
})),
)
.await;
assert!(
!result.is_error,
"Task creation with only start date should succeed"
);
}
#[tokio::test]
async fn test_update_only_deadline_validates_with_existing_start() {
let harness = create_harness();
let create_result = harness
.call_tool(
"create_task",
Some(json!({
"title": "Test task",
"start_date": "2024-06-15"
})),
)
.await;
assert!(!create_result.is_error, "Task creation should succeed");
let create_response = parse_tool_result(&create_result);
let task_uuid = create_response["uuid"]
.as_str()
.expect("Should have UUID in response");
let result = harness
.call_tool_with_fallback(
"update_task",
Some(json!({
"uuid": task_uuid,
"deadline": "2024-01-01" })),
)
.await;
assert!(
result.is_error,
"Updating deadline to before existing start date should fail"
);
}
#[tokio::test]
async fn test_update_only_start_date_validates_with_existing_deadline() {
let harness = create_harness();
let create_result = harness
.call_tool(
"create_task",
Some(json!({
"title": "Test task",
"deadline": "2024-06-15"
})),
)
.await;
assert!(!create_result.is_error, "Task creation should succeed");
let create_response = parse_tool_result(&create_result);
let task_uuid = create_response["uuid"]
.as_str()
.expect("Should have UUID in response");
let result = harness
.call_tool_with_fallback(
"update_task",
Some(json!({
"uuid": task_uuid,
"start_date": "2024-12-31" })),
)
.await;
assert!(
result.is_error,
"Updating start date to after existing deadline should fail"
);
}