Skip to content

Commit

Permalink
#119 Implemented error handling in for generics
Browse files Browse the repository at this point in the history
  • Loading branch information
la10736 committed Nov 27, 2021
1 parent a4e34f2 commit 0fb498f
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 3 deletions.
88 changes: 86 additions & 2 deletions src/error.rs
Expand Up @@ -2,8 +2,8 @@
use std::collections::HashMap;

use proc_macro2::TokenStream;
use syn::spanned::Spanned;
use syn::ItemFn;
use syn::{spanned::Spanned, visit::Visit};
use syn::{visit, ItemFn};

use crate::parse::{
fixture::FixtureInfo,
Expand All @@ -26,6 +26,7 @@ pub(crate) fn fixture(test: &ItemFn, info: &FixtureInfo) -> TokenStream {
missed_arguments(test, info.data.items.iter())
.chain(duplicate_arguments(info.data.items.iter()))
.chain(async_once(test, &info))
.chain(generics_once(test, &info))
.map(|e| e.to_compile_error())
.collect()
}
Expand All @@ -40,6 +41,44 @@ fn async_once<'a>(test: &'a ItemFn, info: &FixtureInfo) -> Errors<'a> {
}
}

#[derive(Default)]
struct SearchImpl(bool);

impl<'ast> Visit<'ast> for SearchImpl {
fn visit_type(&mut self, i: &'ast syn::Type) {
if self.0 {
return;
}
match i {
syn::Type::ImplTrait(_) => self.0 = true,
_ => {}
}
visit::visit_type(self, i);
}
}

impl SearchImpl {
fn function_has_some_impl(f: &ItemFn) -> bool {
let mut s = SearchImpl::default();
visit::visit_item_fn(&mut s, f);
s.0
}
}

fn has_some_generics(test: &ItemFn) -> bool {
test.sig.generics.params.len() > 0 || SearchImpl::function_has_some_impl(test)
}

fn generics_once<'a>(test: &'a ItemFn, info: &FixtureInfo) -> Errors<'a> {
match (has_some_generics(test), info.attributes.get_once()) {
(true, Some(once)) => Box::new(std::iter::once(syn::Error::new(
once.span(),
"Cannot apply #[once] on generic fixture.",
))),
_ => Box::new(std::iter::empty()),
}
}

#[derive(Debug, Default)]
pub(crate) struct ErrorsVec(Vec<syn::Error>);

Expand Down Expand Up @@ -189,3 +228,48 @@ fn case_args_without_cases(params: &RsTestData) -> Errors {
}
Box::new(std::iter::empty())
}

#[cfg(test)]
mod test {
use crate::test::{assert_eq, *};
use rstest_test::assert_in;

use super::*;

#[rstest]
#[case::generics("fn f<G: SomeTrait>(){}")]
#[case::const_generics("fn f<const N: usize>(){}")]
#[case::lifetimes("fn f<'a>(){}")]
#[case::use_impl_in_answer("fn f() -> impl Iterator<Item=u32>{}")]
#[case::use_impl_in_argumets("fn f(it: impl Iterator<Item=u32>){}")]
#[should_panic]
#[case::sanity_check_with_no_generics("fn f() {}")]
fn generics_once_should_return_error(#[case] f: &str) {
let f: ItemFn = f.ast();
let info = FixtureInfo::default().with_once();

let errors = generics_once(&f, &info);

let out = errors
.map(|e| format!("{:?}", e))
.collect::<Vec<_>>()
.join("-----------------------\n");

assert_in!(out, "Cannot apply #[once] on generic fixture.");
}

#[rstest]
#[case::generics("fn f<G: SomeTrait>(){}")]
#[case::const_generics("fn f<const N: usize>(){}")]
#[case::lifetimes("fn f<'a>(){}")]
#[case::use_impl_in_answer("fn f() -> impl Iterator<Item=u32>{}")]
#[case::use_impl_in_argumets("fn f(it: impl Iterator<Item=u32>){}")]
fn generics_once_should_not_return_if_no_once(#[case] f: &str) {
let f: ItemFn = f.ast();
let info = FixtureInfo::default();

let errors = generics_once(&f, &info);

assert_eq!(0, errors.count());
}
}
30 changes: 30 additions & 0 deletions tests/fixture/mod.rs
Expand Up @@ -306,5 +306,35 @@ mod should {
)
.unindent()
);

assert_in!(
output.stderr.str(),
format!(
r#"
error: Cannot apply #[once] on generic fixture.
--> {}/src/lib.rs:43:3
|
43 | #[once]
| ^^^^
"#,
name
)
.unindent()
);

assert_in!(
output.stderr.str(),
format!(
r#"
error: Cannot apply #[once] on generic fixture.
--> {}/src/lib.rs:49:3
|
49 | #[once]
| ^^^^
"#,
name
)
.unindent()
);
}
}
14 changes: 13 additions & 1 deletion tests/resources/fixture/errors.rs
Expand Up @@ -37,4 +37,16 @@ fn error_inject_a_fixture_more_than_once(f: String) {
#[fixture]
#[once]
async fn error_async_once_fixture() {
}
}

#[fixture]
#[once]
fn error_generics_once_fixture<T: std::fmt::Debug>() -> T {
42
}

#[fixture]
#[once]
fn error_generics_once_fixture() -> impl Iterator<Item: u32> {
std::iter::once(42)
}

0 comments on commit 0fb498f

Please sign in to comment.