Skip to content

Commit

Permalink
#121: Implementation and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
la10736 committed Mar 5, 2022
1 parent e97560a commit d075e12
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 17 deletions.
44 changes: 28 additions & 16 deletions rstest_reuse/src/lib.rs
Expand Up @@ -139,8 +139,8 @@

extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{self, parse, parse::Parse, parse_macro_input, Ident, ItemFn, Token};
use quote::{format_ident, quote};
use syn::{self, parse, parse::Parse, parse_macro_input, Attribute, ItemFn, Path, Token};

struct MergeAttrs {
template: ItemFn,
Expand Down Expand Up @@ -196,27 +196,39 @@ pub fn merge_attrs(item: TokenStream) -> TokenStream {
tokens.into()
}

fn get_export(attributes: &[Attribute]) -> Option<&Attribute> {
attributes
.into_iter()
.find(|&attr| attr.path.is_ident(&format_ident!("export")))
}

/// Define a template where the name is given from the function name. This attribute register all
/// attributes. The function signature don't really mater but to make it clear is better that you
/// use a signature like if you're wrinting a standard `rstest`.
#[proc_macro_attribute]
pub fn template(args: proc_macro::TokenStream, input: proc_macro::TokenStream) -> TokenStream {
let args: Option<Ident> = parse(args).unwrap();
let template: ItemFn = parse(input).unwrap();
pub fn template(_args: proc_macro::TokenStream, input: proc_macro::TokenStream) -> TokenStream {
let mut template: ItemFn = parse(input).unwrap();

let rstest_index = template
.attrs
.iter()
.position(|attr| attr.path.is_ident(&format_ident!("rstest")));

let mut tokens = quote! {};
let mut attributes = template.attrs;

let local = if let Some(local) = args {
local.to_string() == "local"
} else {
false
template.attrs = match rstest_index {
Some(idx) => attributes.split_off(idx),
None => std::mem::take(&mut attributes),
};

if !local {
tokens.extend(quote! {
#[macro_export]
});
}
let mut tokens = match get_export(&attributes) {
Some(_) => {
quote! {
#[macro_export]
}
}
None => quote! {},
};

let macro_name = template.sig.ident.clone();
tokens.extend(quote! {
Expand Down Expand Up @@ -263,7 +275,7 @@ pub fn template(args: proc_macro::TokenStream, input: proc_macro::TokenStream) -

#[proc_macro_attribute]
pub fn apply(args: proc_macro::TokenStream, input: proc_macro::TokenStream) -> TokenStream {
let template: Ident = parse(args).unwrap();
let template: Path = parse(args).unwrap();
let test: ItemFn = parse(input).unwrap();
let tokens = quote! {
#template! {
Expand Down
33 changes: 32 additions & 1 deletion rstest_reuse/tests/acceptance.rs
@@ -1,4 +1,6 @@
use rstest_test::{Project, Stringable, TestResults, assert_not_in, sanitize_name, testname};
use rstest_test::{
assert_in, assert_not_in, sanitize_name, testname, Project, Stringable, TestResults,
};

use lazy_static::lazy_static;

Expand Down Expand Up @@ -79,6 +81,35 @@ fn deny_docs() {
.assert(output);
}

#[test]
fn enable_export_macros() {
let (output, _) = run_test("export_template.rs");

TestResults::new()
.ok("foo::bar::test::case_1")
.ok("test::case_1")
.assert(output);
}

#[test]
fn use_same_name_for_more_templates() {
let (output, _) = run_test("templates_with_same_name.rs");

TestResults::new()
.ok("inner1::it_works::case_1")
.ok("inner1::it_works::case_2")
.ok("inner2::it_works::case_1")
.ok("inner2::it_works::case_2")
.assert(output);
}

#[test]
fn no_local_macro_should_not_compile() {
let (output, _) = run_test("no_local_macro_should_not_compile.rs");

assert!(!output.status.success());
}

lazy_static! {
static ref ROOT_DIR: TempDir = TempDir::new(std::env::temp_dir().join("rstest_reuse"), false);
static ref ROOT_PROJECT: Project = Project::new(ROOT_DIR.as_ref());
Expand Down
27 changes: 27 additions & 0 deletions rstest_reuse/tests/resources/export_template.rs
@@ -0,0 +1,27 @@
use rstest_reuse;

mod foo {
mod bar {
use rstest::rstest;
use rstest_reuse::{self, *};

#[template]
#[export]
#[rstest]
#[case("bar")]
fn my_template(#[case] s: &str) {}

#[apply(my_template)]
fn test(#[case] s: &str) {
assert_eq!("bar", s);
}
}
}

use rstest::rstest;
use rstest_reuse::apply;

#[apply(my_template)]
fn test(#[case] s: &str) {
assert_eq!("bar", s);
}
17 changes: 17 additions & 0 deletions rstest_reuse/tests/resources/no_local_macro_should_not_compile.rs
@@ -0,0 +1,17 @@
use rstest_reuse;

mod foo {
use rstest_reuse::{self, *};

#[template]
#[rstest]
#[case("bar")]
fn my_template(#[case] s: &str) {}
}
use rstest::rstest;
use rstest_reuse::apply;

#[apply(my_template)]
fn test(#[case] s: &str) {
assert_eq!("bar", s);
}
27 changes: 27 additions & 0 deletions rstest_reuse/tests/resources/templates_with_same_name.rs
@@ -0,0 +1,27 @@
use rstest_reuse;

mod inner1 {
use rstest::rstest;
use rstest_reuse::*;

#[template]
#[rstest(a, b, case(2, 2), case(4/2, 2))]
fn template(a: u32, b: u32) {}

#[apply(template)]
fn it_works(a: u32, b: u32) {
assert!(a == b);
}
}

mod inner2 {
use rstest::rstest;
use rstest_reuse::*;

#[template]
#[rstest(a, case(2), case(4))]
fn template(a: u32) {}

#[apply(template)]
fn it_works(a: u32) {}
}

0 comments on commit d075e12

Please sign in to comment.