1 /* 2 * This file is derived from src/types.rs in the Rust test library, used under 3 * the Apache License, Version 2.0. The following is the original copyright 4 * information from the Rust project: 5 * 6 * Copyrights in the Rust project are retained by their contributors. No 7 * copyright assignment is required to contribute to the Rust project. 8 * 9 * Some files include explicit copyright notices and/or license notices. 10 * For full authorship information, see the version control history or 11 * https://thanks.rust-lang.org 12 * 13 * Except as otherwise noted (below and/or in individual files), Rust is 14 * licensed under the Apache License, Version 2.0 <LICENSE-APACHE> or 15 * <http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 16 * <LICENSE-MIT> or <http://opensource.org/licenses/MIT>, at your option. 17 * 18 * 19 * Licensed under the Apache License, Version 2.0 (the "License"); 20 * you may not use this file except in compliance with the License. 21 * You may obtain a copy of the License at 22 * 23 * http://www.apache.org/licenses/LICENSE-2.0 24 * 25 * Unless required by applicable law or agreed to in writing, software 26 * distributed under the License is distributed on an "AS IS" BASIS, 27 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 28 * See the License for the specific language governing permissions and 29 * limitations under the License. 30 */ 31 32 //! Common types used by `libtest`. 33 34 use alloc::borrow::Cow; 35 use alloc::boxed::Box; 36 use alloc::string::String; 37 use core::fmt; 38 39 use super::bench::Bencher; 40 use super::options; 41 42 pub use NamePadding::*; 43 pub use TestFn::*; 44 pub use TestName::*; 45 46 /// Type of the test according to the [rust book](https://doc.rust-lang.org/cargo/guide/tests.html) 47 /// conventions. 48 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 49 pub enum TestType { 50 /// Unit-tests are expected to be in the `src` folder of the crate. 51 UnitTest, 52 /// Integration-style tests are expected to be in the `tests` folder of the crate. 53 IntegrationTest, 54 /// Doctests are created by the `librustdoc` manually, so it's a different type of test. 55 DocTest, 56 /// Tests for the sources that don't follow the project layout convention 57 /// (e.g. tests in raw `main.rs` compiled by calling `rustc --test` directly). 58 Unknown, 59 } 60 61 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] 62 pub enum NamePadding { 63 PadNone, 64 PadOnRight, 65 } 66 67 // The name of a test. By convention this follows the rules for rust 68 // paths; i.e., it should be a series of identifiers separated by double 69 // colons. This way if some test runner wants to arrange the tests 70 // hierarchically it may. 71 #[derive(Clone, PartialEq, Eq, Hash, Debug)] 72 pub enum TestName { 73 StaticTestName(&'static str), 74 DynTestName(String), 75 AlignedTestName(Cow<'static, str>, NamePadding), 76 } 77 78 impl TestName { as_slice(&self) -> &str79 pub fn as_slice(&self) -> &str { 80 match *self { 81 StaticTestName(s) => s, 82 DynTestName(ref s) => s, 83 AlignedTestName(ref s, _) => &*s, 84 } 85 } 86 padding(&self) -> NamePadding87 pub fn padding(&self) -> NamePadding { 88 match self { 89 &AlignedTestName(_, p) => p, 90 _ => PadNone, 91 } 92 } 93 with_padding(&self, padding: NamePadding) -> TestName94 pub fn with_padding(&self, padding: NamePadding) -> TestName { 95 let name = match *self { 96 TestName::StaticTestName(name) => Cow::Borrowed(name), 97 TestName::DynTestName(ref name) => Cow::Owned(name.clone()), 98 TestName::AlignedTestName(ref name, _) => name.clone(), 99 }; 100 101 TestName::AlignedTestName(name, padding) 102 } 103 } 104 impl fmt::Display for TestName { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 106 fmt::Display::fmt(self.as_slice(), f) 107 } 108 } 109 110 /// Represents a benchmark function. 111 pub trait TDynBenchFn: Send { run(&self, harness: &mut Bencher)112 fn run(&self, harness: &mut Bencher); 113 } 114 115 // A function that runs a test. If the function returns successfully, 116 // the test succeeds; if the function panics then the test fails. We 117 // may need to come up with a more clever definition of test in order 118 // to support isolation of tests into threads. 119 pub enum TestFn { 120 StaticTestFn(fn()), 121 StaticBenchFn(fn(&mut Bencher)), 122 DynTestFn(Box<dyn FnOnce() + Send>), 123 DynBenchFn(Box<dyn TDynBenchFn + 'static>), 124 } 125 126 impl TestFn { padding(&self) -> NamePadding127 pub fn padding(&self) -> NamePadding { 128 match *self { 129 StaticTestFn(..) => PadNone, 130 StaticBenchFn(..) => PadOnRight, 131 DynTestFn(..) => PadNone, 132 DynBenchFn(..) => PadOnRight, 133 } 134 } 135 } 136 137 impl fmt::Debug for TestFn { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 139 f.write_str(match *self { 140 StaticTestFn(..) => "StaticTestFn(..)", 141 StaticBenchFn(..) => "StaticBenchFn(..)", 142 DynTestFn(..) => "DynTestFn(..)", 143 DynBenchFn(..) => "DynBenchFn(..)", 144 }) 145 } 146 } 147 148 // A unique integer associated with each test. 149 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 150 pub struct TestId(pub usize); 151 152 // The definition of a single test. A test runner will run a list of 153 // these. 154 #[derive(Clone, Debug)] 155 pub struct TestDesc { 156 pub name: TestName, 157 pub ignore: bool, 158 #[cfg(not(bootstrap))] 159 pub ignore_message: Option<&'static str>, 160 pub should_panic: options::ShouldPanic, 161 pub compile_fail: bool, 162 pub no_run: bool, 163 pub test_type: TestType, 164 pub source_file: &'static str, 165 pub start_line: usize, 166 pub start_col: usize, 167 pub end_line: usize, 168 pub end_col: usize, 169 } 170 171 impl TestDesc { padded_name(&self, column_count: usize, align: NamePadding) -> String172 pub fn padded_name(&self, column_count: usize, align: NamePadding) -> String { 173 let mut name = String::from(self.name.as_slice()); 174 let fill = column_count.saturating_sub(name.len()); 175 let pad = " ".repeat(fill); 176 match align { 177 PadNone => name, 178 PadOnRight => { 179 name.push_str(&pad); 180 name 181 } 182 } 183 } 184 185 /// Returns None for ignored test or that that are just run, otherwise give a description of the type of test. 186 /// Descriptions include "should panic", "compile fail" and "compile". test_mode(&self) -> Option<&'static str>187 pub fn test_mode(&self) -> Option<&'static str> { 188 if self.ignore { 189 return None; 190 } 191 match self.should_panic { 192 options::ShouldPanic::Yes | options::ShouldPanic::YesWithMessage(_) => { 193 return Some("should panic"); 194 } 195 options::ShouldPanic::No => {} 196 } 197 if self.compile_fail { 198 return Some("compile fail"); 199 } 200 if self.no_run { 201 return Some("compile"); 202 } 203 None 204 } 205 } 206 207 #[derive(Debug)] 208 pub struct TestDescAndFn { 209 pub desc: TestDesc, 210 pub testfn: TestFn, 211 } 212