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
// This macro is useful for writing tests that deal with errors. It takes an expression of type
// `Result<_, Vec<Error>>` and a search string and asserts that the expressions evaluates to an
// `Err(_)` and that the string representation of at least one of the errors contains the given
// search string.
#[macro_export]
macro_rules! assert_fails {
($expr:expr, $search_str:expr $(,)?) => {{
// Macros are call-by-name, but we want call-by-value (or at least call-by-need) to avoid
// accidentally evaluating arguments multiple times. Here we force eager evaluation.
let expr = $expr;
let search_str = $search_str;
// Check that `$expr` fails and that the failure contains `$search_str`.
if let Err(errors) = expr {
let mut found_error = false;
let mut all_errors_string = "".to_owned();
for error in &errors {
let error_string = error.to_string();
let _ = write!(all_errors_string, "{}\n", error_string);
if error_string.contains(search_str) {
found_error = true;
}
}
assert!(
found_error,
"The expression failed as expected, but the expected message wasn't found in \
any of the errors: {:?}.",
errors,
);
} else {
panic!("The expression was supposed to fail, but it succeeded.");
}
}};
}
// This macro is useful for writing equality tests for types that implement `Debug` but not `Eq`.
// It asserts that the debug representations of the two given expressions match.
#[macro_export]
macro_rules! assert_same {
($expr1:expr, $expr2:expr $(,)?) => {{
// Macros are call-by-name, but we want call-by-value (or at least call-by-need) to avoid
// accidentally evaluating arguments multiple times. Here we force eager evaluation.
let expr1 = $expr1;
let expr2 = $expr2;
// To aid in type inference, the following tells the compiler that the two expressions have
// the same type.
let mut _dummy = &expr1;
_dummy = &expr2;
// Assert that the expressions have the same debug representation.
assert_eq!(format!("{:?}", expr1), format!("{:?}", expr2));
}};
}
#[cfg(test)]
mod tests {
use crate::error::Error;
use std::fmt::Write;
#[test]
#[should_panic(expected = "The expression was supposed to fail, but it succeeded.")]
fn assert_fails_empty() {
let success: Result<usize, Vec<Error>> = Ok(42);
assert_fails!(success, "search string");
}
#[test]
fn assert_fails_match() {
let success: Result<usize, Vec<Error>> = Err(vec![
Error::new("foo bar", None, None, None, None),
Error::new("foo search string bar", None, None, None, None),
Error::new("foo bar", None, None, None, None),
]);
assert_fails!(success, "search string");
}
#[test]
#[should_panic(expected = "the expected message wasn't found")]
fn assert_fails_mismatch() {
let success: Result<usize, Vec<Error>> = Err(vec![
Error::new("foo", None, None, None, None),
Error::new("bar", None, None, None, None),
Error::new("baz", None, None, None, None),
]);
assert_fails!(success, "search string");
}
#[test]
fn assert_same_match() {
assert_same!(42_i32, 42_i32);
}
#[test]
#[should_panic(expected = "42")]
fn assert_same_mismatch() {
assert_same!(42_i32, 43_i32);
}
}