use crate::contracts::Task;
pub fn for_each_searchable_text<F>(task: &Task, mut f: F)
where
F: FnMut(&str),
{
f(&task.title);
task.evidence.iter().for_each(|e| f(e));
task.plan.iter().for_each(|p| f(p));
task.notes.iter().for_each(|n| f(n));
if let Some(req) = &task.request {
f(req);
}
task.tags.iter().for_each(|t| f(t));
task.scope.iter().for_each(|s| f(s));
task.custom_fields.iter().for_each(|(k, v)| {
f(k);
f(v);
});
}
#[cfg(test)]
mod tests {
use super::*;
use crate::contracts::{Task, TaskStatus};
use std::collections::HashMap;
fn test_task() -> Task {
Task {
id: "RQ-0001".to_string(),
status: TaskStatus::Todo,
title: "Test title".to_string(),
description: None,
priority: Default::default(),
tags: vec!["tag1".to_string(), "tag2".to_string()],
scope: vec!["scope1".to_string()],
evidence: vec!["evidence1".to_string()],
plan: vec!["plan1".to_string(), "plan2".to_string()],
notes: vec!["note1".to_string()],
request: Some("request text".to_string()),
agent: None,
created_at: Some("2026-01-18T00:00:00Z".to_string()),
updated_at: Some("2026-01-18T00:00:00Z".to_string()),
completed_at: None,
started_at: None,
scheduled_start: None,
estimated_minutes: None,
actual_minutes: None,
depends_on: vec![],
blocks: vec![],
relates_to: vec![],
duplicates: None,
custom_fields: {
let mut m = HashMap::new();
m.insert("key1".to_string(), "value1".to_string());
m
},
parent_id: None,
}
}
#[test]
fn for_each_collects_all_fields() {
let task = test_task();
let mut collected = Vec::new();
for_each_searchable_text(&task, |text| collected.push(text.to_string()));
assert_eq!(collected.len(), 11);
assert!(collected.contains(&"Test title".to_string()));
assert!(collected.contains(&"evidence1".to_string()));
assert!(collected.contains(&"plan1".to_string()));
assert!(collected.contains(&"plan2".to_string()));
assert!(collected.contains(&"note1".to_string()));
assert!(collected.contains(&"request text".to_string()));
assert!(collected.contains(&"tag1".to_string()));
assert!(collected.contains(&"tag2".to_string()));
assert!(collected.contains(&"scope1".to_string()));
assert!(collected.contains(&"key1".to_string()));
assert!(collected.contains(&"value1".to_string()));
}
#[test]
fn for_each_handles_empty_optional_fields() {
let mut task = test_task();
task.request = None;
task.evidence.clear();
task.custom_fields.clear();
let mut count = 0;
for_each_searchable_text(&task, |_| count += 1);
assert_eq!(count, 7);
}
}