use std::fmt::Debug;
use wasmi::{CompilationMode, Config, Engine, Error, Func, Linker, Module, Store, TrapCode};
fn test_setup(mode: CompilationMode) -> (Store<()>, Linker<()>) {
let mut config = Config::default();
config.consume_fuel(true);
config.compilation_mode(mode);
let engine = Engine::new(&config);
let store = Store::new(&engine, ());
let linker = Linker::new(&engine);
(store, linker)
}
fn create_module(store: &Store<()>, bytes: &[u8]) -> Module {
Module::new(store.engine(), bytes).unwrap()
}
fn default_test_setup(mode: CompilationMode, wasm: &[u8]) -> (Store<()>, Func) {
let (mut store, linker) = test_setup(mode);
let module = create_module(&store, wasm);
let instance = linker.instantiate_and_start(&mut store, &module).unwrap();
let func = instance.get_func(&store, "test").unwrap();
(store, func)
}
#[track_caller]
fn assert_success<T>(call_result: Result<T, Error>)
where
T: Debug,
{
if let Err(error) = call_result {
panic!("expected `Ok` but got: {error}")
}
}
#[track_caller]
fn assert_out_of_fuel<T>(call_result: Result<T, Error>)
where
T: Debug,
{
let Err(error) = call_result else {
panic!("expected `out of fuel` error but got `Ok`")
};
assert_eq!(
error.as_trap_code(),
Some(TrapCode::OutOfFuel),
"expected `out of fuel` but got: {error}"
);
}
const WASM_INPUT: &str = r#"
(module
(func (export "test") (param $a i32) (param $b i32) (result i32)
(i32.add
(local.get $a)
(local.get $b)
)
)
)
"#;
fn run_test(mode: CompilationMode, final_fuel: u64) {
let (mut store, func) = default_test_setup(mode, WASM_INPUT.as_bytes());
let func = func.typed::<(i32, i32), i32>(&store).unwrap();
assert_out_of_fuel(func.call(&mut store, (1, 2)));
assert_eq!(store.get_fuel().ok(), Some(0));
store.set_fuel(1).unwrap();
assert_out_of_fuel(func.call(&mut store, (1, 2)));
assert_eq!(store.get_fuel().ok(), Some(1));
store.set_fuel(100).unwrap();
assert_success(func.call(&mut store, (1, 2)));
assert_eq!(store.get_fuel().ok(), Some(final_fuel));
}
#[test]
fn metered_i32_add_eager() {
run_test(CompilationMode::Eager, 97)
}
#[test]
fn metered_i32_add_lazy_translation() {
run_test(CompilationMode::LazyTranslation, 48)
}
#[test]
fn metered_i32_add_lazy() {
run_test(CompilationMode::Lazy, 34)
}