1//! Common types used by `libtest`.
2
3use std::borrow::Cow;
4use std::fmt;
5use std::sync::mpsc::Sender;
6
7use super::__rust_begin_short_backtrace;
8use super::bench::Bencher;
9use super::event::CompletedTest;
10use super::options;
11
12pub use NamePadding::*;
13pub use TestFn::*;
14pub 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)]
19pub 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)]
32pub 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)]
42pub enum TestName {
43 StaticTestName(&'static str),
44 DynTestName(String),
45 AlignedTestName(Cow<'static, str>, NamePadding),
46}
47
48impl TestName {
49 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
57 pub fn padding(&self) -> NamePadding {
58 match self {
59 &AlignedTestName(_, p) => p,
60 _ => PadNone,
61 }
62 }
63
64 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}
74impl fmt::Display for TestName {
75 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.
85pub 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
94impl TestFn {
95 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
106 pub(crate) fn into_runnable(self) -> Runnable {
107 match self {
108 StaticTestFn(f: fn() -> {unknown}) => Runnable::Test(RunnableTest::Static(f)),
109 StaticBenchFn(f: fn(&mut Bencher) -> {unknown}) => Runnable::Bench(RunnableBench::Static(f)),
110 StaticBenchAsTestFn(f: fn(&mut Bencher) -> {unknown}) => 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
118impl fmt::Debug for TestFn {
119 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
131pub(crate) enum Runnable {
132 Test(RunnableTest),
133 Bench(RunnableBench),
134}
135
136pub(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
143impl RunnableTest {
144 pub(crate) fn run(self) -> Result<(), String> {
145 match self {
146 RunnableTest::Static(f: fn() -> {unknown}) => __rust_begin_short_backtrace(f),
147 RunnableTest::Dynamic(f) => __rust_begin_short_backtrace(f),
148 RunnableTest::StaticBenchAsTest(f: fn(&mut Bencher) -> {unknown}) => {
149 crate::bench::run_once(|b: &mut Bencher| __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
157 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
167pub(crate) enum RunnableBench {
168 Static(fn(&mut Bencher) -> Result<(), String>),
169 Dynamic(Box<dyn Fn(&mut Bencher) -> Result<(), String> + Send>),
170}
171
172impl RunnableBench {
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: fn(&mut Bencher) -> {unknown}) => {
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)]
193pub 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)]
198pub 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
213impl TestDesc {
214 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 tests that are just run, otherwise returns a description of the type of test.
228 /// Descriptions include "should panic", "compile fail" and "compile".
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)]
250pub struct TestDescAndFn {
251 pub desc: TestDesc,
252 pub testfn: TestFn,
253}
254