testing_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::{quote, ToTokens};
3use syn::ItemFn;
4
5mod fixture;
6
7/// Create tests from files.
8///
9/// **NOTE: Path should be relative to the directory of `Cargo.toml` file**.
10/// This is limitation of current proc macro api.
11///
12/// # Why
13///
14/// If you create test dynamically, running a specific test become very
15/// cumbersome.
16///
17/// For example, if you use `test` crate with nightly, you can't use `cargo test
18/// foo` to run tests with name containing `foo`. Instead, you have to implement
19/// your own ignoring logic
20///
21///
22/// # Usage
23///
24/// If you want to load all typescript files from `pass`
25///
26/// ```rust,ignore
27/// 
28/// #[fixture("pass/**/*.{ts,tsx}")]
29/// fn pass(file: PathBuf) {
30///     // test by reading file
31/// }
32/// ```
33///
34/// # Return value
35///
36/// The function is allowed to return `Result` on error. If it's the case
37///
38///
39/// ## Ignoring a test
40///
41/// If the path to the file contains a component starts with `.` (dot), it will
42/// be ignore. This convention is widely used in many projects (including other
43/// languages), as a file or a directory starting with `.` means hidden file in
44/// unix system.
45///
46/// Note that they are added as a test `#[ignore]`, so you can use
47/// `cargo test -- --ignored` or `cargo test -- --include-ignored` to run those
48/// tests.
49///
50///
51/// # Roadmap
52///
53/// - Support async function
54#[proc_macro_attribute]
55pub fn fixture(attr: TokenStream, item: TokenStream) -> TokenStream {
56    let item: ItemFn = syn::parse(item).expect("failed to parse input as a function item");
57
58    if cfg!(feature = "rust-analyzer") {
59        return quote!(
60            #[allow(unused)]
61            #item
62        )
63        .into();
64    }
65
66    let config: self::fixture::Config =
67        syn::parse(attr).expect("failed to parse input passed to #[fixture]");
68
69    let cases = self::fixture::expand(&item.sig.ident, config).unwrap();
70
71    let mut output = proc_macro2::TokenStream::new();
72
73    for case in cases {
74        case.to_tokens(&mut output);
75    }
76
77    item.to_tokens(&mut output);
78
79    output.into()
80}