Rename `tdb-derive` to `tdb-macros`
The proc_macro can now be applied on modules only All functions within the module will be considered to be a test This has the advantage of not having to flag every test functionnext
parent
16304cc4f7
commit
147f13a020
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Created on Sun Sep 13 2020
|
||||
*
|
||||
* This file is a part of TerrabaseDB
|
||||
* Copyright (c) 2020, Sayan Nandan <ohsayan at outlook dot com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//! A library containing a collection of custom derives used by TerrabaseDB
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn;
|
||||
|
||||
fn parse_toks(mut input: syn::ItemFn) -> Result<TokenStream, syn::Error> {
|
||||
let sig = &mut input.sig;
|
||||
let body = &input.block;
|
||||
let attrs = &input.attrs;
|
||||
let vis = input.vis;
|
||||
let header = quote! {
|
||||
#[::core::prelude::v1::test]
|
||||
};
|
||||
let result = quote! {
|
||||
#header
|
||||
#(#attrs)*
|
||||
#vis #sig {
|
||||
let runtime = testsuite::service::BackGroundTask::new();
|
||||
runtime.execute(|| {#body});
|
||||
drop(runtime);
|
||||
}
|
||||
};
|
||||
Ok(result.into())
|
||||
}
|
||||
|
||||
fn test(_args: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let input = syn::parse_macro_input!(item as syn::ItemFn);
|
||||
for attr in &input.attrs {
|
||||
if attr.path.is_ident("test") {
|
||||
let msg = "second test attribute is supplied";
|
||||
return syn::Error::new_spanned(&attr, msg)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
}
|
||||
|
||||
if !input.sig.inputs.is_empty() {
|
||||
let msg = "the test function cannot accept arguments";
|
||||
return syn::Error::new_spanned(&input.sig.inputs, msg)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
parse_toks(input).unwrap_or_else(|e| e.to_compile_error().into())
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
/// Execute the function as a test
|
||||
/// This function starts the server in the background and terminates it when
|
||||
/// the test is over. Do note that, at the moment, this expects a `service` module
|
||||
/// to have a `BackgroundTask` object which should start the background the server
|
||||
pub fn dbtest(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||
test(args, item)
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Created on Sun Sep 13 2020
|
||||
*
|
||||
* This file is a part of TerrabaseDB
|
||||
* Copyright (c) 2020, Sayan Nandan <ohsayan at outlook dot com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//! A library containing a collection of custom derives used by TerrabaseDB
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use rand::*;
|
||||
use std::collections::HashSet;
|
||||
use syn;
|
||||
|
||||
// TODO(@ohsayan): Write docs and also make this use the tokio runtime
|
||||
|
||||
fn parse_dbtest(mut input: syn::ItemFn, rand: u16) -> Result<TokenStream, syn::Error> {
|
||||
let sig = &mut input.sig;
|
||||
let fname = sig.ident.to_string();
|
||||
let body = &input.block;
|
||||
let attrs = &input.attrs;
|
||||
let vis = input.vis;
|
||||
let header = quote! {
|
||||
#[::core::prelude::v1::test]
|
||||
};
|
||||
if sig.asyncness.is_none() {
|
||||
let msg = "`dbtest` functions need to be async";
|
||||
return Err(syn::Error::new_spanned(sig.fn_token, msg));
|
||||
}
|
||||
let body = quote! {
|
||||
let mut socket = tokio::net::TcpStream::connect(#rand).await;
|
||||
#body
|
||||
socket.shutdown(std::net::Shutdown::Both).unwrap();
|
||||
};
|
||||
let result = quote! {
|
||||
#header
|
||||
#(#attrs)*
|
||||
#vis #sig {
|
||||
let runtime = Builder::new_multi_thread()
|
||||
.worker_threads(4)
|
||||
.thread_name(#fname)
|
||||
.thread_stack_size(3 * 1024 * 1024)
|
||||
.build()
|
||||
.unwrap()
|
||||
.block_on(async { #body });
|
||||
}
|
||||
};
|
||||
Ok(result.into())
|
||||
}
|
||||
|
||||
fn parse_test_sig(input: syn::ItemFn, rand: u16) -> TokenStream {
|
||||
for attr in &input.attrs {
|
||||
if attr.path.is_ident("test") {
|
||||
let msg = "second test attribute is supplied";
|
||||
return syn::Error::new_spanned(&attr, msg)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
}
|
||||
|
||||
if !input.sig.inputs.is_empty() {
|
||||
let msg = "the test function cannot accept arguments";
|
||||
return syn::Error::new_spanned(&input.sig.inputs, msg)
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
parse_dbtest(input, rand).unwrap_or_else(|e| e.to_compile_error().into())
|
||||
}
|
||||
|
||||
fn parse_test_module(_args: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let input = syn::parse_macro_input!(item as syn::ItemMod);
|
||||
let (_, content) = input.content.unwrap();
|
||||
let attrs = input.attrs;
|
||||
let vis = input.vis;
|
||||
let mod_token = input.mod_token;
|
||||
let modname = input.ident;
|
||||
let mut rng = thread_rng();
|
||||
let mut in_set = HashSet::<u16>::new();
|
||||
in_set.insert(80);
|
||||
in_set.insert(443);
|
||||
let mut result = quote! {};
|
||||
for item in content {
|
||||
let mut rand: u16 = rng.gen_range(0, 65535);
|
||||
while in_set.contains(&rand) {
|
||||
rand = rng.gen_range(0, 65535);
|
||||
}
|
||||
match item {
|
||||
// We just care about functions, so parse functions and ignore everything
|
||||
// else
|
||||
syn::Item::Fn(function) => {
|
||||
let inp = parse_test_sig(function, rand);
|
||||
let __tok: syn::ItemFn = syn::parse_macro_input!(inp as syn::ItemFn);
|
||||
let tok = quote! {
|
||||
#__tok
|
||||
};
|
||||
result = quote! {
|
||||
#result
|
||||
#tok
|
||||
};
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
let result = quote! {
|
||||
#result
|
||||
};
|
||||
let header = quote! {
|
||||
#[::core::prelude::v1::test]
|
||||
};
|
||||
let finalres = quote! {
|
||||
#header
|
||||
#(#attrs)*
|
||||
#mod_token #vis #modname {
|
||||
#result
|
||||
}
|
||||
};
|
||||
finalres.into()
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn dbtest(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||
parse_test_module(args, item)
|
||||
}
|
Loading…
Reference in New Issue