build(rust): vendor googletest crate
This commit was merged in pull request #76.
This commit is contained in:
1 parent
a6fe84190e
commit
6887b104d6
576 files changed
+284290
-2
No files matched your search
+367
@@ -0,0 +1,367 @@
|
||||
# GoogleTest Rust
|
||||
|
||||
[![crates.io][crates-badge]][crates-url]
|
||||
[![docs.rs][docs-badge]][docs-url]
|
||||
[![Apache licensed][license-badge]][license-url]
|
||||
[![Build Status][actions-badge]][actions-url]
|
||||
[![OpenSSF Best Practices][openssf-badge]][openssf-url]
|
||||
|
||||
[crates-badge]: https://img.shields.io/crates/v/googletest.svg
|
||||
[crates-url]: https://crates.io/crates/googletest
|
||||
[docs-badge]: https://img.shields.io/badge/docs.rs-googletest-66c2a5
|
||||
[docs-url]: https://docs.rs/googletest/*/googletest/
|
||||
[license-badge]: https://img.shields.io/badge/license-Apache-blue.svg
|
||||
[license-url]: https://github.com/google/googletest-rust/blob/main/LICENSE
|
||||
[actions-badge]: https://github.com/google/googletest-rust/workflows/CI/badge.svg
|
||||
[actions-url]: https://github.com/google/googletest-rust/actions?query=workflow%3ACI+branch%3Amain
|
||||
[openssf-badge]: https://www.bestpractices.dev/projects/10037/badge
|
||||
[openssf-url]: https://www.bestpractices.dev/projects/10037
|
||||
|
||||
This library brings the rich assertion types of Google's C++ testing library
|
||||
[GoogleTest](https://github.com/google/googletest) to Rust. It provides:
|
||||
|
||||
* A framework for writing matchers which can be combined to make a wide range
|
||||
of assertions on data,
|
||||
* A rich set of matchers providing similar functionality to those included in
|
||||
[GoogleTest](https://google.github.io/googletest/reference/matchers.html),
|
||||
and
|
||||
* A new set of assertion macros offering similar functionality to those of
|
||||
[GoogleTest](https://google.github.io/googletest/primer.html#assertions).
|
||||
|
||||
**The minimum supported Rust version is 1.85**.
|
||||
|
||||
> :warning: The API is not fully stable and may still be changed until we
|
||||
> publish version 1.0.
|
||||
>
|
||||
> Moreover, any items or modules starting with `__` (double underscores) must
|
||||
> not be used directly. Those items or modules are only for internal uses and
|
||||
> their API may change without a major version update.
|
||||
|
||||
## Learning resources
|
||||
|
||||
If you're just getting started with `googletest`, consider going through
|
||||
the first chapter of
|
||||
["Advanced testing for Rust applications"](https://github.com/mainmatter/rust-advanced-testing-workshop),
|
||||
a self-guided Rust course: it provides a guided introduction to the library,
|
||||
with exercises to help you get comfortable with `googletest` macros,
|
||||
its matchers and its overall philosophy.
|
||||
|
||||
## Assertions and matchers
|
||||
|
||||
The core of GoogleTest is its *matchers*. Matchers indicate what aspect of an
|
||||
actual value one is asserting: (in-)equality, containment, regular expression
|
||||
matching, and so on.
|
||||
|
||||
To make an assertion using a matcher, GoogleTest offers three macros:
|
||||
|
||||
* [`assert_that!`] panics if the assertion fails, aborting the test.
|
||||
* [`expect_that!`] logs an assertion failure, marking the test as having
|
||||
failed, but allows the test to continue running (called a _non-fatal
|
||||
assertion_). It requires the use of the [`gtest`] attribute macro
|
||||
on the test itself.
|
||||
* [`verify_that!`] has no side effects and evaluates to a [`Result<()>`] whose
|
||||
`Err` variant describes the assertion failure, if there is one. In
|
||||
combination with the
|
||||
[`?` operator](https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator),
|
||||
this can be used to abort the test on assertion failure without panicking. It
|
||||
is also the building block for the other two macros above.
|
||||
|
||||
For example:
|
||||
|
||||
```rust
|
||||
use googletest::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn fails_and_panics() {
|
||||
let value = 2;
|
||||
assert_that!(value, eq(4));
|
||||
}
|
||||
|
||||
#[gtest]
|
||||
fn two_logged_failures() {
|
||||
let value = 2;
|
||||
expect_that!(value, eq(4)); // Test now failed, but continues executing.
|
||||
expect_that!(value, eq(5)); // Second failure is also logged.
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fails_immediately_without_panic() -> Result<()> {
|
||||
let value = 2;
|
||||
verify_that!(value, eq(4))?; // Test fails and aborts.
|
||||
verify_that!(value, eq(2))?; // Never executes.
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_assertion() -> Result<()> {
|
||||
let value = 2;
|
||||
verify_that!(value, eq(4)) // One can also just return the last assertion.
|
||||
}
|
||||
```
|
||||
|
||||
This library includes a rich set of matchers, covering:
|
||||
|
||||
* Equality, numeric inequality, and approximate equality;
|
||||
* Strings and regular expressions;
|
||||
* Containers and set-theoretic matching.
|
||||
|
||||
Matchers are composable:
|
||||
|
||||
```rust
|
||||
use googletest::prelude::*;
|
||||
|
||||
#[gtest]
|
||||
fn contains_at_least_one_item_at_least_3() {
|
||||
let value = vec![1, 2, 3];
|
||||
expect_that!(value, contains(ge(3)));
|
||||
}
|
||||
```
|
||||
|
||||
They can also be logically combined:
|
||||
|
||||
```rust
|
||||
use googletest::prelude::*;
|
||||
|
||||
#[gtest]
|
||||
fn strictly_between_9_and_11() {
|
||||
let value = 10;
|
||||
expect_that!(value, gt(9).and(not(ge(11))));
|
||||
}
|
||||
```
|
||||
|
||||
## Pattern-matching
|
||||
|
||||
One can use the macro [`matches_pattern!`] to create a composite matcher for a
|
||||
struct or enum that matches fields with other matchers:
|
||||
|
||||
```rust
|
||||
use googletest::prelude::*;
|
||||
|
||||
struct AStruct {
|
||||
a_field: i32,
|
||||
another_field: i32,
|
||||
a_third_field: &'static str,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn struct_has_expected_values() {
|
||||
let value = AStruct {
|
||||
a_field: 10,
|
||||
another_field: 100,
|
||||
a_third_field: "A correct value",
|
||||
};
|
||||
expect_that!(value, matches_pattern!(AStruct {
|
||||
a_field: eq(10),
|
||||
another_field: gt(50),
|
||||
a_third_field: contains_substring("correct"),
|
||||
}));
|
||||
}
|
||||
```
|
||||
|
||||
## Writing matchers
|
||||
|
||||
One can extend the library by writing additional matchers. To do so, create a
|
||||
struct holding the matcher's data and have it implement the trait [`Matcher`]:
|
||||
|
||||
```rust
|
||||
struct MyEqMatcher<T> {
|
||||
expected: T,
|
||||
}
|
||||
|
||||
impl<T: PartialEq + Debug + Copy> Matcher<T> for MyEqMatcher<T> {
|
||||
fn matches(&self, actual: T) -> MatcherResult {
|
||||
(self.expected == actual).into()
|
||||
}
|
||||
|
||||
fn describe(&self, matcher_result: MatcherResult) -> String {
|
||||
match matcher_result {
|
||||
MatcherResult::Match => {
|
||||
format!("is equal to {:?} the way I define it", self.expected)
|
||||
}
|
||||
MatcherResult::NoMatch => {
|
||||
format!("isn't equal to {:?} the way I define it", self.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
It is recommended to expose a function which constructs the matcher:
|
||||
|
||||
```rust
|
||||
pub fn eq_my_way<T: PartialEq + Debug>(expected: T) -> impl Matcher<T> {
|
||||
MyEqMatcher { expected }
|
||||
}
|
||||
```
|
||||
|
||||
The new matcher can then be used in the assertion macros:
|
||||
|
||||
```rust
|
||||
#[gtest]
|
||||
fn should_be_equal_by_my_definition() {
|
||||
expect_that!(10, eq_my_way(10));
|
||||
}
|
||||
```
|
||||
|
||||
## Non-fatal assertions
|
||||
|
||||
Using non-fatal assertions, a single test is able to log multiple assertion
|
||||
failures. Any single assertion failure causes the test to be considered having
|
||||
failed, but execution continues until the test completes or otherwise aborts.
|
||||
|
||||
This is analogous to the `EXPECT_*` family of macros in GoogleTest.
|
||||
|
||||
To make a non-fatal assertion, use the macro [`expect_that!`]. The test must
|
||||
also be marked with [`gtest`] instead of the Rust-standard `#[test]`.
|
||||
|
||||
```rust
|
||||
use googletest::prelude::*;
|
||||
|
||||
#[gtest]
|
||||
fn three_non_fatal_assertions() {
|
||||
let value = 2;
|
||||
expect_that!(value, eq(2)); // Passes; test still considered passing.
|
||||
expect_that!(value, eq(3)); // Fails; logs failure and marks the test failed.
|
||||
expect_that!(value, eq(4)); // A second failure, also logged.
|
||||
}
|
||||
```
|
||||
|
||||
This can be used in the same tests as `verify_that!`, in which case the test
|
||||
function must also return [`Result<()>`]:
|
||||
|
||||
```rust
|
||||
use googletest::prelude::*;
|
||||
|
||||
#[gtest]
|
||||
fn failing_non_fatal_assertion() -> Result<()> {
|
||||
let value = 2;
|
||||
expect_that!(value, eq(3)); // Just marks the test as having failed.
|
||||
verify_that!(value, eq(2))?; // Passes, so does not abort the test.
|
||||
Ok(()) // Because of the failing expect_that! call above, the
|
||||
// test fails despite returning Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
```rust
|
||||
use googletest::prelude::*;
|
||||
|
||||
#[gtest]
|
||||
fn failing_fatal_assertion_after_non_fatal_assertion() -> Result<()> {
|
||||
let value = 2;
|
||||
verify_that!(value, eq(3))?; // Fails and aborts the test.
|
||||
expect_that!(value, eq(3)); // Never executes, since the test already aborted.
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
### Interoperability
|
||||
|
||||
You can use the `#[gtest]` macro together with many other libraries
|
||||
such as [rstest](https://crates.io/crates/rstest). Just apply both attribute
|
||||
macros to the test:
|
||||
|
||||
```rust
|
||||
#[gtest]
|
||||
#[rstest]
|
||||
#[case(1)]
|
||||
#[case(2)]
|
||||
#[case(3)]
|
||||
fn rstest_works_with_google_test(#[case] value: u32) -> Result<()> {
|
||||
verify_that!(value, gt(0))
|
||||
}
|
||||
```
|
||||
|
||||
Make sure to put `#[gtest]` *before* `#[rstest]`. Otherwise the
|
||||
annotated test will run twice, since both macros will attempt to register a test
|
||||
with the Rust test harness.
|
||||
|
||||
The macro also works together with
|
||||
[async tests with Tokio](https://docs.rs/tokio/latest/tokio/attr.gtest.html) in
|
||||
the same way:
|
||||
|
||||
```rust
|
||||
#[gtest]
|
||||
#[tokio::test]
|
||||
async fn should_work_with_tokio() -> Result<()> {
|
||||
verify_that!(3, gt(0))
|
||||
}
|
||||
```
|
||||
|
||||
There is one caveat when running async tests: test failure reporting through
|
||||
`and_log_failure` will not work properly if the assertion occurs on a different
|
||||
thread than runs the test.
|
||||
|
||||
## Predicate assertions
|
||||
|
||||
The macro [`verify_pred!`] provides predicate assertions analogous to
|
||||
GoogleTest's `EXPECT_PRED` family of macros. Wrap an invocation of a predicate
|
||||
in a `verify_pred!` invocation to turn that into a test assertion which passes
|
||||
precisely when the predicate returns `true`:
|
||||
|
||||
```rust
|
||||
fn stuff_is_correct(x: i32, y: i32) -> bool {
|
||||
x == y
|
||||
}
|
||||
|
||||
let x = 3;
|
||||
let y = 4;
|
||||
verify_pred!(stuff_is_correct(x, y))?;
|
||||
```
|
||||
|
||||
The assertion failure message shows the arguments and the values to which they
|
||||
evaluate:
|
||||
|
||||
```
|
||||
stuff_is_correct(x, y) was false with
|
||||
x = 3,
|
||||
y = 4
|
||||
```
|
||||
|
||||
The `verify_pred!` invocation evaluates to a [`Result<()>`] just like
|
||||
[`verify_that!`]. There is also a macro [`expect_pred!`] to make a non-fatal
|
||||
predicaticate assertion.
|
||||
|
||||
## Unconditionally generating a test failure
|
||||
|
||||
The macro [`fail!`] unconditionally evaluates to a `Result` indicating a test
|
||||
failure. It can be used analogously to [`verify_that!`] and [`verify_pred!`] to
|
||||
cause a test to fail, with an optional formatted message:
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
fn always_fails() -> Result<()> {
|
||||
fail!("This test must fail with {}", "today")
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
This library is configurable through environment variables. Since the
|
||||
configuration does not impact whether a test fails or not but how a failure is
|
||||
displayed, we recommend setting those variables in the personal
|
||||
`~/.cargo/config.toml` instead of in the project-scoped `Cargo.toml`.
|
||||
|
||||
### Configuration variable list
|
||||
|
||||
| Variable name | Description |
|
||||
| ------------- | ------------------------------------------------------- |
|
||||
| NO_COLOR | Disables colored output. See <https://no-color.org/>. |
|
||||
| FORCE_COLOR | Forces colors even when the output is piped to a file. |
|
||||
|
||||
## Contributing Changes
|
||||
|
||||
Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute
|
||||
to this project.
|
||||
|
||||
[`and_log_failure()`]: https://docs.rs/googletest/*/googletest/trait.GoogleTestSupport.html#tymethod.and_log_failure
|
||||
[`assert_that!`]: https://docs.rs/googletest/*/googletest/macro.assert_that.html
|
||||
[`expect_pred!`]: https://docs.rs/googletest/*/googletest/macro.expect_pred.html
|
||||
[`expect_that!`]: https://docs.rs/googletest/*/googletest/macro.expect_that.html
|
||||
[`fail!`]: https://docs.rs/googletest/*/googletest/macro.fail.html
|
||||
[`gtest`]: https://docs.rs/googletest/*/googletest/attr.gtest.html
|
||||
[`matches_pattern!`]: https://docs.rs/googletest/*/googletest/macro.matches_pattern.html
|
||||
[`verify_pred!`]: https://docs.rs/googletest/*/googletest/macro.verify_pred.html
|
||||
[`verify_that!`]: https://docs.rs/googletest/*/googletest/macro.verify_that.html
|
||||
[`Describe`]: https://docs.rs/googletest/*/googletest/matcher/trait.Describe.html
|
||||
[`Matcher`]: https://docs.rs/googletest/*/googletest/matcher/trait.Matcher.html
|
||||
[`Result<()>`]: https://docs.rs/googletest/*/googletest/type.Result.html
|
||||
Reference in new issue
Block a user