Skip to content

Commit dbdc5cc

Browse files
Merge pull request #246 from google:add-proptest-support
PiperOrigin-RevId: 546278377
2 parents 9c92629 + dc128d6 commit dbdc5cc

File tree

7 files changed

+109
-3
lines changed

7 files changed

+109
-3
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ jobs:
4444
name: test / ubuntu / ${{ matrix.toolchain }}
4545
strategy:
4646
matrix:
47-
toolchain: [stable, 1.59.0, nightly, beta]
47+
toolchain: [stable, nightly, beta]
4848
steps:
4949
- uses: actions/checkout@v3
5050
- name: Install ${{ matrix.toolchain }}
@@ -62,7 +62,7 @@ jobs:
6262
name: test (no default features) / ubuntu / ${{ matrix.toolchain }}
6363
strategy:
6464
matrix:
65-
toolchain: [stable]
65+
toolchain: [stable, 1.59]
6666
steps:
6767
- uses: actions/checkout@v3
6868
- name: Install ${{ matrix.toolchain }}

googletest/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,11 @@ authors = [
3232

3333
[dependencies]
3434
googletest_macro = { path = "../googletest_macro", version = "0.8.1" }
35+
ansi_term = "0.12.0"
3536
anyhow = { version = "1", optional = true }
3637
num-traits = "0.2.15"
3738
regex = "1.6.0"
38-
ansi_term = "0.12.0"
39+
proptest = { version = "1.2.0", optional = true }
3940

4041
[dev-dependencies]
4142
indoc = "2"

googletest/crate_docs.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,5 +360,62 @@ fn always_fails() -> Result<()> {
360360
# always_fails().unwrap_err();
361361
```
362362

363+
## Integrations with other crates
364+
365+
GoogleTest Rust includes integrations with the
366+
[Anyhow](https://crates.io/crates/anyhow) and
367+
[Proptest](https://crates.io/crates/proptest) crates to simplify turning
368+
errors from those crates into test failures.
369+
370+
To use this, activate the `anyhow`, respectively `proptest` feature in
371+
GoogleTest Rust and invoke the extension method [`into_test_result()`] on a
372+
`Result` value in your test. For example:
373+
374+
```
375+
# use googletest::prelude::*;
376+
# #[cfg(feature = "anyhow")]
377+
# use anyhow::anyhow;
378+
# #[cfg(feature = "anyhow")]
379+
# /* The attribute macro would prevent the function from being compiled in a doctest.
380+
#[test]
381+
# */
382+
fn has_anyhow_failure() -> Result<()> {
383+
Ok(just_return_error().into_test_result()?)
384+
}
385+
386+
# #[cfg(feature = "anyhow")]
387+
fn just_return_error() -> anyhow::Result<()> {
388+
anyhow::Result::Err(anyhow!("This is an error"))
389+
}
390+
# #[cfg(feature = "anyhow")]
391+
# has_anyhow_failure().unwrap_err();
392+
```
393+
394+
One can convert Proptest test failures into GoogleTest test failures when the
395+
test is invoked with
396+
[`TestRunner::run`](https://docs.rs/proptest/latest/proptest/test_runner/struct.TestRunner.html#method.run):
397+
398+
```
399+
# use googletest::prelude::*;
400+
# #[cfg(feature = "proptest")]
401+
# use proptest::test_runner::{Config, TestRunner};
402+
# #[cfg(feature = "proptest")]
403+
# /* The attribute macro would prevent the function from being compiled in a doctest.
404+
#[test]
405+
# */
406+
fn numbers_are_greater_than_zero() -> Result<()> {
407+
let mut runner = TestRunner::new(Config::default());
408+
runner.run(&(1..100i32), |v| Ok(verify_that!(v, gt(0))?)).into_test_result()
409+
}
410+
# #[cfg(feature = "proptest")]
411+
# numbers_are_greater_than_zero().unwrap();
412+
```
413+
414+
Similarly, when the `proptest` feature is enabled, GoogleTest assertion failures
415+
can automatically be converted into Proptest
416+
[`TestCaseError`](https://docs.rs/proptest/latest/proptest/test_runner/enum.TestCaseError.html)
417+
through the `?` operator as the example above shows.
418+
363419
[`and_log_failure()`]: GoogleTestSupport::and_log_failure
420+
[`into_test_result()`]: IntoTestResult::into_test_result
364421
[`Matcher`]: matcher::Matcher

googletest/src/internal/test_outcome.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,10 @@ impl<T: std::error::Error> From<T> for TestAssertionFailure {
163163
TestAssertionFailure::create(format!("{value}"))
164164
}
165165
}
166+
167+
#[cfg(feature = "proptest")]
168+
impl From<TestAssertionFailure> for proptest::test_runner::TestCaseError {
169+
fn from(value: TestAssertionFailure) -> Self {
170+
proptest::test_runner::TestCaseError::Fail(format!("{value}").into())
171+
}
172+
}

googletest/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,3 +232,12 @@ impl<T> IntoTestResult<T> for std::result::Result<T, anyhow::Error> {
232232
self.map_err(|e| TestAssertionFailure::create(format!("{e}")))
233233
}
234234
}
235+
236+
#[cfg(feature = "proptest")]
237+
impl<OkT, CaseT: std::fmt::Debug> IntoTestResult<OkT>
238+
for std::result::Result<OkT, proptest::test_runner::TestError<CaseT>>
239+
{
240+
fn into_test_result(self) -> std::result::Result<OkT, TestAssertionFailure> {
241+
self.map_err(|e| TestAssertionFailure::create(format!("{e}")))
242+
}
243+
}

googletest/tests/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,7 @@ mod field_matcher_test;
1919
mod matches_pattern_test;
2020
mod pointwise_matcher_test;
2121
mod property_matcher_test;
22+
#[cfg(feature = "proptest")]
23+
mod proptest_integration_test;
2224
mod tuple_matcher_test;
2325
mod unordered_elements_are_matcher_test;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2023 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+
#![cfg(feature = "proptest")]
16+
17+
use googletest::prelude::*;
18+
use proptest::test_runner::{Config, TestRunner};
19+
20+
#[test]
21+
fn numbers_are_greater_than_zero() -> Result<()> {
22+
let mut runner = TestRunner::new(Config::default());
23+
runner.run(&(1..100i32), |v| Ok(verify_that!(v, gt(0))?)).into_test_result()
24+
}
25+
26+
#[test]
27+
fn strings_are_nonempty() -> Result<()> {
28+
let mut runner = TestRunner::new(Config::default());
29+
runner.run(&"[a-zA-Z0-9]+", |v| Ok(verify_that!(v, not(eq("")))?)).into_test_result()
30+
}

0 commit comments

Comments
 (0)