Skip to main content

googletest/
lib.rs

1// Copyright 2022 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#![doc = include_str!("../crate_docs.md")]
16
17extern crate googletest_macro;
18
19#[cfg(test)]
20extern crate quickcheck;
21
22#[macro_use]
23pub mod assertions;
24pub mod description;
25pub mod fixtures;
26#[macro_use]
27pub mod fmt;
28pub mod internal;
29pub mod matcher;
30pub mod matcher_support;
31pub mod matchers;
32
33pub use googletest_macro::__abbreviated_stringify;
34
35/// Re-exports of the symbols in this crate which are most likely to be used.
36///
37/// This includes:
38///  * All assertion macros,
39///  * Traits and type definitions normally used by tests, and
40///  * All built-in matchers.
41///
42/// Typically, one imports everything in the prelude in one's test module:
43///
44/// ```
45/// mod tests {
46///     use googletest::prelude::*;
47/// }
48/// ```
49pub mod prelude {
50    pub use super::fixtures::{ConsumableFixture, Fixture, FixtureOf, StaticFixture};
51    pub use super::gtest;
52    pub use super::matcher::{Matcher, MatcherBase};
53    pub use super::matchers::*;
54    pub use super::scoped_trace;
55    pub use super::verify_current_test_outcome;
56    pub use super::GoogleTestSupport;
57    pub use super::OrFail;
58    pub use super::Result;
59    // Assert macros
60    pub use super::{
61        add_failure, add_failure_at, assert_false, assert_pred, assert_that, assert_true,
62        expect_eq, expect_false, expect_float_eq, expect_ge, expect_gt, expect_le, expect_lt,
63        expect_ne, expect_near, expect_pred, expect_that, expect_true, fail, succeed, verify_eq,
64        verify_false, verify_float_eq, verify_ge, verify_gt, verify_le, verify_lt, verify_ne,
65        verify_near, verify_pred, verify_that, verify_true,
66    };
67}
68
69/// Causes a trace to be included in every test failure message generated
70/// by code in the current scope.
71#[macro_export]
72macro_rules! scoped_trace {
73    ($($arg:tt)*) => {
74        #[allow(clippy::shadow_same, clippy::shadow_unrelated)]
75        let _gtest_trace_guard = $crate::internal::scoped_trace::ScopedTraceGuard::new(
76            format!($($arg)*),
77        );
78    };
79}
80
81pub use googletest_macro::gtest;
82pub use googletest_macro::test;
83
84use internal::test_outcome::{TestAssertionFailure, TestOutcome};
85
86/// A `Result` whose `Err` variant indicates a test failure.
87///
88/// The assertions [`verify_that!`][crate::verify_that],
89/// [`verify_pred!`][crate::verify_pred], and [`fail!`][crate::fail] evaluate
90/// to `Result<()>`. A test function may return `Result<()>` in combination with
91/// those macros to abort immediately on assertion failure.
92///
93/// This can be used with subroutines which may cause the test to fatally fail
94/// and which return some value needed by the caller. For example:
95///
96/// ```ignore
97/// fn load_file_content_as_string() -> Result<String> {
98///     let file_stream = load_file().err_to_test_failure()?;
99///     Ok(file_stream.to_string())
100/// }
101/// ```
102///
103/// The `Err` variant contains a [`TestAssertionFailure`] which carries the data
104/// of the (fatal) assertion failure which generated this result. Non-fatal
105/// assertion failures, which log the failure and report the test as having
106/// failed but allow it to continue running, are not encoded in this type.
107pub type Result<T, E = TestAssertionFailure> = std::result::Result<T, E>;
108
109/// Returns a [`Result`] corresponding to the outcome of the currently running
110/// test.
111///
112/// This returns `Result::Err` precisely if the current test has recorded at
113/// least one test assertion failure via [`expect_that!`][crate::expect_that],
114/// [`expect_pred!`][crate::expect_pred], or
115/// [`GoogleTestSupport::and_log_failure`]. It can be used in concert with the
116/// `?` operator to continue execution of the test conditionally on there not
117/// having been any failure yet.
118///
119/// This requires the use of the [`#[gtest]`][crate::gtest] attribute macro.
120///
121/// ```
122/// # use googletest::prelude::*;
123/// # /* Make sure this also compiles as a doctest.
124/// #[gtest]
125/// # */
126/// # fn foo() -> u32 { 1 }
127/// # fn bar() -> u32 { 2 }
128/// fn should_fail_and_not_execute_last_assertion() -> Result<()> {
129/// #   googletest::internal::test_outcome::TestOutcome::init_current_test_outcome();
130///     expect_that!(foo(), eq(2));     // May fail, but will not abort the test.
131///     expect_that!(bar(), gt(1));     // May fail, but will not abort the test.
132///     verify_current_test_outcome()?; // Aborts the test if one of the previous assertions failed.
133///     verify_that!(foo(), gt(0))      // Does not execute if the line above aborts.
134/// }
135/// # verify_that!(should_fail_and_not_execute_last_assertion(), err(displays_as(contains_substring("Test failed")))).unwrap();
136/// ```
137#[track_caller]
138pub fn verify_current_test_outcome() -> Result<()> {
139    TestOutcome::get_current_test_outcome()
140}
141
142/// Adds to `Result` support for GoogleTest Rust functionality.
143pub trait GoogleTestSupport {
144    /// If `self` is a `Result::Err`, writes to `stdout` a failure report
145    /// and marks the test failed. Otherwise, does nothing.
146    ///
147    /// This can be used for non-fatal test assertions, for example:
148    ///
149    /// ```
150    /// # use googletest::prelude::*;
151    /// # use googletest::internal::test_outcome::TestOutcome;
152    /// # TestOutcome::init_current_test_outcome();
153    /// let actual = 42;
154    /// verify_that!(actual, eq(42)).and_log_failure();
155    ///                                  // Test still passing; nothing happens
156    /// verify_that!(actual, eq(10)).and_log_failure();
157    ///                          // Test now fails and failure output to stdout
158    /// verify_that!(actual, eq(100)).and_log_failure();
159    ///               // Test still fails and new failure also output to stdout
160    /// # TestOutcome::close_current_test_outcome::<&str>(Ok(())).unwrap_err();
161    /// ```
162    fn and_log_failure(self);
163
164    /// If `self` is a `Result::Err`, writes to `stdout` with a failure report
165    /// and the message returned by `provider`.
166    ///
167    /// This is equivalent to combining [`GoogleTestSupport::and_log_failure`]
168    /// with a call to [`GoogleTestSupport::with_failure_message`].
169    ///
170    /// Example:
171    ///
172    /// ```
173    /// # use googletest::GoogleTestSupport;
174    /// # use googletest::assertions::verify_eq;
175    /// # use googletest::internal::test_outcome::TestOutcome;
176    /// # TestOutcome::init_current_test_outcome();
177    /// let actual = 0;
178    /// verify_eq!(actual, 42)
179    ///    .and_log_failure_with_message(|| format!("Actual {} was wrong!", actual));
180    /// # TestOutcome::close_current_test_outcome::<&str>(Ok(())).unwrap_err();
181    /// ```
182    fn and_log_failure_with_message(self, provider: impl FnOnce() -> String)
183    where
184        Self: Sized,
185    {
186        self.with_failure_message(provider).and_log_failure();
187    }
188
189    /// Adds `message` to the logged failure message if `self` is a
190    /// `Result::Err`. Otherwise, does nothing.
191    ///
192    /// If this method is called more than once, only `message` from the last
193    /// invocation is output.
194    ///
195    /// For example:
196    ///
197    /// ```
198    /// # use googletest::prelude::*;
199    /// # fn should_fail() -> Result<()> {
200    /// let actual = 0;
201    /// verify_that!(actual, eq(42)).failure_message("Actual was wrong!")?;
202    /// # Ok(())
203    /// # }
204    /// # verify_that!(should_fail(), err(displays_as(contains_substring("Actual was wrong"))))
205    /// #     .unwrap();
206    /// ```
207    ///
208    /// results in the following failure message:
209    ///
210    /// ```text
211    /// Expected: actual equal to 42
212    ///   but was: 0
213    /// Actual was wrong!
214    /// ```
215    ///
216    /// One can pass a `String` too:
217    ///
218    /// ```
219    /// # use googletest::prelude::*;
220    /// # fn should_fail() -> Result<()> {
221    /// let actual = 0;
222    /// verify_that!(actual, eq(42))
223    ///    .failure_message(format!("Actual {} was wrong!", actual))?;
224    /// # Ok(())
225    /// # }
226    /// # verify_that!(should_fail(), err(displays_as(contains_substring("Actual 0 was wrong"))))
227    /// #     .unwrap();
228    /// ```
229    ///
230    /// However, consider using [`GoogleTestSupport::with_failure_message`]
231    /// instead in that case to avoid unnecessary memory allocation when the
232    /// message is not needed.
233    fn failure_message(self, message: impl Into<String>) -> Self;
234
235    /// Adds the output of the closure `provider` to the logged failure message
236    /// if `self` is a `Result::Err`. Otherwise, does nothing.
237    ///
238    /// This is analogous to [`GoogleTestSupport::failure_message`] but
239    /// only executes the closure `provider` if it actually produces the
240    /// message, thus saving possible memory allocation.
241    ///
242    /// ```
243    /// # use googletest::prelude::*;
244    /// # fn should_fail() -> Result<()> {
245    /// let actual = 0;
246    /// verify_that!(actual, eq(42))
247    ///    .with_failure_message(|| format!("Actual {} was wrong!", actual))?;
248    /// # Ok(())
249    /// # }
250    /// # verify_that!(should_fail(), err(displays_as(contains_substring("Actual 0 was wrong"))))
251    /// #     .unwrap();
252    /// ```
253    fn with_failure_message(self, provider: impl FnOnce() -> String) -> Self;
254}
255
256impl<T> GoogleTestSupport for std::result::Result<T, TestAssertionFailure> {
257    fn and_log_failure(self) {
258        TestOutcome::ensure_test_context_present();
259        if let Err(failure) = self {
260            failure.log();
261        }
262    }
263
264    fn failure_message(mut self, message: impl Into<String>) -> Self {
265        if let Err(ref mut failure) = self {
266            failure.custom_message = Some(message.into());
267        }
268        self
269    }
270
271    fn with_failure_message(mut self, provider: impl FnOnce() -> String) -> Self {
272        if let Err(ref mut failure) = self {
273            failure.custom_message = Some(provider());
274        }
275        self
276    }
277}
278
279/// Provides an extension method for converting an arbitrary type into
280/// `googletest`'s [`Result`] type.
281///
282/// A type can implement this trait to provide an easy way to return immediately
283/// from a test in conjunction with the `?` operator. This is useful for
284/// [`Option`] and [`Result`][std::result::Result] types whose `Result::Err`
285/// variant does not implement [`std::error::Error`].
286///
287/// If `Result::Err` implements [`std::error::Error`] you can just use the `?`
288/// operator directly.
289///
290/// ```ignore
291/// #[test]
292/// fn should_work() -> googletest::Result<()> {
293///     let value = something_which_can_fail().or_fail()?;
294///     let value = something_which_can_fail_with_option().or_fail()?;
295///     ...
296/// }
297///
298/// fn something_which_can_fail() -> std::result::Result<T, String> { ... }
299/// fn something_which_can_fail_with_option() -> Option<T> { ... }
300/// ```
301pub trait OrFail {
302    /// The success type of the test result.
303    type Output;
304
305    /// Converts a value into a [`Result`] containing
306    /// either the [`Self::Output`] type or a [`TestAssertionFailure`].
307    ///
308    /// The most frequently used implementations convert
309    /// `Result<T, E>` into `Result<T, TestAssertionFailure>` and
310    /// `Option<T>` into `Result<T, TestAssertionFailure>`.
311    fn or_fail(self) -> Result<Self::Output>;
312}
313
314impl<T, E: std::fmt::Debug> OrFail for std::result::Result<T, E> {
315    type Output = T;
316
317    #[track_caller]
318    fn or_fail(self) -> std::result::Result<T, TestAssertionFailure> {
319        match self {
320            Ok(t) => Ok(t),
321            Err(e) => Err(TestAssertionFailure::create(format!("{e:?}"))),
322        }
323    }
324}
325
326impl<T> OrFail for Option<T> {
327    type Output = T;
328
329    #[track_caller]
330    fn or_fail(self) -> std::result::Result<T, TestAssertionFailure> {
331        match self {
332            Some(t) => Ok(t),
333            None => Err(TestAssertionFailure::create(format!(
334                "called `Option::or_fail()` on a `Option::<{}>::None` value",
335                std::any::type_name::<T>()
336            ))),
337        }
338    }
339}
340
341#[doc(hidden)]
342pub mod __internal_macro_support {
343    use crate::fixtures::Fixture;
344
345    pub struct FixtureTearDownOnDrop<T: Fixture> {
346        fixture: Option<T>,
347    }
348
349    impl<T: Fixture> FixtureTearDownOnDrop<T> {
350        pub fn new(fixture: T) -> Self {
351            Self { fixture: Some(fixture) }
352        }
353        pub fn tear_down(mut self) -> crate::Result<()> {
354            if let Some(fixture) = self.fixture.take() {
355                fixture.tear_down()
356            } else {
357                Ok(())
358            }
359        }
360    }
361
362    impl<T: Fixture> AsRef<T> for FixtureTearDownOnDrop<T> {
363        fn as_ref(&self) -> &T {
364            self.fixture.as_ref().unwrap()
365        }
366    }
367
368    impl<T: Fixture> AsMut<T> for FixtureTearDownOnDrop<T> {
369        fn as_mut(&mut self) -> &mut T {
370            self.fixture.as_mut().unwrap()
371        }
372    }
373
374    impl<T: Fixture> Drop for FixtureTearDownOnDrop<T> {
375        fn drop(&mut self) {
376            if let Some(fixture) = self.fixture.take() {
377                fixture.tear_down().unwrap();
378            }
379        }
380    }
381}