diff --git a/derive/src/error.rs b/derive/src/error.rs index 3895f51..209b8c6 100644 --- a/derive/src/error.rs +++ b/derive/src/error.rs @@ -1,4 +1,4 @@ -use proc_macro2::{TokenStream, Span}; +use proc_macro2::{Span, TokenStream}; use quote::{quote_spanned, ToTokens}; macro_rules! err_span { @@ -21,10 +21,7 @@ impl CompileError { } pub fn new(msg: String) -> Self { - CompileError { - span: None, - msg, - } + CompileError { span: None, msg } } } @@ -34,6 +31,7 @@ impl ToTokens for CompileError { let span = self.span.unwrap_or_else(|| Span::call_site()); (quote_spanned! { span=> compile_error!(#msg); - }).to_tokens(dst); + }) + .to_tokens(dst); } } diff --git a/derive/src/lib.rs b/derive/src/lib.rs index d9b4aff..71932e6 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -24,7 +24,7 @@ //! //! #[derive_externals] //! impl<'a> NonStaticExternals<'a> { -//! pub fn hello(&self, a: u32, b: u32) -> u32 { +//! pub fn add(&self, a: u32, b: u32) -> u32 { //! a + b //! } //! @@ -60,8 +60,6 @@ pub fn derive_externals(_attr: TokenStream, input: TokenStream) -> TokenStream { codegen::codegen(&ext_def, &mut input); input.into() } - Err(err) => { - (quote::quote! { #err }).into() - } + Err(err) => (quote::quote! { #err }).into(), } } diff --git a/derive/src/parser.rs b/derive/src/parser.rs index 8e42ccb..ec954c4 100644 --- a/derive/src/parser.rs +++ b/derive/src/parser.rs @@ -37,7 +37,8 @@ pub struct ImplBlockDef { /// Parse an incoming stream of tokens into externalities definition. pub fn parse(input: proc_macro2::TokenStream) -> Result { - let item_impl = syn::parse2::(input).map_err(|_| CompileError::new("failed to parse".to_string()))?; + let item_impl = syn::parse2::(input) + .map_err(|_| CompileError::new("failed to parse".to_string()))?; let mut funcs = vec![]; @@ -57,9 +58,12 @@ pub fn parse(input: proc_macro2::TokenStream) -> Result return None, - _ => return Some( - Err(err_span!(input.span(), "only &self and &mut self supported as first argument")) - ), + _ => { + return Some(Err(err_span!( + input.span(), + "only &self and &mut self supported as first argument" + ))); + } } } diff --git a/wasmi/tests/derives.rs b/wasmi/tests/derives.rs index 2f05f24..1f8eb9c 100644 --- a/wasmi/tests/derives.rs +++ b/wasmi/tests/derives.rs @@ -2,6 +2,8 @@ extern crate wasmi; extern crate wasmi_derive; +#[macro_use] +extern crate assert_matches; use std::fmt; use wasmi::HostError; @@ -22,7 +24,7 @@ struct NonStaticExternals<'a> { #[derive_externals] impl<'a> NonStaticExternals<'a> { - pub fn hello(&self, a: u32, b: u32) -> u32 { + pub fn add(&self, a: u32, b: u32) -> u32 { a + b } @@ -34,3 +36,117 @@ impl<'a> NonStaticExternals<'a> { Err(NoInfoError) } } + +mod tests { + extern crate wabt; + + use super::*; + use wasmi::{ImportsBuilder, Module, ModuleInstance, RuntimeValue}; + + macro_rules! gen_test { + ($test_name:ident, $wat:expr, |$instance:ident| $verify:expr) => { + #[test] + fn $test_name() { + // We don't test wat compiliation, loading or decoding. + let wasm = &wabt::wat2wasm($wat).expect("invalid wat"); + let module = Module::from_buffer(&wasm).expect("can't load module"); + + let resolver = NonStaticExternals::resolver(); + + let mut imports = ImportsBuilder::new(); + imports.push_resolver("env", &resolver); + let $instance = ModuleInstance::new(&module, &imports); + + $verify + } + }; + } + + gen_test! { it_works, + r#" + (module + (import "env" "add" (func $add (param i32 i32) (result i32))) + (import "env" "increment" (func $increment)) + (import "env" "traps" (func $traps)) + + (export "add" (func $add)) + (export "increment" (func $increment)) + (export "traps" (func $traps)) + ) + "#, + |not_started_instance_result| { + let mut state = 0; + let mut externals = NonStaticExternals { + state: &mut state, + }; + + let instance = not_started_instance_result.unwrap().assert_no_start(); + assert_matches!( + instance.invoke_export( + "traps", + &[], + &mut externals, + ), + Err(_) + ); + + assert_eq!(*externals.state, 0); + assert_matches!( + instance.invoke_export( + "increment", + &[], + &mut externals, + ), + Ok(None) + ); + assert_eq!(*externals.state, 1); + + assert_matches!( + instance.invoke_export( + "add", + &[RuntimeValue::I32(5), RuntimeValue::I32(2)], + &mut externals, + ), + Ok(Some(RuntimeValue::I32(7))) + ); + } + } + + gen_test! { wrong_signature, + r#" + (module + (import "env" "add" (func $add (param i64 i32) (result i32))) + ) + "#, + |result| { + match result { + Ok(_) => panic!(), + Err(err) => { + assert_eq!( + &format!("{:?}", err), + r#"Instantiation("Export add has different signature Signature { params: [I64, I32], return_type: Some(I32) }")"#, + ); + } + } + } + } + + gen_test! { nonexistent_name, + r#" + (module + (import "env" "foo" (func $foo)) + ) + "#, + |result| { + match result { + Ok(_) => panic!(), + Err(err) => { + assert_eq!( + &format!("{:?}", err), + r#"Instantiation("Export foo not found")"#, + ); + } + } + } + } +}