1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#![allow(clippy::test_attr_in_doctest)]
#![allow(unexpected_cfgs)]
#![cfg_attr(use_proc_macro_diagnostic, feature(proc_macro_diagnostic))]
extern crate proc_macro;

// Test utility module
#[cfg(test)]
pub(crate) mod test;

#[macro_use]
mod error;
mod parse;
mod refident;
mod render;
mod resolver;
mod utils;

use syn::{parse_macro_input, ItemFn};

use crate::parse::{fixture::FixtureInfo, rstest::RsTestInfo};
use parse::ExtendWithFunctionAttrs;
use quote::ToTokens;

#[allow(missing_docs)]
#[proc_macro_attribute]
pub fn fixture(
    args: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let mut info: FixtureInfo = parse_macro_input!(args as FixtureInfo);
    let mut fixture = parse_macro_input!(input as ItemFn);

    let extend_result = info.extend_with_function_attrs(&mut fixture);

    let mut errors = error::fixture(&fixture, &info);

    if let Err(attrs_errors) = extend_result {
        attrs_errors.to_tokens(&mut errors);
    }

    if errors.is_empty() {
        render::fixture(fixture, info)
    } else {
        errors
    }
    .into()
}

#[allow(missing_docs)]
#[proc_macro_attribute]
pub fn rstest(
    args: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let mut test = parse_macro_input!(input as ItemFn);
    let mut info = parse_macro_input!(args as RsTestInfo);

    let extend_result = info.extend_with_function_attrs(&mut test);

    let mut errors = error::rstest(&test, &info);

    if let Err(attrs_errors) = extend_result {
        attrs_errors.to_tokens(&mut errors);
    }

    if errors.is_empty() {
        if info.data.has_list_values() {
            render::matrix(test, info)
        } else if info.data.has_cases() {
            render::parametrize(test, info)
        } else {
            render::single(test, info)
        }
    } else {
        errors
    }
    .into()
}