#![allow(
clippy::string_lit_as_bytes,
clippy::manual_string_new,
clippy::needless_pass_by_value,
clippy::uninlined_format_args,
clippy::needless_collect,
clippy::cast_sign_loss
)]
use std::{collections::BTreeMap, fs::read, path::PathBuf};
use wacc::types::{CheckCount, ContextPath};
use wacc::{
storage::{Pairs, Stack},
vm::{Builder, Context, Instance, Value},
};
use wasmtime::{AsContextMut, StoreLimitsBuilder};
const MEMORY_LIMIT: usize = 1 << 22;
fn load_wasm(file_name: &str) -> Option<Vec<u8>> {
let mut pb = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
pb.push("target");
pb.push(file_name);
println!("trying to load: {}", pb.as_os_str().display());
read(&pb).ok()
}
fn load_wast(file_name: &str) -> Vec<u8> {
let mut pb = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
pb.push("examples/wacc/wast");
pb.push(file_name);
println!("trying to load: {}", pb.as_os_str().display());
read(&pb).unwrap_or_else(|_| panic!("Error loading file {file_name}"))
}
fn test_example(
script: Vec<u8>,
expected: bool,
current: Kvp,
proposed: Kvp,
pstack: Stk,
rstack: Stk,
) -> Instance {
let context = Context {
current: Box::new(current),
proposed: Box::new(proposed),
pstack: Box::new(pstack),
rstack: Box::new(rstack),
check_count: CheckCount::zero(),
write_idx: 0,
context: ContextPath::new("/forks/child/"),
log: Vec::default(),
limiter: StoreLimitsBuilder::new()
.memory_size(MEMORY_LIMIT)
.instances(2)
.memories(1)
.build(),
};
let mut instance = Builder::new()
.with_context(context)
.with_bytes(&script)
.try_build()
.unwrap();
let result = instance.run("move_every_zig").unwrap();
assert_eq!(expected, result);
instance
}
#[derive(Default, Clone)]
struct Kvp {
pub pairs: BTreeMap<String, Value>,
}
impl Pairs for Kvp {
fn get(&self, key: &str) -> Option<Value> {
self.pairs.get(key).cloned()
}
fn put(&mut self, key: &str, value: &Value) -> Option<Value> {
self.pairs.insert(key.to_string(), value.clone())
}
}
#[derive(Default, Clone)]
struct Stk {
pub stack: Vec<Value>,
}
impl Stack for Stk {
fn push(&mut self, value: Value) {
self.stack.push(value);
}
fn pop(&mut self) -> Option<Value> {
self.stack.pop()
}
fn top(&self) -> Option<Value> {
self.stack.last().cloned()
}
fn peek(&self, idx: usize) -> Option<Value> {
if idx >= self.stack.len() {
return None;
}
Some(self.stack[self.stack.len() - 1 - idx].clone())
}
fn len(&self) -> usize {
self.stack.len()
}
fn is_empty(&self) -> bool {
self.stack.is_empty()
}
}
#[test]
fn test_branch_wast() {
let kvp = Kvp::default();
let pstack = Stk::default();
let rstack = Stk::default();
let script = load_wast("branch.wast");
let mut instance = test_example(script, true, kvp.clone(), kvp, pstack, rstack);
assert_eq!(b"/forks/child/keys/primary\n".to_vec(), instance.log());
let mut ctx = instance.store.as_context_mut();
let context = ctx.data_mut();
assert_eq!(0, context.pstack.len());
assert_eq!(0, context.rstack.len());
}
#[test]
fn test_branch_wasm() {
let Some(script) = load_wasm("branch.wasm") else {
eprintln!("Skipping test_branch_wasm: branch.wasm not found (run 'make' in examples/wast to build)");
return;
};
let kvp = Kvp::default();
let pstack = Stk::default();
let rstack = Stk::default();
let mut instance = test_example(script, true, kvp.clone(), kvp, pstack, rstack);
assert_eq!(b"/forks/child/keys/primary\n".to_vec(), instance.log());
let mut ctx = instance.store.as_context_mut();
let context = ctx.data_mut();
assert_eq!(0, context.pstack.len());
assert_eq!(0, context.rstack.len());
}