• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Common types used by `libtest`.
2 
3 use std::borrow::Cow;
4 use std::fmt;
5 use std::sync::mpsc::Sender;
6 
7 use super::__rust_begin_short_backtrace;
8 use super::bench::Bencher;
9 use super::event::CompletedTest;
10 use super::options;
11 
12 pub use NamePadding::*;
13 pub use TestFn::*;
14 pub use TestName::*;
15 
16 /// Type of the test according to the [rust book](https://doc.rust-lang.org/cargo/guide/tests.html)
17 /// conventions.
18 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
19 pub enum TestType {
20     /// Unit-tests are expected to be in the `src` folder of the crate.
21     UnitTest,
22     /// Integration-style tests are expected to be in the `tests` folder of the crate.
23     IntegrationTest,
24     /// Doctests are created by the `librustdoc` manually, so it's a different type of test.
25     DocTest,
26     /// Tests for the sources that don't follow the project layout convention
27     /// (e.g. tests in raw `main.rs` compiled by calling `rustc --test` directly).
28     Unknown,
29 }
30 
31 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
32 pub enum NamePadding {
33     PadNone,
34     PadOnRight,
35 }
36 
37 // The name of a test. By convention this follows the rules for rust
38 // paths; i.e., it should be a series of identifiers separated by double
39 // colons. This way if some test runner wants to arrange the tests
40 // hierarchically it may.
41 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
42 pub enum TestName {
43     StaticTestName(&'static str),
44     DynTestName(String),
45     AlignedTestName(Cow<'static, str>, NamePadding),
46 }
47 
48 impl TestName {
as_slice(&self) -> &str49     pub fn as_slice(&self) -> &str {
50         match *self {
51             StaticTestName(s) => s,
52             DynTestName(ref s) => s,
53             AlignedTestName(ref s, _) => s,
54         }
55     }
56 
padding(&self) -> NamePadding57     pub fn padding(&self) -> NamePadding {
58         match self {
59             &AlignedTestName(_, p) => p,
60             _ => PadNone,
61         }
62     }
63 
with_padding(&self, padding: NamePadding) -> TestName64     pub fn with_padding(&self, padding: NamePadding) -> TestName {
65         let name = match *self {
66             TestName::StaticTestName(name) => Cow::Borrowed(name),
67             TestName::DynTestName(ref name) => Cow::Owned(name.clone()),
68             TestName::AlignedTestName(ref name, _) => name.clone(),
69         };
70 
71         TestName::AlignedTestName(name, padding)
72     }
73 }
74 impl fmt::Display for TestName {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result75     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76         fmt::Display::fmt(self.as_slice(), f)
77     }
78 }
79 
80 // A function that runs a test. If the function returns successfully,
81 // the test succeeds; if the function panics or returns Result::Err
82 // then the test fails. We may need to come up with a more clever
83 // definition of test in order to support isolation of tests into
84 // threads.
85 pub enum TestFn {
86     StaticTestFn(fn() -> Result<(), String>),
87     StaticBenchFn(fn(&mut Bencher) -> Result<(), String>),
88     StaticBenchAsTestFn(fn(&mut Bencher) -> Result<(), String>),
89     DynTestFn(Box<dyn FnOnce() -> Result<(), String> + Send>),
90     DynBenchFn(Box<dyn Fn(&mut Bencher) -> Result<(), String> + Send>),
91     DynBenchAsTestFn(Box<dyn Fn(&mut Bencher) -> Result<(), String> + Send>),
92 }
93 
94 impl TestFn {
padding(&self) -> NamePadding95     pub fn padding(&self) -> NamePadding {
96         match *self {
97             StaticTestFn(..) => PadNone,
98             StaticBenchFn(..) => PadOnRight,
99             StaticBenchAsTestFn(..) => PadNone,
100             DynTestFn(..) => PadNone,
101             DynBenchFn(..) => PadOnRight,
102             DynBenchAsTestFn(..) => PadNone,
103         }
104     }
105 
into_runnable(self) -> Runnable106     pub(crate) fn into_runnable(self) -> Runnable {
107         match self {
108             StaticTestFn(f) => Runnable::Test(RunnableTest::Static(f)),
109             StaticBenchFn(f) => Runnable::Bench(RunnableBench::Static(f)),
110             StaticBenchAsTestFn(f) => Runnable::Test(RunnableTest::StaticBenchAsTest(f)),
111             DynTestFn(f) => Runnable::Test(RunnableTest::Dynamic(f)),
112             DynBenchFn(f) => Runnable::Bench(RunnableBench::Dynamic(f)),
113             DynBenchAsTestFn(f) => Runnable::Test(RunnableTest::DynamicBenchAsTest(f)),
114         }
115     }
116 }
117 
118 impl fmt::Debug for TestFn {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result119     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120         f.write_str(match *self {
121             StaticTestFn(..) => "StaticTestFn(..)",
122             StaticBenchFn(..) => "StaticBenchFn(..)",
123             StaticBenchAsTestFn(..) => "StaticBenchAsTestFn(..)",
124             DynTestFn(..) => "DynTestFn(..)",
125             DynBenchFn(..) => "DynBenchFn(..)",
126             DynBenchAsTestFn(..) => "DynBenchAsTestFn(..)",
127         })
128     }
129 }
130 
131 pub(crate) enum Runnable {
132     Test(RunnableTest),
133     Bench(RunnableBench),
134 }
135 
136 pub(crate) enum RunnableTest {
137     Static(fn() -> Result<(), String>),
138     Dynamic(Box<dyn FnOnce() -> Result<(), String> + Send>),
139     StaticBenchAsTest(fn(&mut Bencher) -> Result<(), String>),
140     DynamicBenchAsTest(Box<dyn Fn(&mut Bencher) -> Result<(), String> + Send>),
141 }
142 
143 impl RunnableTest {
run(self) -> Result<(), String>144     pub(crate) fn run(self) -> Result<(), String> {
145         match self {
146             RunnableTest::Static(f) => __rust_begin_short_backtrace(f),
147             RunnableTest::Dynamic(f) => __rust_begin_short_backtrace(f),
148             RunnableTest::StaticBenchAsTest(f) => {
149                 crate::bench::run_once(|b| __rust_begin_short_backtrace(|| f(b)))
150             }
151             RunnableTest::DynamicBenchAsTest(f) => {
152                 crate::bench::run_once(|b| __rust_begin_short_backtrace(|| f(b)))
153             }
154         }
155     }
156 
is_dynamic(&self) -> bool157     pub(crate) fn is_dynamic(&self) -> bool {
158         match self {
159             RunnableTest::Static(_) => false,
160             RunnableTest::StaticBenchAsTest(_) => false,
161             RunnableTest::Dynamic(_) => true,
162             RunnableTest::DynamicBenchAsTest(_) => true,
163         }
164     }
165 }
166 
167 pub(crate) enum RunnableBench {
168     Static(fn(&mut Bencher) -> Result<(), String>),
169     Dynamic(Box<dyn Fn(&mut Bencher) -> Result<(), String> + Send>),
170 }
171 
172 impl RunnableBench {
run( self, id: TestId, desc: &TestDesc, monitor_ch: &Sender<CompletedTest>, nocapture: bool, )173     pub(crate) fn run(
174         self,
175         id: TestId,
176         desc: &TestDesc,
177         monitor_ch: &Sender<CompletedTest>,
178         nocapture: bool,
179     ) {
180         match self {
181             RunnableBench::Static(f) => {
182                 crate::bench::benchmark(id, desc.clone(), monitor_ch.clone(), nocapture, f)
183             }
184             RunnableBench::Dynamic(f) => {
185                 crate::bench::benchmark(id, desc.clone(), monitor_ch.clone(), nocapture, f)
186             }
187         }
188     }
189 }
190 
191 // A unique integer associated with each test.
192 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
193 pub struct TestId(pub usize);
194 
195 // The definition of a single test. A test runner will run a list of
196 // these.
197 #[derive(Clone, Debug)]
198 pub struct TestDesc {
199     pub name: TestName,
200     pub ignore: bool,
201     pub ignore_message: Option<&'static str>,
202     pub source_file: &'static str,
203     pub start_line: usize,
204     pub start_col: usize,
205     pub end_line: usize,
206     pub end_col: usize,
207     pub should_panic: options::ShouldPanic,
208     pub compile_fail: bool,
209     pub no_run: bool,
210     pub test_type: TestType,
211 }
212 
213 impl TestDesc {
padded_name(&self, column_count: usize, align: NamePadding) -> String214     pub fn padded_name(&self, column_count: usize, align: NamePadding) -> String {
215         let mut name = String::from(self.name.as_slice());
216         let fill = column_count.saturating_sub(name.len());
217         let pad = " ".repeat(fill);
218         match align {
219             PadNone => name,
220             PadOnRight => {
221                 name.push_str(&pad);
222                 name
223             }
224         }
225     }
226 
227     /// Returns None for ignored test or that that are just run, otherwise give a description of the type of test.
228     /// Descriptions include "should panic", "compile fail" and "compile".
test_mode(&self) -> Option<&'static str>229     pub fn test_mode(&self) -> Option<&'static str> {
230         if self.ignore {
231             return None;
232         }
233         match self.should_panic {
234             options::ShouldPanic::Yes | options::ShouldPanic::YesWithMessage(_) => {
235                 return Some("should panic");
236             }
237             options::ShouldPanic::No => {}
238         }
239         if self.compile_fail {
240             return Some("compile fail");
241         }
242         if self.no_run {
243             return Some("compile");
244         }
245         None
246     }
247 }
248 
249 #[derive(Debug)]
250 pub struct TestDescAndFn {
251     pub desc: TestDesc,
252     pub testfn: TestFn,
253 }
254