Skip to content

Commit 3801d22

Browse files
Merge pull request google#448 from google:fixtures
PiperOrigin-RevId: 684861200
2 parents efc2fc1 + 08bcf23 commit 3801d22

File tree

9 files changed

+471
-68
lines changed

9 files changed

+471
-68
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ jobs:
7878
name: test (no default features) / ubuntu / ${{ matrix.toolchain }}
7979
strategy:
8080
matrix:
81-
toolchain: [stable, 1.66]
81+
toolchain: [stable, 1.70.0]
8282
steps:
8383
- uses: actions/checkout@v4
8484
- name: Install ${{ matrix.toolchain }}
@@ -93,7 +93,7 @@ jobs:
9393
name: integration-test / ubuntu / ${{ matrix.toolchain }}
9494
strategy:
9595
matrix:
96-
toolchain: [stable, 1.66.0, nightly, beta]
96+
toolchain: [stable, 1.70.0, nightly, beta]
9797
steps:
9898
- uses: actions/checkout@v4
9999
- name: Install ${{ matrix.toolchain }}

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ This library brings the rich assertion types of Google's C++ testing library
2525
* A new set of assertion macros offering similar functionality to those of
2626
[GoogleTest](https://google.github.io/googletest/primer.html#assertions).
2727

28-
**The minimum supported Rust version is 1.66**.
28+
**The minimum supported Rust version is 1.70**.
2929

3030
> :warning: The API is not fully stable and may still be changed until we
3131
> publish version 1.0.

googletest/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ repository = "https://github.com/google/googletest-rust"
2222
readme = "../README.md"
2323
license = "Apache-2.0"
2424
edition = "2021"
25-
rust-version = "1.66.0"
25+
rust-version = "1.70.0"
2626
authors = [
2727
"Bradford Hovinen <[email protected]>",
2828
"Bastien Jacot-Guillarmod <[email protected]>",

googletest/src/fixtures.rs

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
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+
use std::{
16+
any::{Any, TypeId},
17+
collections::HashMap,
18+
ops::{Deref, DerefMut},
19+
sync::{Mutex, OnceLock},
20+
};
21+
22+
/// Interface for structure to be set up and torn down as part of a test.
23+
/// Types implementing `Fixture` can be passed as a reference argument to a
24+
/// test function.
25+
///
26+
/// ```ignore
27+
/// strct MyFixture { ... }
28+
///
29+
/// impl Fixture for MyFixture { ... }
30+
///
31+
/// #[gtest]
32+
/// fn test_with_fixture(my_fixture: &MyFixture) {...}
33+
/// ```
34+
pub trait Fixture: Sized {
35+
/// Factory method of the `Fixture`.
36+
///
37+
/// This method is called by the test harness before the test case
38+
/// If this method returns an `Err(...)`, then the test case is not
39+
/// evaluated and only the fixtures previously set up are torn down.
40+
fn set_up() -> crate::Result<Self>;
41+
42+
/// Clean up method for the fixture.
43+
///
44+
/// This method is called by the test harness after the test case.
45+
/// If the `Fixture` has been set up, the test harness will call this
46+
/// method, even if the test case failed or panicked.
47+
fn tear_down(self) -> crate::Result<()>;
48+
}
49+
50+
/// Interface for structure to be set up before the test case.
51+
/// Types implementing `ConsumableFixture` can be passed by value to
52+
/// a test function.
53+
///
54+
/// ```ignore
55+
/// strct MyFixture { ... }
56+
///
57+
/// impl ConsumableFixture for MyFixture { ... }
58+
///
59+
/// #[gtest]
60+
/// fn test_with_fixture(my_fixture: MyFixture) {...}
61+
/// ```
62+
pub trait ConsumableFixture: Sized {
63+
/// Factory method of the `ConsumableFixture`.
64+
///
65+
/// This method is called by the test harness before the test case.
66+
/// If this method returns an `Err(...)`, then the test case is not
67+
/// evaluated.
68+
fn set_up() -> crate::Result<Self>;
69+
}
70+
71+
/// Generic adapter to implement `ConsumableFixture` on any type implementing
72+
/// `Default`.
73+
pub struct FixtureOf<T>(T);
74+
75+
impl<T: Default> ConsumableFixture for FixtureOf<T> {
76+
fn set_up() -> crate::Result<Self> {
77+
Ok(Self(T::default()))
78+
}
79+
}
80+
81+
impl<T> Deref for FixtureOf<T> {
82+
type Target = T;
83+
84+
fn deref(&self) -> &Self::Target {
85+
&self.0
86+
}
87+
}
88+
89+
impl<T> DerefMut for FixtureOf<T> {
90+
fn deref_mut(&mut self) -> &mut Self::Target {
91+
&mut self.0
92+
}
93+
}
94+
95+
/// Interface for structure to be set up only once before all tests.
96+
/// Types implementing `StaticFixture` can be passed as a double referenced
97+
/// argument to a test function.
98+
///
99+
/// ```ignore
100+
/// strct MyFixture{ ... }
101+
///
102+
/// impl StaticFixture for MyFixture { ... }
103+
///
104+
/// #[gtest]
105+
/// fn test_with_fixture(my_fixture: &&MyFixture){...}
106+
/// ```
107+
pub trait StaticFixture: Sized + Sync + Send {
108+
/// Factory method of the `StaticFixture`.
109+
///
110+
/// This method is called by the test harness before the first test case
111+
/// using this fixture. If this method returns an `Err(...)`, then every
112+
/// test cases using this fixture are not evaluated.
113+
fn set_up_once() -> crate::Result<Self>;
114+
}
115+
116+
impl<F: StaticFixture + 'static> Fixture for &'static F {
117+
fn set_up() -> crate::Result<Self> {
118+
static ONCE_FIXTURE_REPO: OnceLock<
119+
Mutex<HashMap<TypeId, &'static (dyn Any + Sync + Send)>>,
120+
> = OnceLock::new();
121+
let mut map = ONCE_FIXTURE_REPO.get_or_init(|| Mutex::new(HashMap::new())).lock()?;
122+
let any =
123+
map.entry(TypeId::of::<F>()).or_insert_with(|| Box::leak(Box::new(F::set_up_once())));
124+
match any.downcast_ref::<crate::Result<F>>() {
125+
Some(Ok(ref fixture)) => Ok(fixture),
126+
Some(Err(e)) => Err(e.clone()),
127+
None => panic!("Downcast failed. This is a bug in GoogleTest Rust"),
128+
}
129+
}
130+
131+
// Note that this is `&F` being torn down, not `F`.
132+
fn tear_down(self) -> crate::Result<()> {
133+
Ok(())
134+
}
135+
}
136+
137+
#[cfg(test)]
138+
mod tests {
139+
140+
use std::sync::Once;
141+
142+
use super::FixtureOf;
143+
use super::StaticFixture;
144+
use crate as googletest;
145+
use crate::prelude::*;
146+
use crate::test;
147+
148+
#[test]
149+
fn fixture_no_fixture() -> Result<()> {
150+
Ok(())
151+
}
152+
153+
struct AlwaysSucceed;
154+
155+
impl Fixture for AlwaysSucceed {
156+
fn set_up() -> crate::Result<Self> {
157+
Ok(Self)
158+
}
159+
160+
fn tear_down(self) -> crate::Result<()> {
161+
Ok(())
162+
}
163+
}
164+
165+
#[test]
166+
fn fixture_one_fixture(_: &AlwaysSucceed) -> Result<()> {
167+
Ok(())
168+
}
169+
170+
#[test]
171+
fn fixture_three_fixtures(
172+
_: &AlwaysSucceed,
173+
_: &AlwaysSucceed,
174+
_: &AlwaysSucceed,
175+
) -> Result<()> {
176+
Ok(())
177+
}
178+
179+
struct NotAFixture {
180+
a_field: i32,
181+
}
182+
183+
impl Default for NotAFixture {
184+
fn default() -> Self {
185+
Self { a_field: 33 }
186+
}
187+
}
188+
189+
#[test]
190+
fn fixture_of_non_fixture(not_a_fixture: FixtureOf<NotAFixture>) -> Result<()> {
191+
verify_that!(not_a_fixture.a_field, eq(33))
192+
}
193+
194+
#[test]
195+
fn fixture_of_non_fixture_mut(mut not_a_fixture: FixtureOf<NotAFixture>) -> Result<()> {
196+
not_a_fixture.a_field += 10;
197+
verify_that!(not_a_fixture.a_field, eq(43))
198+
}
199+
struct PanickyFixture;
200+
201+
impl Fixture for PanickyFixture {
202+
fn set_up() -> crate::Result<Self> {
203+
Ok(Self)
204+
}
205+
206+
fn tear_down(self) -> crate::Result<()> {
207+
panic!("Whoooops");
208+
}
209+
}
210+
211+
#[test]
212+
#[should_panic(expected = "Whoooops")]
213+
fn fixture_teardown_called_even_if_test_fail(_: &PanickyFixture) {
214+
panic!("Test failed");
215+
}
216+
217+
struct FailingTearDown;
218+
219+
impl Fixture for FailingTearDown {
220+
fn set_up() -> crate::Result<Self> {
221+
Ok(Self)
222+
}
223+
224+
fn tear_down(self) -> crate::Result<()> {
225+
Err(googletest::TestAssertionFailure::create("It must fail!".into()))
226+
}
227+
}
228+
229+
struct OnlyOnce;
230+
231+
impl StaticFixture for OnlyOnce {
232+
fn set_up_once() -> crate::Result<Self> {
233+
static ONCE: Once = Once::new();
234+
assert!(!ONCE.is_completed());
235+
ONCE.call_once(|| {});
236+
Ok(Self)
237+
}
238+
}
239+
240+
#[test]
241+
fn static_fixture_works(_: &&OnlyOnce) {}
242+
243+
#[test]
244+
fn static_fixture_same_static_fixture_twice(once: &&OnlyOnce, twice: &&OnlyOnce) {
245+
// checks it points to the same memory address.
246+
let once: *const OnlyOnce = *once;
247+
let twice: *const OnlyOnce = *twice;
248+
expect_eq!(once, twice);
249+
}
250+
251+
struct AnotherStaticFixture;
252+
253+
impl StaticFixture for AnotherStaticFixture {
254+
fn set_up_once() -> crate::Result<Self> {
255+
Ok(Self)
256+
}
257+
}
258+
259+
#[test]
260+
fn static_fixture_two_different_static_fixtures(_: &&OnlyOnce, _: &&AnotherStaticFixture) {}
261+
}

googletest/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ extern crate quickcheck;
2222
#[macro_use]
2323
pub mod assertions;
2424
pub mod description;
25+
pub mod fixtures;
2526
pub mod internal;
2627
pub mod matcher;
2728
pub mod matcher_support;
@@ -42,6 +43,7 @@ pub mod matchers;
4243
/// }
4344
/// ```
4445
pub mod prelude {
46+
pub use super::fixtures::{ConsumableFixture, Fixture, FixtureOf, StaticFixture};
4547
pub use super::gtest;
4648
pub use super::matcher::{Matcher, MatcherBase};
4749
pub use super::matchers::*;

googletest_macro/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ authors = [
2828
[dependencies]
2929
quote = "1.0.33"
3030
syn = {version = "2.0.39", features = ["full"]}
31+
proc-macro2 = "1.0.85"
3132

3233
[lib]
3334
name = "googletest_macro"

0 commit comments

Comments
 (0)