Comments (12)
Yes, it'll be very nice to have this feature. Freak free to open a PR.
from rstest.
@narpfel I've implemented it in https://github.com/la10736/rstest/tree/by_ref
I didn't published it yet because I need to do some refactor till merge it. You can try it ... let me know if it's ok
from rstest.
While I was fixing #230 I noted that the following syntax will work
use std::cell::Cell;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum E<'a> {
A(bool),
B(&'a Cell<E<'a>>),
}
fn make_e_from_bool<'a>(b: bool) -> E<'a> {
E::A(b)
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
#[rstest]
#[case(true, E::A(true))]
fn it_works<'a>(#[case] b: bool, #[case] expected: E<'a>) {
let actual = make_e_from_bool(b);
assert_eq!(actual, expected);
}
}
Is this code fine for you?
from rstest.
Unfortunately not. This is my real code:
#[rstest]
#[case::bool("true", Value::Bool(true))]
fn test_eval<'a>(bump: &'a Bump, #[case] src: &'static str, #[case] expected: Value<'a>) {
pretty_assertions::assert_eq!(eval_str(bump, src).unwrap(), expected);
}
bump
is actually used by the code under test and can’t be removed.
from rstest.
And what about to use #[once]
here? Is it an issue to have a just an Bump
instance?
With the unreleased version follow code works
use std::cell::Cell;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum E<'a> {
A(bool),
B(&'a Cell<E<'a>>),
}
fn make_e_from_bool<'a>(_bump: &'a (), b: bool) -> E<'a> {
E::A(b)
}
fn new_bump() {}
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
#[fixture]
#[once]
fn bump() -> () {}
#[rstest]
#[case(true, E::A(true))]
fn it_works<'a>(bump: &'a (), #[case] b: bool, #[case] expected: E<'a>) {
let actual = make_e_from_bool(&bump, b);
assert_eq!(actual, expected);
}
}
from rstest.
A #[once]
fixture would be possible, but I’d like to avoid it if possible because then the tests would leak memory, and that’s annoying when testing with tools that flag memory leaks such as miri or valgrind.
from rstest.
That's new for me... why static reference is marked as memory leak in valgrind? Ok, verbose set up will report it as an not released static reference but should not be an issue.
Anyway I cannot accept a PR about this just because is a breaking change when #[once]
fixture is used.
Beside that my next feature will be a #[map]
attribute that should be help to fix this case too: follow code should will work
use std::cell::Cell;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum E<'a> {
A(bool),
B(&'a Cell<E<'a>>),
}
fn make_e_from_bool<'a>(_bump: &'a (), b: bool) -> E<'a> {
E::A(b)
}
fn new_bump() {}
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
#[fixture]
fn bump() -> () {}
#[rstest]
#[case(true, E::A(true))]
fn it_works<'a>(#[map(|b| &b)] bump: &'a (), #[case] b: bool, #[case] expected: E<'a>) {
let actual = make_e_from_bool(&bump, b);
assert_eq!(actual, expected);
}
}
from rstest.
I think that even with a #[once]
fixture it will not work, because bumpalo::Bump
is !Sync
and has to be wrapped in a Mutex
. And to lock it, you create a MutexGuard
, which derefs to the Bump
. But... the reference’s lifetime is bounded by the MutexGuard
’s lifetime, so we’re back to exactly the same problem as in the initial code.
Anyway I cannot accept a PR about this just because is a breaking change when #[once] fixture is used.
I think there’s a non-breaking way to implement this by annotating fixture parameters with an attribute to enable pass-by-reference, like this:
#[fixture]
fn f() -> u32 { 42 }
#[rstest]
fn test(#[by_reference] f: &u32) {
assert_eq!(*f, 42);
}
Beside that my next feature will be a #[map] attribute that should be help to fix this case
How would that work? It looks like the closure returns a reference to a local variable?
from rstest.
I think that even with a
#[once]
fixture it will not work, becausebumpalo::Bump
is!Sync
and has to be wrapped in aMutex
. And to lock it, you create aMutexGuard
, which derefs to theBump
. But... the reference’s lifetime is bounded by theMutexGuard
’s lifetime, so we’re back to exactly the same problem as in the initial code.
Right!
Anyway I cannot accept a PR about this just because is a breaking change when #[once] fixture is used.
I think there’s a non-breaking way to implement this by annotating fixture parameters with an attribute to enable pass-by-reference, like this:
#[fixture] fn f() -> u32 { 42 } #[rstest] fn test(#[by_reference] f: &u32) { assert_eq!(*f, 42); }Beside that my next feature will be a #[map] attribute that should be help to fix this case
How would that work? It looks like the closure returns a reference to a local variable?
Yes, that's feasible. Maybe the right syntax can be just #[ref]
and should work for every kind of input.
from rstest.
Maybe the right syntax can be just #[ref]
I don’t think #[ref]
can be an attribute because ref
is a keyword. #[r#ref]
would be possible, but at that point I think #[by_ref]
is better.
and should work for every kind of input.
You mean also for #[case]
, #[values]
, and #[files]
? That would need some more work in this code
rstest/rstest_macros/src/parse/rstest.rs
Lines 134 to 140 in 06a2117
fn f(#[case] #[by_reference] x: u32)
as both a test case input and a fixture when both parsers recognise #[by_reference]
.
For now I’d like to get this feature working (and robust) for #[fixture]
first and then maybe look into supporting the other input types.
from rstest.
Ok #[by_ref]
it's a good compromise. I've an idea of how to implement it in a generic way. My idea is to catch #[by_ref]
and set it as argument attribute and just use &
we I use this argument on calling test function.
Example :
#[fixture]
fn f() -> u32 { 42 }
#[rstest]
#[case(42)]
fn test(#[by_ref] f: &u32, #[case] #[by_ref] c: &u32, #[values(42, 142)] #[by_ref] v: &u32) {
assert_eq!(f, c);
assert_eq!(*c, *v%100);
}
it'll be expanded in something like follow:
mod f {
fn default() -> u32 {
42
}
}
fn test(f: &u32, c: &u32, v: &u32) {
assert_eq!(f, c);
assert_eq!(*c, *v%100);
}
mod test {
use super::*;
mod case_1 {
use super::*;
#[test]
fn v_1_42() {
let f = f::default();
let c = 42;
let v = 42;
test(&f, &c, &v)
}
#[test]
fn v_2_142() {
let f = f::default();
let c = 42;
let v = 142;
test(&f, &c, &v)
}
}
}
from rstest.
That branch works for my use case. Thanks!
from rstest.
Related Issues (20)
- Injecting static types HOT 5
- Create a fixture from `files` attribute HOT 3
- skip cases based on feature flag? HOT 5
- `#[once]` fixtures are unsound for types that are not `Sync` HOT 4
- clippy::duplicated_attributes warning with rust 1.79.0-nightly HOT 3
- Update `rstest_reuse` docs and release new version
- `#[from(source)]` should accept path also and not just idents
- rstest_reuse: "the `async` keyword is missing from the function declaration" HOT 1
- replace return <expr>; with <expr> [needless_return] HOT 3
- Support dynamic `#[values]` HOT 1
- Feature: Optional label in the `#[case...]` HOT 1
- Dynamically set #[values(..)] HOT 1
- New test files are only recognized after `cargo clean` HOT 4
- feat: provide a cargo feature to disable the proc macro inference in #221 HOT 2
- consider adding a `wasm-bindgen` feature HOT 1
- Recommendation on choosing between different sets of `#[values(...)]`?
- Mixing `#[rstest]` and `#[serial]` breaks VS Code's IntelliSense with rust-analyzer HOT 3
- Possibility of resolving a fixture only once per test?
- Automatically test all variants of an enum HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rstest.