Add some (incomplete set) basic sanity end-to-end tests (#2)
* Add some (incomplete set) basic sanity end-to-end tests This commit adds some (an incomplete set of) basic sanity end-to-end tests. It uses `test.witx` to autogenerate types and module interface functions (aka the syscalls), and tests their implementation. For the host memory, it uses simplistic `&mut [u8]` where we have full control of the addressing and contents. * Add sanity test for baz interface func This commit adds a sanity test for the `Foo::baz` interface func. * Upcast start/len for Region to avoid overflow * Reenable alignment checking for memory * use an array to implement hostmemory Co-authored-by: Pat Hickey <pat@moreproductive.org>
This commit is contained in:
@@ -7,10 +7,10 @@ pub struct Region {
|
||||
impl Region {
|
||||
pub fn overlaps(&self, rhs: Region) -> bool {
|
||||
let self_start = self.start as u64;
|
||||
let self_end = self.start as u64 + self.len as u64;
|
||||
let self_end = ((self_start + self.len as u64) as i64 - 1) as u64;
|
||||
|
||||
let rhs_start = rhs.start as u64;
|
||||
let rhs_end = rhs.start as u64 + rhs.len as u64;
|
||||
let rhs_end = ((rhs_start + rhs.len as u64) as i64 - 1) as u64;
|
||||
|
||||
// start of rhs inside self:
|
||||
if rhs_start >= self_start && rhs_start < self_end {
|
||||
|
||||
2821
lib_generated.rs
2821
lib_generated.rs
File diff suppressed because it is too large
Load Diff
97
src/lib.rs
97
src/lib.rs
@@ -1,100 +1,3 @@
|
||||
pub mod test {
|
||||
// FIXME: parameterize macro on what ctx type is used here
|
||||
generate::from_witx!({
|
||||
witx: ["test.witx"],
|
||||
ctx: WasiCtx,
|
||||
});
|
||||
|
||||
pub struct WasiCtx {
|
||||
guest_errors: Vec<::memory::GuestError>,
|
||||
}
|
||||
|
||||
impl foo::Foo for WasiCtx {
|
||||
fn bar(&mut self, an_int: u32, an_float: f32) -> Result<(), types::Errno> {
|
||||
println!("BAR: {} {}", an_int, an_float);
|
||||
Ok(())
|
||||
}
|
||||
fn baz(
|
||||
&mut self,
|
||||
excuse: types::Excuse,
|
||||
a_better_excuse_by_reference: ::memory::GuestPtrMut<types::Excuse>,
|
||||
a_lamer_excuse_by_reference: ::memory::GuestPtr<types::Excuse>,
|
||||
two_layers_of_excuses: ::memory::GuestPtrMut<::memory::GuestPtr<types::Excuse>>,
|
||||
) -> Result<(), types::Errno> {
|
||||
// Read enum value from mutable:
|
||||
let mut a_better_excuse_ref: ::memory::GuestRefMut<types::Excuse> =
|
||||
a_better_excuse_by_reference.as_ref_mut().map_err(|e| {
|
||||
eprintln!("a_better_excuse_by_reference error: {}", e);
|
||||
types::Errno::InvalidArg
|
||||
})?;
|
||||
let a_better_excuse: types::Excuse = *a_better_excuse_ref;
|
||||
|
||||
// Read enum value from immutable ptr:
|
||||
let a_lamer_excuse = *a_lamer_excuse_by_reference.as_ref().map_err(|e| {
|
||||
eprintln!("a_lamer_excuse_by_reference error: {}", e);
|
||||
types::Errno::InvalidArg
|
||||
})?;
|
||||
|
||||
// Write enum to mutable ptr:
|
||||
*a_better_excuse_ref = a_lamer_excuse;
|
||||
|
||||
// Read ptr value from mutable ptr:
|
||||
let one_layer_down: ::memory::GuestPtr<types::Excuse> =
|
||||
two_layers_of_excuses.read_ptr_from_guest().map_err(|e| {
|
||||
eprintln!("one_layer_down error: {}", e);
|
||||
types::Errno::InvalidArg
|
||||
})?;
|
||||
|
||||
// Read enum value from that ptr:
|
||||
let two_layers_down: types::Excuse = *one_layer_down.as_ref().map_err(|e| {
|
||||
eprintln!("two_layers_down error: {}", e);
|
||||
types::Errno::InvalidArg
|
||||
})?;
|
||||
|
||||
// Write ptr value to mutable ptr:
|
||||
two_layers_of_excuses.write_ptr_to_guest(&a_better_excuse_by_reference.as_immut());
|
||||
|
||||
println!(
|
||||
"BAZ: excuse: {:?}, better excuse: {:?}, lamer excuse: {:?}, two layers down: {:?}",
|
||||
excuse, a_better_excuse, a_lamer_excuse, two_layers_down
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn bat(&mut self, an_int: u32) -> Result<f32, types::Errno> {
|
||||
println!("bat: {}", an_int);
|
||||
Ok((an_int as f32) * 2.0)
|
||||
}
|
||||
|
||||
fn sum_of_pair(&mut self, an_pair: &types::PairInts) -> Result<i64, types::Errno> {
|
||||
println!("sum of pair: {:?}", an_pair);
|
||||
Ok(an_pair.first as i64 + an_pair.second as i64)
|
||||
}
|
||||
fn sum_of_pair_of_ptrs(
|
||||
&mut self,
|
||||
an_pair: &types::PairIntPtrs,
|
||||
) -> Result<i64, types::Errno> {
|
||||
let first = *an_pair.first.as_ref().unwrap();
|
||||
let second = *an_pair.second.as_ref().unwrap();
|
||||
println!("sum of pair of ptrs: {} + {}", first, second);
|
||||
Ok(first as i64 + second as i64)
|
||||
}
|
||||
}
|
||||
// Errno is used as a first return value in the functions above, therefore
|
||||
// it must implement GuestErrorType with type Context = WasiCtx.
|
||||
// The context type should let you do logging or debugging or whatever you need
|
||||
// with these errors. We just push them to vecs.
|
||||
impl ::memory::GuestErrorType for types::Errno {
|
||||
type Context = WasiCtx;
|
||||
fn success() -> types::Errno {
|
||||
types::Errno::Ok
|
||||
}
|
||||
fn from_error(e: ::memory::GuestError, ctx: &mut WasiCtx) -> types::Errno {
|
||||
ctx.guest_errors.push(e);
|
||||
types::Errno::InvalidArg
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
pub mod wasi {
|
||||
generate::from_witx!("crates/WASI/phases/snapshot/witx/wasi_snapshot_preview1.witx");
|
||||
|
||||
202
tests/main.rs
Normal file
202
tests/main.rs
Normal file
@@ -0,0 +1,202 @@
|
||||
generate::from_witx!({
|
||||
witx: ["tests/test.witx"],
|
||||
ctx: WasiCtx,
|
||||
});
|
||||
|
||||
use crate::foo::Foo;
|
||||
|
||||
pub struct WasiCtx {
|
||||
guest_errors: Vec<::memory::GuestError>,
|
||||
}
|
||||
|
||||
impl WasiCtx {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
guest_errors: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl foo::Foo for WasiCtx {
|
||||
fn bar(&mut self, an_int: u32, an_float: f32) -> Result<(), types::Errno> {
|
||||
println!("BAR: {} {}", an_int, an_float);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn baz(
|
||||
&mut self,
|
||||
_excuse: types::Excuse,
|
||||
a_better_excuse_by_reference: ::memory::GuestPtrMut<types::Excuse>,
|
||||
a_lamer_excuse_by_reference: ::memory::GuestPtr<types::Excuse>,
|
||||
two_layers_of_excuses: ::memory::GuestPtrMut<::memory::GuestPtr<types::Excuse>>,
|
||||
) -> Result<(), types::Errno> {
|
||||
// Read enum value from mutable:
|
||||
let mut a_better_excuse_ref: ::memory::GuestRefMut<types::Excuse> =
|
||||
a_better_excuse_by_reference.as_ref_mut().map_err(|e| {
|
||||
eprintln!("a_better_excuse_by_reference error: {}", e);
|
||||
types::Errno::InvalidArg
|
||||
})?;
|
||||
let _a_better_excuse: types::Excuse = *a_better_excuse_ref;
|
||||
|
||||
// Read enum value from immutable ptr:
|
||||
let a_lamer_excuse = *a_lamer_excuse_by_reference.as_ref().map_err(|e| {
|
||||
eprintln!("a_lamer_excuse_by_reference error: {}", e);
|
||||
types::Errno::InvalidArg
|
||||
})?;
|
||||
println!("{:?}", a_lamer_excuse);
|
||||
|
||||
// Write enum to mutable ptr:
|
||||
*a_better_excuse_ref = a_lamer_excuse;
|
||||
println!("{:?}", *a_better_excuse_ref);
|
||||
|
||||
// Read ptr value from mutable ptr:
|
||||
let one_layer_down: ::memory::GuestPtr<types::Excuse> =
|
||||
two_layers_of_excuses.read_ptr_from_guest().map_err(|e| {
|
||||
eprintln!("one_layer_down error: {}", e);
|
||||
types::Errno::InvalidArg
|
||||
})?;
|
||||
|
||||
// Read enum value from that ptr:
|
||||
let _two_layers_down: types::Excuse = *one_layer_down.as_ref().map_err(|e| {
|
||||
eprintln!("two_layers_down error: {}", e);
|
||||
types::Errno::InvalidArg
|
||||
})?;
|
||||
|
||||
// Write ptr value to mutable ptr:
|
||||
two_layers_of_excuses.write_ptr_to_guest(&a_better_excuse_by_reference.as_immut());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn bat(&mut self, an_int: u32) -> Result<f32, types::Errno> {
|
||||
Ok((an_int as f32) * 2.0)
|
||||
}
|
||||
|
||||
fn sum_of_pair(&mut self, an_pair: &types::PairInts) -> Result<i64, types::Errno> {
|
||||
Ok(an_pair.first as i64 + an_pair.second as i64)
|
||||
}
|
||||
|
||||
fn sum_of_pair_of_ptrs(&mut self, an_pair: &types::PairIntPtrs) -> Result<i64, types::Errno> {
|
||||
let first = *an_pair
|
||||
.first
|
||||
.as_ref()
|
||||
.expect("dereferencing GuestPtr should succeed");
|
||||
let second = *an_pair
|
||||
.second
|
||||
.as_ref()
|
||||
.expect("dereferncing GuestPtr should succeed");
|
||||
Ok(first as i64 + second as i64)
|
||||
}
|
||||
}
|
||||
// Errno is used as a first return value in the functions above, therefore
|
||||
// it must implement GuestErrorType with type Context = WasiCtx.
|
||||
// The context type should let you do logging or debugging or whatever you need
|
||||
// with these errors. We just push them to vecs.
|
||||
impl ::memory::GuestErrorType for types::Errno {
|
||||
type Context = WasiCtx;
|
||||
fn success() -> types::Errno {
|
||||
types::Errno::Ok
|
||||
}
|
||||
fn from_error(e: ::memory::GuestError, ctx: &mut WasiCtx) -> types::Errno {
|
||||
ctx.guest_errors.push(e);
|
||||
types::Errno::InvalidArg
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(align(4096))]
|
||||
struct HostMemory {
|
||||
buffer: [u8; 4096],
|
||||
}
|
||||
impl HostMemory {
|
||||
pub fn new() -> Self {
|
||||
HostMemory { buffer: [0; 4096] }
|
||||
}
|
||||
pub fn as_mut_ptr(&mut self) -> *mut u8 {
|
||||
self.buffer.as_mut_ptr()
|
||||
}
|
||||
pub fn len(&self) -> usize {
|
||||
self.buffer.len()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hostmemory_is_aligned() {
|
||||
let mut h = HostMemory::new();
|
||||
assert_eq!(h.as_mut_ptr() as usize % 4096, 0);
|
||||
let mut h = Box::new(HostMemory::new());
|
||||
assert_eq!(h.as_mut_ptr() as usize % 4096, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bat() {
|
||||
let mut ctx = WasiCtx::new();
|
||||
assert_eq!(ctx.bat(2), Ok(4.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn baz() {
|
||||
let mut ctx = WasiCtx::new();
|
||||
let mut host_memory = HostMemory::new();
|
||||
let guest_memory = memory::GuestMemory::new(host_memory.as_mut_ptr(), host_memory.len() as u32);
|
||||
let sizeof_excuse = std::mem::size_of::<types::Excuse>();
|
||||
let padding = 4 - sizeof_excuse % 4;
|
||||
{
|
||||
let lame_mut: memory::GuestPtrMut<types::Excuse> = guest_memory.ptr_mut(0).unwrap();
|
||||
let mut lame = lame_mut.as_ref_mut().unwrap();
|
||||
*lame = types::Excuse::Sleeping;
|
||||
}
|
||||
let lame: memory::GuestPtr<types::Excuse> = guest_memory
|
||||
.ptr(0)
|
||||
.expect("GuestPtr<types::Excuse> fits in the memory");
|
||||
assert_eq!(*lame.as_ref().unwrap(), types::Excuse::Sleeping);
|
||||
let better: memory::GuestPtrMut<types::Excuse> = guest_memory
|
||||
.ptr_mut((sizeof_excuse + padding) as u32)
|
||||
.expect("GuestPtr<types::Excuse> fits in the memory");
|
||||
let ptr_to_ptr: memory::GuestPtrMut<memory::GuestPtr<types::Excuse>> = guest_memory
|
||||
.ptr_mut((sizeof_excuse + padding) as u32 * 2)
|
||||
.expect("GuestPtr<GuestPtr<_>> fits in the memory");
|
||||
assert!(ctx
|
||||
.baz(
|
||||
types::Excuse::DogAte,
|
||||
better.clone(),
|
||||
lame,
|
||||
ptr_to_ptr.clone()
|
||||
)
|
||||
.is_ok());
|
||||
assert_eq!(*better.as_ref().unwrap(), types::Excuse::Sleeping);
|
||||
let ptr = ptr_to_ptr.read_ptr_from_guest().unwrap();
|
||||
assert_eq!(*ptr.as_ref().unwrap(), types::Excuse::Sleeping);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sum_of_pair() {
|
||||
let mut ctx = WasiCtx::new();
|
||||
let pair = types::PairInts {
|
||||
first: 1,
|
||||
second: 2,
|
||||
};
|
||||
assert_eq!(ctx.sum_of_pair(&pair), Ok(3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sum_of_pair_of_ptrs() {
|
||||
let mut ctx = WasiCtx::new();
|
||||
let mut host_memory = HostMemory::new();
|
||||
let guest_memory = memory::GuestMemory::new(host_memory.as_mut_ptr(), host_memory.len() as u32);
|
||||
{
|
||||
let first_mut: memory::GuestPtrMut<i32> = guest_memory.ptr_mut(0).unwrap();
|
||||
let mut x = first_mut.as_ref_mut().unwrap();
|
||||
*x = 1;
|
||||
let second_mut: memory::GuestPtrMut<i32> = guest_memory.ptr_mut(4).unwrap();
|
||||
let mut x = second_mut.as_ref_mut().unwrap();
|
||||
*x = 2;
|
||||
}
|
||||
let first: memory::GuestPtr<i32> = guest_memory
|
||||
.ptr(0)
|
||||
.expect("GuestPtr<i32> fits in the memory");
|
||||
let second: memory::GuestPtr<i32> = guest_memory
|
||||
.ptr(4)
|
||||
.expect("GuestPtr<i32> fits in the memory");
|
||||
let pair = types::PairIntPtrs { first, second };
|
||||
assert_eq!(ctx.sum_of_pair_of_ptrs(&pair), Ok(3));
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
(typename $errno
|
||||
(enum u32
|
||||
$ok
|
||||
Reference in New Issue
Block a user