1use std::borrow::Cow;
4use std::fmt;
5use std::sync::mpsc::Sender;
6
7pub use NamePadding::*;
8pub use TestFn::*;
9pub use TestName::*;
10
11use super::bench::Bencher;
12use super::event::CompletedTest;
13use super::{__rust_begin_short_backtrace, options};
14
15#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
18pub enum TestType {
19 UnitTest,
21 IntegrationTest,
23 DocTest,
25 Unknown,
28}
29
30#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
31pub enum NamePadding {
32 PadNone,
33 PadOnRight,
34}
35
36#[derive(Clone, PartialEq, Eq, Hash, Debug)]
41pub enum TestName {
42 StaticTestName(&'static str),
43 DynTestName(String),
44 AlignedTestName(Cow<'static, str>, NamePadding),
45}
46
47impl TestName {
48 pub fn as_slice(&self) -> &str {
49 match *self {
50 StaticTestName(s) => s,
51 DynTestName(ref s) => s,
52 AlignedTestName(ref s, _) => s,
53 }
54 }
55
56 pub fn padding(&self) -> NamePadding {
57 match self {
58 &AlignedTestName(_, p) => p,
59 _ => PadNone,
60 }
61 }
62
63 pub fn with_padding(&self, padding: NamePadding) -> TestName {
64 let name = match *self {
65 TestName::StaticTestName(name) => Cow::Borrowed(name),
66 TestName::DynTestName(ref name) => Cow::Owned(name.clone()),
67 TestName::AlignedTestName(ref name, _) => name.clone(),
68 };
69
70 TestName::AlignedTestName(name, padding)
71 }
72}
73impl fmt::Display for TestName {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 fmt::Display::fmt(self.as_slice(), f)
76 }
77}
78
79pub enum TestFn {
85 StaticTestFn(fn() -> Result<(), String>),
86 StaticBenchFn(fn(&mut Bencher) -> Result<(), String>),
87 StaticBenchAsTestFn(fn(&mut Bencher) -> Result<(), String>),
88 DynTestFn(Box<dyn FnOnce() -> Result<(), String> + Send>),
89 DynBenchFn(Box<dyn Fn(&mut Bencher) -> Result<(), String> + Send>),
90 DynBenchAsTestFn(Box<dyn Fn(&mut Bencher) -> Result<(), String> + Send>),
91}
92
93impl TestFn {
94 pub fn padding(&self) -> NamePadding {
95 match *self {
96 StaticTestFn(..) => PadNone,
97 StaticBenchFn(..) => PadOnRight,
98 StaticBenchAsTestFn(..) => PadNone,
99 DynTestFn(..) => PadNone,
100 DynBenchFn(..) => PadOnRight,
101 DynBenchAsTestFn(..) => PadNone,
102 }
103 }
104
105 pub(crate) fn into_runnable(self) -> Runnable {
106 match self {
107 StaticTestFn(f) => Runnable::Test(RunnableTest::Static(f)),
108 StaticBenchFn(f) => Runnable::Bench(RunnableBench::Static(f)),
109 StaticBenchAsTestFn(f) => Runnable::Test(RunnableTest::StaticBenchAsTest(f)),
110 DynTestFn(f) => Runnable::Test(RunnableTest::Dynamic(f)),
111 DynBenchFn(f) => Runnable::Bench(RunnableBench::Dynamic(f)),
112 DynBenchAsTestFn(f) => Runnable::Test(RunnableTest::DynamicBenchAsTest(f)),
113 }
114 }
115}
116
117impl fmt::Debug for TestFn {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 f.write_str(match *self {
120 StaticTestFn(..) => "StaticTestFn(..)",
121 StaticBenchFn(..) => "StaticBenchFn(..)",
122 StaticBenchAsTestFn(..) => "StaticBenchAsTestFn(..)",
123 DynTestFn(..) => "DynTestFn(..)",
124 DynBenchFn(..) => "DynBenchFn(..)",
125 DynBenchAsTestFn(..) => "DynBenchAsTestFn(..)",
126 })
127 }
128}
129
130pub(crate) enum Runnable {
131 Test(RunnableTest),
132 Bench(RunnableBench),
133}
134
135pub(crate) enum RunnableTest {
136 Static(fn() -> Result<(), String>),
137 Dynamic(Box<dyn FnOnce() -> Result<(), String> + Send>),
138 StaticBenchAsTest(fn(&mut Bencher) -> Result<(), String>),
139 DynamicBenchAsTest(Box<dyn Fn(&mut Bencher) -> Result<(), String> + Send>),
140}
141
142impl RunnableTest {
143 pub(crate) fn run(self) -> Result<(), String> {
144 match self {
145 RunnableTest::Static(f) => __rust_begin_short_backtrace(f),
146 RunnableTest::Dynamic(f) => __rust_begin_short_backtrace(f),
147 RunnableTest::StaticBenchAsTest(f) => {
148 crate::bench::run_once(|b| __rust_begin_short_backtrace(|| f(b)))
149 }
150 RunnableTest::DynamicBenchAsTest(f) => {
151 crate::bench::run_once(|b| __rust_begin_short_backtrace(|| f(b)))
152 }
153 }
154 }
155
156 pub(crate) fn is_dynamic(&self) -> bool {
157 match self {
158 RunnableTest::Static(_) => false,
159 RunnableTest::StaticBenchAsTest(_) => false,
160 RunnableTest::Dynamic(_) => true,
161 RunnableTest::DynamicBenchAsTest(_) => true,
162 }
163 }
164}
165
166pub(crate) enum RunnableBench {
167 Static(fn(&mut Bencher) -> Result<(), String>),
168 Dynamic(Box<dyn Fn(&mut Bencher) -> Result<(), String> + Send>),
169}
170
171impl RunnableBench {
172 pub(crate) fn run(
173 self,
174 id: TestId,
175 desc: &TestDesc,
176 monitor_ch: &Sender<CompletedTest>,
177 nocapture: bool,
178 ) {
179 match self {
180 RunnableBench::Static(f) => {
181 crate::bench::benchmark(id, desc.clone(), monitor_ch.clone(), nocapture, f)
182 }
183 RunnableBench::Dynamic(f) => {
184 crate::bench::benchmark(id, desc.clone(), monitor_ch.clone(), nocapture, f)
185 }
186 }
187 }
188}
189
190#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
192pub struct TestId(pub usize);
193
194#[derive(Clone, Debug)]
197pub struct TestDesc {
198 pub name: TestName,
199 pub ignore: bool,
200 pub ignore_message: Option<&'static str>,
201 pub source_file: &'static str,
202 pub start_line: usize,
203 pub start_col: usize,
204 pub end_line: usize,
205 pub end_col: usize,
206 pub should_panic: options::ShouldPanic,
207 pub compile_fail: bool,
208 pub no_run: bool,
209 pub test_type: TestType,
210}
211
212impl TestDesc {
213 pub fn padded_name(&self, column_count: usize, align: NamePadding) -> String {
214 let mut name = String::from(self.name.as_slice());
215 let fill = column_count.saturating_sub(name.len());
216 let pad = " ".repeat(fill);
217 match align {
218 PadNone => name,
219 PadOnRight => {
220 name.push_str(&pad);
221 name
222 }
223 }
224 }
225
226 pub fn test_mode(&self) -> Option<&'static str> {
229 if self.ignore {
230 return None;
231 }
232 match self.should_panic {
233 options::ShouldPanic::Yes | options::ShouldPanic::YesWithMessage(_) => {
234 return Some("should panic");
235 }
236 options::ShouldPanic::No => {}
237 }
238 if self.compile_fail {
239 return Some("compile fail");
240 }
241 if self.no_run {
242 return Some("compile");
243 }
244 None
245 }
246}
247
248#[derive(Debug)]
249pub struct TestDescAndFn {
250 pub desc: TestDesc,
251 pub testfn: TestFn,
252}
253
254impl TestDescAndFn {
255 pub const fn new_doctest(
256 test_name: &'static str,
257 ignore: bool,
258 source_file: &'static str,
259 start_line: usize,
260 no_run: bool,
261 should_panic: bool,
262 testfn: TestFn,
263 ) -> Self {
264 Self {
265 desc: TestDesc {
266 name: StaticTestName(test_name),
267 ignore,
268 ignore_message: None,
269 source_file,
270 start_line,
271 start_col: 0,
272 end_line: 0,
273 end_col: 0,
274 compile_fail: false,
275 no_run,
276 should_panic: if should_panic {
277 options::ShouldPanic::Yes
278 } else {
279 options::ShouldPanic::No
280 },
281 test_type: TestType::DocTest,
282 },
283 testfn,
284 }
285 }
286}