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