1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
/*! A library for writing asynchronous tests. This library provides a framework for writing the free-style, asynchronous tests without using the default test harness provided by `rustc`. The concept and design are **strongly** inspired by [`libtest-mimic`](https://github.com/LukasKalbertodt/libtest-mimic), but also focuses on the affinity with the `async`/`.await` syntax. # Example ```no_run # fn main() { futures::executor::block_on(async { use mimicaw::{Args, Test, TestDesc, Outcome}; // Parse command line arguments. let args = Args::from_env().unwrap_or_else(|st| st.exit()); // Each test case is described using `Test` having one associated data. // // The data will be used by the runner described below to run tests. let tests = vec![ Test::test("case1", "foo"), Test::test("case2", "bar"), Test::test("case3_long_computation", "baz").ignore(true), Test::test("case4", "The quick brown fox jumps over the lazy dog."), ]; // A function for running the test cases. // // Each test result is asynchronous and a future is returned to acquire the result. let runner = |_desc: TestDesc, data: &'static str| { async move { match data { "foo" | "baz" => Outcome::passed(), "bar" => Outcome::failed().error_message("`bar' is forbidden"), data => Outcome::failed().error_message(format!("unknown data: {}", data)), } } }; // Run the process of test suite. // // The test cases are filtered according to the command line arguments, and then executed concurrently from the top. let status = mimicaw::run_tests(&args, tests, runner).await; status.exit() # }) } ``` !*/ #![doc(html_root_url = "https://docs.rs/mimicaw/0.1.3")] #![deny(missing_docs)] #![cfg_attr(test, deny(warnings))] #![forbid(unsafe_code, clippy::unimplemented, clippy::todo)] mod args; mod driver; mod printer; mod report; mod test; pub use crate::{ args::{Args, ColorConfig, OutputFormat}, driver::TestRunner, report::Report, test::{Outcome, Test, TestDesc}, }; use crate::driver::TestDriver; /// Exit status code used as a result of the test process. #[derive(Copy, Clone, Debug, PartialEq)] pub struct ExitStatus(i32); impl ExitStatus { const OK: Self = Self(0); const FAILED: Self = Self(101); /// Return whether the status is successful or not. #[inline] pub fn success(self) -> bool { self.code() == 0 } /// Return the raw exit code. #[inline] pub fn code(self) -> i32 { self.0 } /// Terminate the test process with the exit code. /// /// This method **should not** be called before the cleanup /// of the test process has completed. #[inline] pub fn exit(self) -> ! { std::process::exit(self.code()); } /// Terminate the test process if the exit code is not successful. /// /// This method **should not** be called before the cleanup /// of the test process has completed. #[inline] pub fn exit_if_failed(self) { if !self.success() { self.exit(); } } } /// Run a test suite using the specified test runner. /// /// The test suite runs as follows: /// /// * Test cases that do not satisfy the conditions given in /// the command line options are filtered out. /// * Apply the test runner to each test case that passed to /// the filter, and create futures for awaiting their outcomes. /// these futures are executed concurrently, and their results /// are written to the console in the order of completion. /// * Finally, the results of all test cases are aggregated. pub async fn run_tests<D>( args: &Args, tests: impl IntoIterator<Item = Test<D>>, runner: impl TestRunner<D>, ) -> ExitStatus { match run_tests_with_report(args, tests, runner).await { Ok(report) => report.status(), Err(status) => status, } } /// Run a test suite and report the summary. pub async fn run_tests_with_report<D>( args: &Args, tests: impl IntoIterator<Item = Test<D>>, runner: impl TestRunner<D>, ) -> Result<Report, ExitStatus> { let driver = TestDriver::new(&args); driver.run_tests(tests, runner).await } #[test] fn test_html_root_url() { version_sync::assert_html_root_url_updated!("src/lib.rs"); }