* test coverage: make sure aliases to builtins get tested

* trivial support for handles

* add tests for handles
This commit is contained in:
Pat Hickey
2020-02-27 03:57:36 -07:00
committed by GitHub
parent 10dcaeeab4
commit 90182bc5da
6 changed files with 166 additions and 5 deletions

View File

@@ -308,6 +308,11 @@ fn marshal_arg(
}
}
witx::Type::Union(_u) => read_conversion,
witx::Type::Handle(_h) => {
let name = names.func_param(&param.name);
let handle_type = names.type_ref(tref, anon_lifetime());
quote!( let #name = #handle_type::from(#name); )
}
_ => unimplemented!("argument type marshalling"),
}
}

View File

@@ -21,7 +21,7 @@ pub fn define_datatype(names: &Names, namedtype: &witx::NamedType) -> TokenStrea
}
}
witx::Type::Union(u) => define_union(names, &namedtype.name, &u),
witx::Type::Handle(_h) => unimplemented!("handle types"),
witx::Type::Handle(h) => define_handle(names, &namedtype.name, &h),
witx::Type::Builtin(b) => define_builtin(names, &namedtype.name, *b),
witx::Type::Pointer(p) => define_witx_pointer(
names,
@@ -398,10 +398,73 @@ fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype) -> TokenS
}
}
fn define_handle(names: &Names, name: &witx::Id, h: &witx::HandleDatatype) -> TokenStream {
let ident = names.type_(name);
let size = h.mem_size_align().size as u32;
let align = h.mem_size_align().align as u32;
quote! {
#[derive(Copy, Clone, Debug, ::std::hash::Hash, Eq, PartialEq)]
pub struct #ident(u32);
impl From<#ident> for u32 {
fn from(e: #ident) -> u32 {
e.0
}
}
impl From<#ident> for i32 {
fn from(e: #ident) -> i32 {
e.0 as i32
}
}
impl From<u32> for #ident {
fn from(e: u32) -> #ident {
#ident(e)
}
}
impl From<i32> for #ident {
fn from(e: i32) -> #ident {
#ident(e as u32)
}
}
impl ::std::fmt::Display for #ident {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
write!(f, "{}({})", stringify!(#ident), self.0)
}
}
impl wiggle_runtime::GuestType for #ident {
fn size() -> u32 {
#size
}
fn align() -> u32 {
#align
}
fn name() -> String {
stringify!(#ident).to_owned()
}
fn validate(ptr: &wiggle_runtime::GuestPtr<#ident>) -> Result<(), wiggle_runtime::GuestError> {
Ok(())
}
}
impl<'a> wiggle_runtime::GuestTypeClone<'a> for #ident {
fn read_from_guest(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<#ident, wiggle_runtime::GuestError> {
let r = location.as_ref()?;
Ok(*r)
}
fn write_to_guest(&self, location: &wiggle_runtime::GuestPtrMut<'a, Self>) {
unsafe { (location.as_raw() as *mut #ident).write(*self) };
}
}
impl<'a> wiggle_runtime::GuestTypeCopy<'a> for #ident {}
}
}
fn define_builtin(names: &Names, name: &witx::Id, builtin: witx::BuiltinType) -> TokenStream {
let ident = names.type_(name);
let built = names.builtin_type(builtin, quote!('a));
if let witx::BuiltinType::String = builtin {
if builtin.needs_lifetime() {
quote!(pub type #ident<'a> = #built;)
} else {
quote!(pub type #ident = #built;)

View File

@@ -14,7 +14,10 @@ impl atoms::Atoms for WasiCtx {
println!("INT FLOAT ARGS: {} {}", an_int, an_float);
Ok(())
}
fn double_int_return_float(&mut self, an_int: u32) -> Result<f32, types::Errno> {
fn double_int_return_float(
&mut self,
an_int: u32,
) -> Result<types::AliasToFloat, types::Errno> {
Ok((an_int as f32) * 2.0)
}
}
@@ -75,7 +78,7 @@ impl DoubleIntExercise {
self.return_loc.ptr as i32,
);
let return_val: GuestRef<f32> = guest_memory
let return_val: GuestRef<types::AliasToFloat> = guest_memory
.ptr(self.return_loc.ptr)
.expect("return loc ptr")
.as_ref()

View File

@@ -1,5 +1,7 @@
(use "errno.witx")
(typename $alias_to_float f32)
(module $atoms
(@interface func (export "int_float_args")
(param $an_int u32)
@@ -8,5 +10,5 @@
(@interface func (export "double_int_return_float")
(param $an_int u32)
(result $error $errno)
(result $doubled_it f32))
(result $doubled_it $alias_to_float))
)

76
tests/handles.rs Normal file
View File

@@ -0,0 +1,76 @@
use proptest::prelude::*;
use wiggle_runtime::{GuestError, GuestType};
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
const FD_VAL: u32 = 123;
wiggle_generate::from_witx!({
witx: ["tests/handles.witx"],
ctx: WasiCtx,
});
impl_errno!(types::Errno);
impl handle_examples::HandleExamples for WasiCtx {
fn fd_create(&mut self) -> Result<types::Fd, types::Errno> {
Ok(types::Fd::from(FD_VAL))
}
fn fd_consume(&mut self, fd: types::Fd) -> Result<(), types::Errno> {
println!("FD_CONSUME {}", fd);
if fd == types::Fd::from(FD_VAL) {
Ok(())
} else {
Err(types::Errno::InvalidArg)
}
}
}
#[derive(Debug)]
struct HandleExercise {
pub return_loc: MemArea,
}
impl HandleExercise {
pub fn test(&self) {
let mut ctx = WasiCtx::new();
let mut host_memory = HostMemory::new();
let mut guest_memory = host_memory.guest_memory();
let e = handle_examples::fd_create(&mut ctx, &mut guest_memory, self.return_loc.ptr as i32);
assert_eq!(e, types::Errno::Ok.into(), "fd_create error");
let h_got: u32 = *guest_memory
.ptr(self.return_loc.ptr)
.expect("return ptr")
.as_ref()
.expect("return ref_mut");
assert_eq!(h_got, 123, "fd_create return val");
let e = handle_examples::fd_consume(&mut ctx, &mut guest_memory, h_got as i32);
assert_eq!(e, types::Errno::Ok.into(), "fd_consume error");
let e = handle_examples::fd_consume(&mut ctx, &mut guest_memory, h_got as i32 + 1);
assert_eq!(
e,
types::Errno::InvalidArg.into(),
"fd_consume invalid error"
);
}
pub fn strat() -> BoxedStrategy<Self> {
(HostMemory::mem_area_strat(types::Fd::size()))
.prop_map(|return_loc| HandleExercise { return_loc })
.boxed()
}
}
proptest! {
#[test]
fn handle_exercise(e in HandleExercise::strat()) {
e.test()
}
}

12
tests/handles.witx Normal file
View File

@@ -0,0 +1,12 @@
(use "errno.witx")
(typename $fd (handle))
(module $handle_examples
(@interface func (export "fd_create")
(result $error $errno)
(result $fd $fd))
(@interface func (export "fd_consume")
(param $fd $fd)
(result $error $errno))
)