From d9523f033153102911d5697930dbd9bff8a1a990 Mon Sep 17 00:00:00 2001 From: michele Date: Sat, 13 Nov 2021 18:38:22 +0100 Subject: [PATCH] #119 async once fixtere should raise error --- src/error.rs | 11 ++++++++++ src/parse/fixture.rs | 34 +++++++++++++++++++------------ src/parse/mod.rs | 10 ++++----- src/refident.rs | 9 ++++++++ tests/fixture/mod.rs | 15 ++++++++++++++ tests/resources/fixture/errors.rs | 5 +++++ 6 files changed, 66 insertions(+), 18 deletions(-) diff --git a/src/error.rs b/src/error.rs index 5c88bdc..09e05a2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -25,10 +25,21 @@ pub(crate) fn rstest(test: &ItemFn, info: &RsTestInfo) -> TokenStream { 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)) .map(|e| e.to_compile_error()) .collect() } +fn async_once<'a>(test: &'a ItemFn, info: &FixtureInfo) -> Errors<'a> { + match (test.sig.asyncness, info.attributes.get_once()) { + (Some(_asyncness), Some(once)) => Box::new(std::iter::once(syn::Error::new( + once.span(), + "Cannot apply #[once] to async fixture.", + ))), + _ => Box::new(std::iter::empty()), + } +} + #[derive(Debug, Default)] pub(crate) struct ErrorsVec(Vec); diff --git a/src/parse/fixture.rs b/src/parse/fixture.rs index 8e14722..624eb70 100644 --- a/src/parse/fixture.rs +++ b/src/parse/fixture.rs @@ -11,7 +11,12 @@ use super::{ extract_partials_return_type, parse_vector_trailing_till_double_comma, Attributes, ExtendWithFunctionAttrs, Fixture, }; -use crate::{error::ErrorsVec, parse::extract_once, refident::RefIdent, utils::attr_is}; +use crate::{ + error::ErrorsVec, + parse::extract_once, + refident::{MaybeIdent, RefIdent}, + utils::attr_is, +}; use crate::{parse::Attribute, utils::attr_in}; use proc_macro2::TokenStream; use quote::{format_ident, ToTokens}; @@ -54,7 +59,7 @@ impl ExtendWithFunctionAttrs for FixtureInfo { defaults, default_return_type, partials_return_type, - is_once + once ) = merge_errors!( extract_fixtures(item_fn), extract_defaults(item_fn), @@ -74,9 +79,10 @@ impl ExtendWithFunctionAttrs for FixtureInfo { for (id, return_type) in partials_return_type { self.attributes.set_partial_return_type(id, return_type); } - if is_once { - self.attributes.set_once(); - } + match once { + Some(ident) => self.attributes.set_once(ident), + None => {} + }; Ok(()) } } @@ -289,16 +295,18 @@ impl FixtureModifiers { )) } - pub(crate) fn set_once(&mut self) { - self.inner - .attributes - .push(Attribute::Attr(format_ident!("once"))) + pub(crate) fn set_once(&mut self, once: syn::Ident) { + self.inner.attributes.push(Attribute::Attr(once)) } - pub(crate) fn is_once(&self) -> bool { + pub(crate) fn get_once(&self) -> Option<&Ident> { self.iter() .find(|&a| a == &Attribute::Attr(format_ident!("once"))) - .is_some() + .and_then(|a| a.maybe_ident()) + } + + pub(crate) fn is_once(&self) -> bool { + self.get_once().is_some() } fn extract_type(&self, attr_name: &str) -> Option { @@ -566,7 +574,7 @@ mod extend { info.extend_with_function_attrs(&mut item_fn).unwrap(); - assert!(info.attributes.is_once(),); + assert!(info.attributes.is_once()); } #[test] @@ -580,7 +588,7 @@ mod extend { info.extend_with_function_attrs(&mut item_fn).unwrap(); - assert!(!info.attributes.is_once(),); + assert!(!info.attributes.is_once()); } mod raise_error { diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 63c1205..d9baf25 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -224,7 +224,7 @@ pub(crate) fn extract_partials_return_type( partials_type_extractor.take() } -pub(crate) fn extract_once(item_fn: &mut ItemFn) -> Result { +pub(crate) fn extract_once(item_fn: &mut ItemFn) -> Result, ErrorsVec> { let mut extractor = IsOnceAttributeFunctionExtractor::default(); extractor.visit_item_fn_mut(item_fn); extractor.take() @@ -362,17 +362,17 @@ impl VisitMut for PartialsTypeFunctionExtractor { /// Simple struct used to visit function attributes and extract once /// type -struct IsOnceAttributeFunctionExtractor(Result); +struct IsOnceAttributeFunctionExtractor(Result, ErrorsVec>); impl IsOnceAttributeFunctionExtractor { - fn take(self) -> Result { + fn take(self) -> Result, ErrorsVec> { self.0 } } impl Default for IsOnceAttributeFunctionExtractor { fn default() -> Self { - Self(Ok(false)) + Self(Ok(None)) } } @@ -384,7 +384,7 @@ impl VisitMut for IsOnceAttributeFunctionExtractor { node.attrs = remain; if onces.len() == 1 { - self.0 = Ok(true); + self.0 = Ok(onces[0].path.get_ident().cloned()); } else if onces.len() > 1 { self.0 = Err(onces .into_iter() diff --git a/src/refident.rs b/src/refident.rs index e3083f1..2041bf4 100644 --- a/src/refident.rs +++ b/src/refident.rs @@ -75,3 +75,12 @@ impl MaybeIdent for syn::GenericParam { } } } + +impl MaybeIdent for crate::parse::Attribute { + fn maybe_ident(&self) -> Option<&Ident> { + use crate::parse::Attribute::*; + match self { + Attr(ident) | Tagged(ident, _) | Type(ident, _) => Some(ident), + } + } +} diff --git a/tests/fixture/mod.rs b/tests/fixture/mod.rs index 1cb0517..365fdf6 100644 --- a/tests/fixture/mod.rs +++ b/tests/fixture/mod.rs @@ -290,5 +290,20 @@ mod should { ) .unindent() ); + + assert_in!( + output.stderr.str(), + format!( + r#" + error: Cannot apply #[once] to async fixture. + --> {}/src/lib.rs:38:3 + | + 38 | #[once] + | ^^^^ + "#, + name + ) + .unindent() + ); } } diff --git a/tests/resources/fixture/errors.rs b/tests/resources/fixture/errors.rs index aac0846..d465d9e 100644 --- a/tests/resources/fixture/errors.rs +++ b/tests/resources/fixture/errors.rs @@ -33,3 +33,8 @@ fn f(name: &str) -> String { #[fixture(f("first"), f("second"))] fn error_inject_a_fixture_more_than_once(f: String) { } + +#[fixture] +#[once] +async fn error_async_once_fixture() { +} \ No newline at end of file