1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
use std::result::Result; use errors::{Error, ErrorKind, ResultExt}; pub trait CumulativeErrorCollector<R> { fn collect_if_no_errors(self) -> Result<Vec<R>, Error>; } impl<T, R, E> CumulativeErrorCollector<R> for T where T: Iterator<Item=Result<R, E>>, E: Into<Error> { fn collect_if_no_errors(self) -> Result<Vec<R>, Error> { let mut results = Vec::new(); let mut errors = Vec::new(); for item in self { match item { Ok(item) => results.push(item), Err(err) => errors.push(err.into()) } } if errors.is_empty() { return Ok(results) } Err(ErrorKind::CumulativeError(errors).into()) } } #[cfg(test)] mod tests { use super::*; use std::fmt::Debug; #[test] fn returns_ok_when_all_results_were_ok() { let results: Vec<Result<(), Error>> = vec![Ok(()), Ok(()), Ok(())]; let actual = results.into_iter().collect_if_no_errors(); assert!(actual.is_ok()) } #[test] fn returns_error_if_there_is_one_error() { let results: Vec<Result<(), Error>> = vec![Ok(()), Err("dummy".into()), Ok(())]; let actual = results.into_iter().collect_if_no_errors(); assert!(actual.is_err()); } #[test] fn returns_cumulative_error_if_there_is_one_error() { let results: Vec<Result<(), Error>> = vec![Ok(()), Err("dummy".into()), Ok(())]; let actual = results.into_iter().collect_if_no_errors(); assert_error( "1 error(s) occured:\n".to_owned() + "Error no. 1: dummy\n", actual ); } #[test] fn returns_cumulative_errors_if_there_are_three_error() { let results: Vec<Result<(), Error>> = vec![Err("first".into()), Err("other".into()), Err("last".into())]; let actual = results.into_iter().collect_if_no_errors(); assert_error( "3 error(s) occured:\n".to_owned() + "Error no. 1: first\n" + "Error no. 2: other\n" + "Error no. 3: last\n", actual ); } #[test] fn returns_cumulative_error_with_cause() {; let results = vec![ (Err("root cause".into()) as Result<(), Error>) .chain_err(|| "intermediate cause") .chain_err(|| "error") ]; let actual = results.into_iter().collect_if_no_errors(); assert_error( "1 error(s) occured:\n".to_owned() + "Error no. 1: error\n" + " caused by: intermediate cause\n" + " caused by: root cause\n", actual ); } #[test] fn returns_cause_for_every_inner_error() {; let results = vec![ (Err("first cause".into()) as Result<(), Error>) .chain_err(|| "first error"), (Err("second cause".into()) as Result<(), Error>) .chain_err(|| "second error"), ]; let actual = results.into_iter().collect_if_no_errors(); assert_error( "2 error(s) occured:\n".to_owned() + "Error no. 1: first error\n" + " caused by: first cause\n" + "Error no. 2: second error\n" + " caused by: second cause\n", actual ); } fn assert_error<T: Debug>(expected: String, result: Result<T, Error>) { let actual = format!("{}", result.unwrap_err()); assert_eq!(expected, actual) } }