1 | //! Common types used by `libtest`. |
2 | |
3 | use std::borrow::Cow; |
4 | use std::fmt; |
5 | |
6 | use super::bench::Bencher; |
7 | use super::options; |
8 | |
9 | pub use NamePadding::*; |
10 | pub use TestFn::*; |
11 | pub use TestName::*; |
12 | |
13 | /// Type of the test according to the [rust book](https://doc.rust-lang.org/cargo/guide/tests.html) |
14 | /// conventions. |
15 | #[derive (Copy, Clone, Debug, PartialEq, Eq, Hash)] |
16 | pub enum TestType { |
17 | /// Unit-tests are expected to be in the `src` folder of the crate. |
18 | UnitTest, |
19 | /// Integration-style tests are expected to be in the `tests` folder of the crate. |
20 | IntegrationTest, |
21 | /// Doctests are created by the `librustdoc` manually, so it's a different type of test. |
22 | DocTest, |
23 | /// Tests for the sources that don't follow the project layout convention |
24 | /// (e.g. tests in raw `main.rs` compiled by calling `rustc --test` directly). |
25 | Unknown, |
26 | } |
27 | |
28 | #[derive (Clone, Copy, PartialEq, Eq, Hash, Debug)] |
29 | pub enum NamePadding { |
30 | PadNone, |
31 | PadOnRight, |
32 | } |
33 | |
34 | // The name of a test. By convention this follows the rules for rust |
35 | // paths; i.e., it should be a series of identifiers separated by double |
36 | // colons. This way if some test runner wants to arrange the tests |
37 | // hierarchically it may. |
38 | #[derive (Clone, PartialEq, Eq, Hash, Debug)] |
39 | pub enum TestName { |
40 | StaticTestName(&'static str), |
41 | DynTestName(String), |
42 | AlignedTestName(Cow<'static, str>, NamePadding), |
43 | } |
44 | |
45 | impl TestName { |
46 | pub fn as_slice(&self) -> &str { |
47 | match *self { |
48 | StaticTestName(s) => s, |
49 | DynTestName(ref s) => s, |
50 | AlignedTestName(ref s, _) => &*s, |
51 | } |
52 | } |
53 | |
54 | pub fn padding(&self) -> NamePadding { |
55 | match self { |
56 | &AlignedTestName(_, p) => p, |
57 | _ => PadNone, |
58 | } |
59 | } |
60 | |
61 | pub fn with_padding(&self, padding: NamePadding) -> TestName { |
62 | let name = match *self { |
63 | TestName::StaticTestName(name) => Cow::Borrowed(name), |
64 | TestName::DynTestName(ref name) => Cow::Owned(name.clone()), |
65 | TestName::AlignedTestName(ref name, _) => name.clone(), |
66 | }; |
67 | |
68 | TestName::AlignedTestName(name, padding) |
69 | } |
70 | } |
71 | impl fmt::Display for TestName { |
72 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
73 | fmt::Display::fmt(self.as_slice(), f) |
74 | } |
75 | } |
76 | |
77 | /// Represents a benchmark function. |
78 | pub trait TDynBenchFn: Send { |
79 | fn run(&self, harness: &mut Bencher); |
80 | } |
81 | |
82 | // A function that runs a test. If the function returns successfully, |
83 | // the test succeeds; if the function panics then the test fails. We |
84 | // may need to come up with a more clever definition of test in order |
85 | // to support isolation of tests into threads. |
86 | pub enum TestFn { |
87 | StaticTestFn(fn()), |
88 | StaticBenchFn(fn(&mut Bencher)), |
89 | DynTestFn(Box<dyn FnOnce() + Send>), |
90 | DynBenchFn(Box<dyn TDynBenchFn + 'static>), |
91 | } |
92 | |
93 | impl TestFn { |
94 | pub fn padding(&self) -> NamePadding { |
95 | match *self { |
96 | StaticTestFn(..) => PadNone, |
97 | StaticBenchFn(..) => PadOnRight, |
98 | DynTestFn(..) => PadNone, |
99 | DynBenchFn(..) => PadOnRight, |
100 | } |
101 | } |
102 | } |
103 | |
104 | impl fmt::Debug for TestFn { |
105 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
106 | f.write_str(data:match *self { |
107 | StaticTestFn(..) => "StaticTestFn(..)" , |
108 | StaticBenchFn(..) => "StaticBenchFn(..)" , |
109 | DynTestFn(..) => "DynTestFn(..)" , |
110 | DynBenchFn(..) => "DynBenchFn(..)" , |
111 | }) |
112 | } |
113 | } |
114 | |
115 | // The definition of a single test. A test runner will run a list of |
116 | // these. |
117 | #[derive (Clone, Debug, PartialEq, Eq, Hash)] |
118 | pub struct TestDesc { |
119 | pub name: TestName, |
120 | pub ignore: bool, |
121 | pub should_panic: options::ShouldPanic, |
122 | pub allow_fail: bool, |
123 | pub test_type: TestType, |
124 | } |
125 | |
126 | impl TestDesc { |
127 | pub fn padded_name(&self, column_count: usize, align: NamePadding) -> String { |
128 | let mut name: String = String::from(self.name.as_slice()); |
129 | let fill: usize = column_count.saturating_sub(name.len()); |
130 | let pad: String = " " .repeat(fill); |
131 | match align { |
132 | PadNone => name, |
133 | PadOnRight => { |
134 | name.push_str(&pad); |
135 | name |
136 | } |
137 | } |
138 | } |
139 | } |
140 | |
141 | #[derive (Debug)] |
142 | pub struct TestDescAndFn { |
143 | pub desc: TestDesc, |
144 | pub testfn: TestFn, |
145 | } |
146 | |