1use super::Process;
4use crate::error::Result;
5
6pub fn apply_to_each(
12 processes: &[Process],
13 mut act: impl FnMut(&Process) -> Result<()>,
14) -> (Vec<Process>, Vec<(Process, String)>) {
15 let mut succeeded = Vec::new();
16 let mut failed = Vec::new();
17 for proc in processes {
18 match act(proc) {
19 Ok(()) => succeeded.push(proc.clone()),
20 Err(e) => failed.push((proc.clone(), e.to_string())),
21 }
22 }
23 (succeeded, failed)
24}
25
26#[cfg(test)]
27mod tests {
28 use super::*;
29 use crate::error::ProcError;
30
31 fn three() -> Vec<Process> {
33 let me = Process::find_by_pid(std::process::id())
34 .unwrap()
35 .expect("this test process");
36 (1..=3).map(|pid| Process { pid, ..me.clone() }).collect()
37 }
38
39 #[test]
40 fn sorts_each_process_by_what_the_action_did_to_it_in_order() {
41 let processes = three();
42 let (worked, failed) = apply_to_each(&processes, |p| {
43 if p.pid == 2 {
44 Err(ProcError::SignalError("no permission".to_string()))
45 } else {
46 Ok(())
47 }
48 });
49 assert_eq!(worked.iter().map(|p| p.pid).collect::<Vec<_>>(), [1, 3]);
50 assert_eq!(failed.len(), 1);
51 assert_eq!(failed[0].0.pid, 2);
52 assert_eq!(failed[0].1, "Signal failed: no permission");
53 }
54
55 #[test]
56 fn runs_the_action_once_per_process_even_after_a_failure() {
57 let processes = three();
58 let mut seen = Vec::new();
59 let (worked, failed) = apply_to_each(&processes, |p| {
60 seen.push(p.pid);
61 Err(ProcError::ProcessGone(p.pid))
62 });
63 assert_eq!(seen, [1, 2, 3]);
64 assert!(worked.is_empty());
65 assert_eq!(failed.len(), 3);
66 assert_eq!(failed[2].1, "Process 3 is no longer running");
67 }
68}