use super::maybe_verify;
use crate::{
store::Store,
types::{AgentKind, Task, TaskId, TaskStatus, VerifyStatus},
};
use chrono::Local;
fn task(id: &str, status: TaskStatus, dir: Option<&str>, verify: Option<&str>) -> Task {
Task {
id: TaskId(id.to_string()),
agent: AgentKind::Codex,
custom_agent_name: None,
prompt: "prompt".to_string(),
resolved_prompt: None,
category: None,
status,
parent_task_id: None,
workgroup_id: None,
caller_kind: None,
caller_session_id: None,
agent_session_id: None,
repo_path: None,
worktree_path: dir.map(str::to_string),
worktree_branch: Some("fix/verify-gate".to_string()),
final_head_sha: None,
final_branch: None,
start_sha: None,
log_path: None,
output_path: None,
tokens: None,
prompt_tokens: None,
duration_ms: Some(10),
model: None,
cost_usd: None,
exit_code: Some(0),
created_at: Local::now(),
completed_at: Some(Local::now()),
verify: verify.map(str::to_string),
verify_status: VerifyStatus::Skipped,
pending_reason: None,
read_only: false,
budget: false,
audit_verdict: None,
audit_report_path: None,
delivery_assessment: None,
}
}
#[test]
fn configured_verify_without_working_dir_is_a_legitimate_skip() {
let store = Store::open_memory().unwrap();
let task_id = TaskId("t-verify-no-dir".to_string());
store
.insert_task(&task(task_id.as_str(), TaskStatus::Done, None, Some("true")))
.unwrap();
maybe_verify(&store, &task_id, Some("true"), None, None);
let task = store.get_task(task_id.as_str()).unwrap().unwrap();
assert_eq!(task.verify_status, VerifyStatus::Skipped);
assert_eq!(task.status, TaskStatus::Done);
assert!(store.latest_error(task_id.as_str()).is_none());
}
#[test]
fn configured_verify_spawn_failure_fails_not_skipped() {
let dir = tempfile::tempdir().unwrap();
let dir_str = dir.path().to_string_lossy().to_string();
let store = Store::open_memory().unwrap();
let task_id = TaskId("t-verify-spawn-fail".to_string());
store
.insert_task(&task(task_id.as_str(), TaskStatus::Done, Some(&dir_str), Some("missing-aid-verify-bin")))
.unwrap();
maybe_verify(&store, &task_id, Some("missing-aid-verify-bin"), Some(&dir_str), None);
let task = store.get_task(task_id.as_str()).unwrap().unwrap();
assert_eq!(task.verify_status, VerifyStatus::Failed);
assert_eq!(task.status, TaskStatus::Failed);
assert!(store.latest_error(task_id.as_str()).unwrap().contains("Failed to run verify command"));
}
#[test]
fn no_configured_verify_leaves_done_task_successful() {
let store = Store::open_memory().unwrap();
let task_id = TaskId("t-no-verify".to_string());
store
.insert_task(&task(task_id.as_str(), TaskStatus::Done, None, None))
.unwrap();
maybe_verify(&store, &task_id, None, None, None);
let task = store.get_task(task_id.as_str()).unwrap().unwrap();
assert_eq!(task.verify_status, VerifyStatus::Skipped);
assert_eq!(task.status, TaskStatus::Done);
assert_eq!(task.exit_code, Some(0));
}
#[test]
fn auto_verify_without_project_file_remains_legitimate_skip() {
let dir = tempfile::tempdir().unwrap();
let dir_str = dir.path().to_string_lossy().to_string();
let store = Store::open_memory().unwrap();
let task_id = TaskId("t-no-project".to_string());
store
.insert_task(&task(task_id.as_str(), TaskStatus::Done, Some(&dir_str), Some("auto")))
.unwrap();
maybe_verify(&store, &task_id, Some("auto"), Some(&dir_str), None);
let task = store.get_task(task_id.as_str()).unwrap().unwrap();
assert_eq!(task.verify_status, VerifyStatus::Skipped);
assert_eq!(task.status, TaskStatus::Done);
assert_eq!(task.exit_code, Some(0));
}
#[test]
fn rustc_error_does_not_emit_missing_npm_hint() {
let worktree = tempfile::tempdir().unwrap();
let dir_str = worktree.path().to_string_lossy().to_string();
let store = Store::open_memory().unwrap();
let task_id = TaskId("t-rustc-vfail".to_string());
crate::worktree_deps::prepare_worktree_dependencies(
&store,
&task_id,
worktree.path(),
worktree.path(),
None,
false,
None,
true,
Some("fix/verify-gate"),
)
.unwrap();
let script = worktree.path().join("rustc-error.sh");
std::fs::write(
&script,
"#!/bin/sh\necho 'error[E0308]: mismatched types' >&2\nexit 1\n",
)
.unwrap();
store
.insert_task(&task(task_id.as_str(), TaskStatus::Done, Some(&dir_str), Some("auto")))
.unwrap();
maybe_verify(
&store,
&task_id,
Some(&format!("sh {}", script.display())),
Some(&dir_str),
None,
);
let events = store.get_events(task_id.as_str()).unwrap();
assert!(!events.iter().any(|event| {
event.detail.contains("verify likely failed because dependencies weren't installed")
}));
}