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