]>
Commit | Line | Data |
---|---|---|
f20569fa XL |
1 | use std::any::Any; |
2 | ||
3 | use super::bench::BenchSamples; | |
4 | use super::options::ShouldPanic; | |
5 | use super::time; | |
6 | use super::types::TestDesc; | |
7 | ||
8 | pub use self::TestResult::*; | |
9 | ||
10 | // Return codes for secondary process. | |
11 | // Start somewhere other than 0 so we know the return code means what we think | |
12 | // it means. | |
13 | pub const TR_OK: i32 = 50; | |
14 | pub const TR_FAILED: i32 = 51; | |
15 | ||
16 | #[derive(Debug, Clone, PartialEq)] | |
17 | pub enum TestResult { | |
18 | TrOk, | |
19 | TrFailed, | |
20 | TrFailedMsg(String), | |
21 | TrIgnored, | |
22 | TrAllowedFail, | |
23 | TrBench(BenchSamples), | |
24 | TrTimedFail, | |
25 | } | |
26 | ||
27 | unsafe impl Send for TestResult {} | |
28 | ||
29 | /// Creates a `TestResult` depending on the raw result of test execution | |
30 | /// and associated data. | |
31 | pub fn calc_result<'a>( | |
32 | desc: &TestDesc, | |
33 | task_result: Result<(), &'a (dyn Any + 'static + Send)>, | |
34 | time_opts: &Option<time::TestTimeOptions>, | |
35 | exec_time: &Option<time::TestExecTime>, | |
36 | ) -> TestResult { | |
37 | let result = match (&desc.should_panic, task_result) { | |
38 | (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TestResult::TrOk, | |
39 | (&ShouldPanic::YesWithMessage(msg), Err(ref err)) => { | |
40 | let maybe_panic_str = err | |
41 | .downcast_ref::<String>() | |
42 | .map(|e| &**e) | |
43 | .or_else(|| err.downcast_ref::<&'static str>().copied()); | |
44 | ||
45 | if maybe_panic_str.map(|e| e.contains(msg)).unwrap_or(false) { | |
46 | TestResult::TrOk | |
47 | } else if desc.allow_fail { | |
48 | TestResult::TrAllowedFail | |
49 | } else if let Some(panic_str) = maybe_panic_str { | |
50 | TestResult::TrFailedMsg(format!( | |
51 | r#"panic did not contain expected string | |
52 | panic message: `{:?}`, | |
53 | expected substring: `{:?}`"#, | |
54 | panic_str, msg | |
55 | )) | |
56 | } else { | |
57 | TestResult::TrFailedMsg(format!( | |
58 | r#"expected panic with string value, | |
59 | found non-string value: `{:?}` | |
60 | expected substring: `{:?}`"#, | |
61 | (**err).type_id(), | |
62 | msg | |
63 | )) | |
64 | } | |
65 | } | |
66 | (&ShouldPanic::Yes, Ok(())) => { | |
67 | TestResult::TrFailedMsg("test did not panic as expected".to_string()) | |
68 | } | |
69 | _ if desc.allow_fail => TestResult::TrAllowedFail, | |
70 | _ => TestResult::TrFailed, | |
71 | }; | |
72 | ||
73 | // If test is already failed (or allowed to fail), do not change the result. | |
74 | if result != TestResult::TrOk { | |
75 | return result; | |
76 | } | |
77 | ||
78 | // Check if test is failed due to timeout. | |
79 | if let (Some(opts), Some(time)) = (time_opts, exec_time) { | |
80 | if opts.error_on_excess && opts.is_critical(desc, time) { | |
81 | return TestResult::TrTimedFail; | |
82 | } | |
83 | } | |
84 | ||
85 | result | |
86 | } | |
87 | ||
88 | /// Creates a `TestResult` depending on the exit code of test subprocess. | |
89 | pub fn get_result_from_exit_code( | |
90 | desc: &TestDesc, | |
91 | code: i32, | |
92 | time_opts: &Option<time::TestTimeOptions>, | |
93 | exec_time: &Option<time::TestExecTime>, | |
94 | ) -> TestResult { | |
95 | let result = match (desc.allow_fail, code) { | |
96 | (_, TR_OK) => TestResult::TrOk, | |
97 | (true, TR_FAILED) => TestResult::TrAllowedFail, | |
98 | (false, TR_FAILED) => TestResult::TrFailed, | |
99 | (_, _) => TestResult::TrFailedMsg(format!("got unexpected return code {}", code)), | |
100 | }; | |
101 | ||
102 | // If test is already failed (or allowed to fail), do not change the result. | |
103 | if result != TestResult::TrOk { | |
104 | return result; | |
105 | } | |
106 | ||
107 | // Check if test is failed due to timeout. | |
108 | if let (Some(opts), Some(time)) = (time_opts, exec_time) { | |
109 | if opts.error_on_excess && opts.is_critical(desc, time) { | |
110 | return TestResult::TrTimedFail; | |
111 | } | |
112 | } | |
113 | ||
114 | result | |
115 | } |