Skip to content

Commit 23c60eb

Browse files
committed
externally visible test macro
1 parent 0e22b12 commit 23c60eb

File tree

3 files changed

+75
-0
lines changed

3 files changed

+75
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ members = [
1212
"lightning-custom-message",
1313
"lightning-transaction-sync",
1414
"possiblyrandom",
15+
"ext-test-macro",
1516
]
1617

1718
exclude = [

ext-test-macro/Cargo.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[package]
2+
name = "ext-test-macro"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[lib]
7+
proc-macro = true
8+
9+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
10+
11+
[dependencies]
12+
syn = { version = "1.0", features = ["full"] }
13+
quote = "1.0"
14+
proc-macro2 = "1.0"

ext-test-macro/src/lib.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use proc_macro::TokenStream;
2+
use proc_macro2::TokenStream as TokenStream2;
3+
use quote::quote;
4+
use syn::{ItemFn, ItemMod, parse2};
5+
6+
/// An exposed test. This is a test that will run locally and also be
7+
/// made available to other crates that want to run it in their own context.
8+
///
9+
/// For example:
10+
/// ```ignore
11+
/// #[xtest]
12+
/// pub fn test_f1() {
13+
/// f1();
14+
/// }
15+
/// ```
16+
///
17+
/// May also be applied to modules, like so:
18+
///
19+
/// ```ignore
20+
/// #[xtest(feature = "externalize-the-tests")]
21+
/// pub mod tests {
22+
/// ...
23+
/// }
24+
/// ```
25+
///
26+
/// Which will include the module if we are testing or the `externalize-the-tests` feature
27+
/// is on.
28+
#[proc_macro_attribute]
29+
pub fn xtest(attrs: TokenStream, item: TokenStream) -> TokenStream {
30+
let input = syn::parse_macro_input!(item as TokenStream2);
31+
let attrs = syn::parse_macro_input!(attrs as TokenStream2);
32+
33+
let expanded = if is_module_definition(input.clone()) {
34+
let cfg = if attrs.is_empty() {
35+
quote! { #[cfg(test)] }
36+
} else {
37+
quote! { #[cfg(any(test, #attrs))] }
38+
};
39+
quote! {
40+
#cfg
41+
#input
42+
}
43+
} else if is_function_definition(input.clone()) {
44+
quote! {
45+
#[cfg_attr(test, ::core::prelude::v1::test)]
46+
#input
47+
}
48+
} else {
49+
panic!("xtest can only be applied to functions or modules");
50+
};
51+
expanded.into()
52+
}
53+
54+
fn is_module_definition(input: TokenStream2) -> bool {
55+
parse2::<ItemMod>(input).is_ok()
56+
}
57+
58+
fn is_function_definition(input: TokenStream2) -> bool {
59+
parse2::<ItemFn>(input).is_ok()
60+
}

0 commit comments

Comments
 (0)