mirror of
https://github.com/fluencelabs/marine-rs-sdk-test
synced 2024-12-04 15:20:18 +00:00
intermediate
This commit is contained in:
parent
9811e476ed
commit
fbd021e3e2
@ -17,5 +17,12 @@ all-features = true
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
fluence-app-service = "0.5.2"
|
||||
fluence-faas = "0.5.2"
|
||||
quote = "1.0.9"
|
||||
proc-macro2 = "1.0.24"
|
||||
serde = { version = "=1.0.118", features = ["derive"] }
|
||||
serde_json = "1.0.56"
|
||||
syn = { version = '1.0.65', features = ['full'] }
|
||||
uuid = { version = "0.8.2", features = ["v4"] }
|
||||
|
||||
#fluence-sdk-wit = { path = "../wit", version = "=0.4.2" }
|
||||
|
61
crates/macro-test/src/attributes.rs
Normal file
61
crates/macro-test/src/attributes.rs
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2020 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use syn::parse::Parse;
|
||||
use syn::parse::ParseStream;
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub(crate) struct FCETestAttributes {
|
||||
pub(crate) config_path: String,
|
||||
}
|
||||
|
||||
impl Parse for FCETestAttributes {
|
||||
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
|
||||
let config_file_path = parse_config_file_path(input)?;
|
||||
let attributes = FCETestAttributes {
|
||||
config_path: config_file_path,
|
||||
};
|
||||
|
||||
Ok(attributes)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parse_config_file_path(token_stream: ParseStream<'_>) -> syn::Result<String> {
|
||||
let attr_name = token_stream.step(|cursor| match cursor.ident() {
|
||||
Some((ident, rem)) => Ok((ident, rem)),
|
||||
None => Err(cursor.error("Expected a valid identifier")),
|
||||
})?;
|
||||
|
||||
match attr_name.to_string().as_str() {
|
||||
"config" => {
|
||||
// trying to parse `=`
|
||||
token_stream.parse::<syn::token::Eq>()?;
|
||||
|
||||
match token_stream.parse::<syn::Ident>() {
|
||||
Ok(config_file_path) => Ok(config_file_path.to_string()),
|
||||
Err(e) => Err(syn::Error::new(
|
||||
attr_name.span(),
|
||||
format!("failed to parse a config file path: {}", e),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
attr => Err(syn::Error::new(
|
||||
attr_name.span(),
|
||||
format!("Expected 'config' identifier, but {} found", attr),
|
||||
)),
|
||||
}
|
||||
}
|
@ -14,3 +14,57 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
pub(super) fn fce_test_impl(
|
||||
attr: TokenStream,
|
||||
func_input: syn::ItemFn,
|
||||
) -> Result<TokenStream, TokenStream> {
|
||||
use crate::attributes::FCETestAttributes;
|
||||
|
||||
let attrs = syn::parse2::<FCETestAttributes>(attr).map_err(|e| e.into_compile_error())?;
|
||||
let generated_test = generate_test_glue_code(func_input, &attrs.config_path);
|
||||
|
||||
Ok(generated_test)
|
||||
}
|
||||
|
||||
fn generate_test_glue_code(func: syn::ItemFn, config_path: &str) -> TokenStream {
|
||||
let fce_ctor = generate_fce_ctor(config_path);
|
||||
let original_block = func.block;
|
||||
let signature = func.sig;
|
||||
|
||||
quote! {
|
||||
#[test]
|
||||
#signature {
|
||||
#fce_ctor
|
||||
|
||||
#original_block
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_fce_ctor(config_path: &str) -> TokenStream {
|
||||
let config_path = new_ident(config_path);
|
||||
|
||||
let tmp_file_path = std::env::temp_dir();
|
||||
let random_uuid = uuid::Uuid::new_v4().to_string();
|
||||
let service_id = new_ident(&random_uuid);
|
||||
|
||||
let tmp_file_path = tmp_file_path.join(random_uuid);
|
||||
let tmp_file_path = tmp_file_path.to_string_lossy().to_string();
|
||||
let tmp_file_path = new_ident(&tmp_file_path);
|
||||
|
||||
quote! {
|
||||
let mut __fce__generated_fce_config = fluence_faas::TomlAppServiceConfig::load(#config_path)
|
||||
.unwrap_or_else(|e| panic!("app service located at `{}` config can't be loaded: {}", #config_path, e));
|
||||
__fce__generated_fce_config.service_base_dir = Some(#tmp_file_path);
|
||||
|
||||
let fce = fce_app_service::AppService::new_with_empty_facade(__fce__generated_fce_config, #service_id, std::collections::HashMap::new())
|
||||
.unwrap_or_else(|e| panic!("app service can't be created: {}", e));
|
||||
}
|
||||
}
|
||||
|
||||
fn new_ident(name: &str) -> syn::Ident {
|
||||
syn::Ident::new(name, proc_macro2::Span::call_site())
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/fluence-sdk-macro/0.4.2")]
|
||||
/*
|
||||
#![deny(
|
||||
dead_code,
|
||||
nonstandard_style,
|
||||
@ -23,21 +24,40 @@
|
||||
unused_unsafe,
|
||||
unreachable_patterns
|
||||
)]
|
||||
*/
|
||||
#![warn(rust_2018_idioms)]
|
||||
#![recursion_limit = "1024"]
|
||||
|
||||
mod attributes;
|
||||
mod fce_test;
|
||||
|
||||
use fce_test::fce_test_impl;
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
/// This macro allows user to write tests for services in the following form:
|
||||
///```rust
|
||||
/// #[fce_test(config = "/path/to/Config.toml")]
|
||||
/// fn test() {
|
||||
/// let service_result = fce.call("greeting", "name");
|
||||
/// assert_eq!(&service_result, "Hi, name!");
|
||||
/// }
|
||||
///```
|
||||
///
|
||||
/// This function is desugrated in the following way:
|
||||
///```rust
|
||||
/// #[test]
|
||||
/// fn test() {
|
||||
/// let fce = fluence_faas::FluenceFaaS::with_raw_config("/path/to/Config.toml")
|
||||
/// .unwrap_or_else(|e| panic!("test instance can't be instantiated: {}", e));
|
||||
/// let service_result = fce.call("greeting", "name");
|
||||
/// assert_eq!(&service_result, "Hi, name!");
|
||||
/// }
|
||||
///```
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn fce_test(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||
// into converts proc_macro::TokenStream to proc_macro2::TokenStream
|
||||
match fce_impl(input.into()) {
|
||||
Ok(v) => v,
|
||||
// converts syn:error to proc_macro2::TokenStream
|
||||
Err(e) => e.to_compile_error(),
|
||||
}
|
||||
// converts proc_macro2::TokenStream to proc_macro::TokenStream
|
||||
.into()
|
||||
pub fn fce_test(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let func_input = syn::parse_macro_input!(input as syn::ItemFn);
|
||||
let result = fce_test_impl(attrs.into(), func_input).unwrap_or_else(std::convert::identity);
|
||||
|
||||
result.into()
|
||||
}
|
||||
|
@ -14,9 +14,9 @@ license = "Apache-2.0"
|
||||
all-features = true
|
||||
|
||||
[dependencies]
|
||||
quote = "1.0.7"
|
||||
proc-macro2 = "1.0.18"
|
||||
quote = "1.0.9"
|
||||
proc-macro2 = "1.0.24"
|
||||
serde = { version = "=1.0.118", features = ["derive"] }
|
||||
serde_json = "1.0.56"
|
||||
syn = { version = '1.0.33', features = ['full'] }
|
||||
uuid = { version = "0.8.1", features = ["v4"] }
|
||||
syn = { version = '1.0.65', features = ['full'] }
|
||||
uuid = { version = "0.8.2", features = ["v4"] }
|
||||
|
Loading…
Reference in New Issue
Block a user