Skip to main content

test_that/
lib.rs

1// Copyright 2022 Google LLC
2// Copyright 2026 Bradford Hovinen <bradford@hovinen.me>
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#![no_std]
17#![doc = include_str!("../crate_docs.md")]
18#![cfg_attr(docsrs, feature(doc_cfg), doc(auto_cfg))]
19
20#[macro_use]
21extern crate alloc;
22#[cfg(feature = "std")]
23extern crate std;
24
25/// Re-export of `alloc` for use by this crate's macros.
26/// Do not use directly; it is not part of the public API.
27#[doc(hidden)]
28pub extern crate alloc as __alloc;
29
30#[cfg(feature = "test-that-macro")]
31extern crate test_that_macro;
32
33#[cfg(test)]
34extern crate quickcheck;
35
36#[macro_use]
37pub mod assertions;
38pub mod description;
39pub mod internal;
40pub mod matcher;
41pub mod matcher_support;
42pub mod matchers;
43
44#[cfg(feature = "googletest-compat")]
45pub mod compat;
46
47/// Re-exports of the symbols in this crate which are most likely to be used.
48///
49/// This includes:
50///  * All assertion macros,
51///  * Traits and type definitions normally used by tests, and
52///  * All built-in matchers.
53///
54/// Typically, one imports everything in the prelude in one's test module:
55///
56/// ```
57/// mod tests {
58///     use test_that::prelude::*;
59/// }
60/// ```
61pub mod prelude {
62    pub use super::OrFailExt;
63    #[cfg(feature = "googletest-compat")]
64    #[allow(deprecated)]
65    pub use super::Result;
66    pub use super::TestResult;
67    pub use super::TestResultExt;
68    #[cfg(feature = "googletest-compat")]
69    #[allow(deprecated)]
70    pub use super::compat::IntoTestResult;
71    pub use super::matcher::Matcher;
72    pub use super::matcher::MatcherExt;
73    pub use super::matchers::containers::*;
74    pub use super::matchers::*;
75    #[cfg(feature = "std")]
76    pub use super::verify_current_test_outcome;
77    pub use super::{assert_that, fail, verify_pred, verify_that};
78    #[cfg(feature = "non-fatal-assertions")]
79    pub use super::{expect_pred, expect_that};
80}
81
82use alloc::string::String;
83#[cfg(feature = "non-fatal-assertions")]
84pub use test_that_macro::test;
85
86use internal::test_outcome::{TestAssertionFailure, TestOutcome};
87
88/// A `Result` whose `Err` variant indicates a test failure.
89///
90/// The assertions [`verify_that!`][crate::verify_that],
91/// [`verify_pred!`][crate::verify_pred], and [`fail!`][crate::fail] evaluate
92/// to `TestResult<()>`. A test function may return `TestResult<()>` in
93/// combination with those macros to abort immediately on assertion failure.
94///
95/// This can be used with subroutines which may cause the test to fatally fail
96/// and which return some value needed by the caller. For example:
97///
98/// ```ignore
99/// fn load_file_content_as_string() -> TestResult<String> {
100///     let file_stream = load_file().err_to_test_failure()?;
101///     Ok(file_stream.to_string())
102/// }
103/// ```
104///
105/// The `Err` variant contains a [`TestAssertionFailure`] which carries the data
106/// of the (fatal) assertion failure which generated this result. Non-fatal
107/// assertion failures, which log the failure and report the test as having
108/// failed but allow it to continue running, are not encoded in this type.
109pub type TestResult<T> = core::result::Result<T, TestAssertionFailure>;
110
111/// Alias for [TestResult] to ease porting from [googletest](https://docs.rs/googletest).
112#[cfg(feature = "googletest-compat")]
113#[cfg_attr(feature = "googletest-migrate", deprecated(note = "Use TestResult instead"))]
114pub type Result<T> = TestResult<T>;
115
116/// Returns a [`Result`] corresponding to the outcome of the currently running
117/// test.
118///
119/// This returns `Result::Err` precisely if the current test has recorded at
120/// least one test assertion failure via [`expect_that!`][crate::expect_that],
121/// [`expect_pred!`][crate::expect_pred], or [`TestResultExt::and_log_failure`].
122/// It can be used in concert with the `?` operator to continue execution of the
123/// test conditionally on there not having been any failure yet.
124///
125/// This requires the use of the [`#[test_that::test]`][crate::test] attribute
126/// macro.
127///
128/// ```
129/// # use test_that::prelude::*;
130/// # #[cfg(feature = "non-fatal-assertions")] {
131/// # /* Make sure this also compiles as a doctest.
132/// #[test_that::test]
133/// # */
134/// # fn foo() -> u32 { 1 }
135/// # fn bar() -> u32 { 2 }
136/// fn should_fail_and_not_execute_last_assertion() -> TestResult<()> {
137/// #   test_that::internal::test_outcome::TestOutcome::init_current_test_outcome();
138///     expect_that!(foo(), eq(2));     // May fail, but will not abort the test.
139///     expect_that!(bar(), gt(1));     // May fail, but will not abort the test.
140///     verify_current_test_outcome()?; // Aborts the test if one of the previous assertions failed.
141///     verify_that!(foo(), gt(0))      // Does not execute if the line above aborts.
142/// }
143/// # verify_that!(should_fail_and_not_execute_last_assertion(), err(displays_as(contains_substring("Test failed")))).unwrap();
144/// # }
145/// ```
146#[cfg(feature = "std")]
147pub fn verify_current_test_outcome() -> TestResult<()> {
148    TestOutcome::get_current_test_outcome()
149}
150
151/// Adds to `Result` support for Test That! functionality.
152pub trait TestResultExt {
153    /// If `self` is a `Result::Err`, writes to `stdout` a failure report
154    /// and marks the test failed. Otherwise, does nothing.
155    ///
156    /// This can be used for non-fatal test assertions, for example:
157    ///
158    /// ```
159    /// # use test_that::prelude::*;
160    /// # use test_that::internal::test_outcome::TestOutcome;
161    /// # #[cfg(feature = "std")]
162    /// # TestOutcome::init_current_test_outcome();
163    /// let actual = 42;
164    /// verify_that!(actual, eq(42)).and_log_failure();
165    ///                                  // Test still passing; nothing happens
166    /// verify_that!(actual, eq(10)).and_log_failure();
167    ///                          // Test now fails and failure output to stdout
168    /// verify_that!(actual, eq(100)).and_log_failure();
169    ///               // Test still fails and new failure also output to stdout
170    /// # #[cfg(feature = "std")]
171    /// # TestOutcome::close_current_test_outcome::<&str>(Ok(())).unwrap_err();
172    /// ```
173    fn and_log_failure(self);
174
175    /// Adds `message` to the logged failure message if `self` is a
176    /// `Result::Err`. Otherwise, does nothing.
177    ///
178    /// If this method is called more than once, only `message` from the last
179    /// invocation is output.
180    ///
181    /// For example:
182    ///
183    /// ```
184    /// # use test_that::prelude::*;
185    /// # fn should_fail() -> TestResult<()> {
186    /// let actual = 0;
187    /// verify_that!(actual, eq(42)).failure_message("Actual was wrong!")?;
188    /// # Ok(())
189    /// # }
190    /// # verify_that!(should_fail(), err(displays_as(contains_substring("Actual was wrong"))))
191    /// #     .unwrap();
192    /// ```
193    ///
194    /// results in the following failure message:
195    ///
196    /// ```text
197    /// Expected: actual equal to 42
198    ///   but was: 0
199    /// Actual was wrong!
200    /// ```
201    ///
202    /// One can pass a `String` too:
203    ///
204    /// ```
205    /// # use test_that::prelude::*;
206    /// # fn should_fail() -> TestResult<()> {
207    /// let actual = 0;
208    /// verify_that!(actual, eq(42))
209    ///    .failure_message(format!("Actual {} was wrong!", actual))?;
210    /// # Ok(())
211    /// # }
212    /// # verify_that!(should_fail(), err(displays_as(contains_substring("Actual 0 was wrong"))))
213    /// #     .unwrap();
214    /// ```
215    ///
216    /// However, consider using [`TestResultExt::with_failure_message`]
217    /// instead in that case to avoid unnecessary memory allocation when the
218    /// message is not needed.
219    fn failure_message(self, message: impl Into<String>) -> Self;
220
221    /// Adds the output of the closure `provider` to the logged failure message
222    /// if `self` is a `Result::Err`. Otherwise, does nothing.
223    ///
224    /// This is analogous to [`TestResultExt::failure_message`] but
225    /// only executes the closure `provider` if it actually produces the
226    /// message, thus saving possible memory allocation.
227    ///
228    /// ```
229    /// # use test_that::prelude::*;
230    /// # fn should_fail() -> TestResult<()> {
231    /// let actual = 0;
232    /// verify_that!(actual, eq(42))
233    ///    .with_failure_message(|| format!("Actual {} was wrong!", actual))?;
234    /// # Ok(())
235    /// # }
236    /// # verify_that!(should_fail(), err(displays_as(contains_substring("Actual 0 was wrong"))))
237    /// #     .unwrap();
238    /// ```
239    fn with_failure_message(self, provider: impl FnOnce() -> String) -> Self;
240}
241
242impl<T> TestResultExt for core::result::Result<T, TestAssertionFailure> {
243    fn and_log_failure(self) {
244        TestOutcome::ensure_text_context_present();
245        if let Err(failure) = self {
246            failure.log();
247        }
248    }
249
250    fn failure_message(mut self, message: impl Into<String>) -> Self {
251        if let Err(ref mut failure) = self {
252            failure.custom_message = Some(message.into());
253        }
254        self
255    }
256
257    fn with_failure_message(mut self, provider: impl FnOnce() -> String) -> Self {
258        if let Err(ref mut failure) = self {
259            failure.custom_message = Some(provider());
260        }
261        self
262    }
263}
264
265/// Provides an extension method for converting an arbitrary type into a
266/// [`Result`].
267///
268/// A type can implement this trait to provide an easy way to return immediately
269/// from a test in conjunction with the `?` operator. This is useful for
270/// [`Result`] types whose `Result::Err` variant does not implement
271/// [`std::error::Error`].
272///
273/// There is an implementation of this trait for [`anyhow::Error`] (which does
274/// not implement `std::error::Error`) when the `anyhow` feature is enabled.
275/// Importing this trait allows one to easily map [`anyhow::Error`] to a test
276/// failure:
277///
278/// ```ignore
279/// #[test]
280/// fn should_work() -> Result<()> {
281///     let value = something_which_can_fail().or_fail()?;
282///     ...
283/// }
284///
285/// fn something_which_can_fail() -> anyhow::Result<...> { ... }
286/// ```
287pub trait OrFailExt<T> {
288    /// Converts this instance into a [`Result`].
289    ///
290    /// Typically, the `Self` type is itself a [`core::result::Result`]. This
291    /// method should then map the `Err` variant to a [`TestAssertionFailure`]
292    /// and leave the `Ok` variant unchanged.
293    fn or_fail(self) -> TestResult<T>;
294}
295
296#[cfg(feature = "anyhow")]
297impl<T> OrFailExt<T> for core::result::Result<T, anyhow::Error> {
298    fn or_fail(self) -> core::result::Result<T, TestAssertionFailure> {
299        self.map_err(|e| TestAssertionFailure::create(alloc::format!("{e:#}")))
300    }
301}
302
303#[cfg(feature = "proptest")]
304impl<OkT, CaseT: core::fmt::Debug> OrFailExt<OkT>
305    for core::result::Result<OkT, proptest::test_runner::TestError<CaseT>>
306{
307    fn or_fail(self) -> core::result::Result<OkT, TestAssertionFailure> {
308        self.map_err(|e| TestAssertionFailure::create(alloc::format!("{e}")))
309    }
310}