Path: blob/main/crates/wiggle/tests/records.rs
1692 views
use proptest::prelude::*;1use wiggle::{GuestMemory, GuestPtr};2use wiggle_test::{HostMemory, MemArea, MemAreas, WasiCtx, impl_errno};34wiggle::from_witx!({5witx: ["tests/records.witx"],6});78impl_errno!(types::Errno);910impl<'a> records::Records for WasiCtx<'a> {11fn sum_of_pair(12&mut self,13_memory: &mut GuestMemory<'_>,14an_pair: &types::PairInts,15) -> Result<i64, types::Errno> {16Ok(an_pair.first as i64 + an_pair.second as i64)17}1819fn sum_of_pair_of_ptrs(20&mut self,21memory: &mut GuestMemory<'_>,22an_pair: &types::PairIntPtrs,23) -> Result<i64, types::Errno> {24let first = memory25.read(an_pair.first)26.expect("dereferencing GuestPtr should succeed");27let second = memory28.read(an_pair.second)29.expect("dereferencing GuestPtr should succeed");30Ok(first as i64 + second as i64)31}3233fn sum_of_int_and_ptr(34&mut self,35memory: &mut GuestMemory<'_>,36an_pair: &types::PairIntAndPtr,37) -> Result<i64, types::Errno> {38let first = memory39.read(an_pair.first)40.expect("dereferencing GuestPtr should succeed");41let second = an_pair.second as i64;42Ok(first as i64 + second)43}4445fn return_pair_ints(46&mut self,47_memory: &mut GuestMemory<'_>,48) -> Result<types::PairInts, types::Errno> {49Ok(types::PairInts {50first: 10,51second: 20,52})53}5455fn return_pair_of_ptrs(56&mut self,57_memory: &mut GuestMemory<'_>,58first: GuestPtr<i32>,59second: GuestPtr<i32>,60) -> Result<types::PairIntPtrs, types::Errno> {61Ok(types::PairIntPtrs { first, second })62}6364fn sum_array(65&mut self,66memory: &mut GuestMemory<'_>,67record_of_list: &types::RecordOfList,68) -> Result<u16, types::Errno> {69// my kingdom for try blocks70fn aux(71memory: &mut GuestMemory<'_>,72record_of_list: &types::RecordOfList,73) -> Result<u16, wiggle::GuestError> {74let mut s = 0;75for elem in record_of_list.arr.iter() {76let v = memory.read(elem?)?;77s += v as u16;78}79Ok(s)80}81match aux(memory, record_of_list) {82Ok(s) => Ok(s),83Err(guest_err) => {84eprintln!("guest error summing array: {guest_err:?}");85Err(types::Errno::PicketLine)86}87}88}89}9091#[derive(Debug)]92struct SumOfPairExercise {93pub input: types::PairInts,94pub input_loc: MemArea,95pub return_loc: MemArea,96}9798impl SumOfPairExercise {99pub fn strat() -> BoxedStrategy<Self> {100(101prop::num::i32::ANY,102prop::num::i32::ANY,103HostMemory::mem_area_strat(8),104HostMemory::mem_area_strat(8),105)106.prop_map(|(first, second, input_loc, return_loc)| SumOfPairExercise {107input: types::PairInts { first, second },108input_loc,109return_loc,110})111.prop_filter("non-overlapping pointers", |e| {112MemArea::non_overlapping_set(&[e.input_loc, e.return_loc])113})114.boxed()115}116117pub fn test(&self) {118let mut ctx = WasiCtx::new();119let mut host_memory = HostMemory::new();120let mut memory = host_memory.guest_memory();121122memory123.write(GuestPtr::new(self.input_loc.ptr), self.input.first)124.expect("input ref_mut");125memory126.write(GuestPtr::new(self.input_loc.ptr + 4), self.input.second)127.expect("input ref_mut");128let sum_err = records::sum_of_pair(129&mut ctx,130&mut memory,131self.input_loc.ptr as i32,132self.return_loc.ptr as i32,133)134.unwrap();135136assert_eq!(sum_err, types::Errno::Ok as i32, "sum errno");137138let return_val: i64 = memory139.read(GuestPtr::new(self.return_loc.ptr))140.expect("return ref");141142assert_eq!(143return_val,144self.input.first as i64 + self.input.second as i64,145"sum return value"146);147}148}149150proptest! {151#[test]152fn sum_of_pair(e in SumOfPairExercise::strat()) {153e.test();154}155}156157#[derive(Debug)]158struct SumPairPtrsExercise {159input_first: i32,160input_second: i32,161input_first_loc: MemArea,162input_second_loc: MemArea,163input_struct_loc: MemArea,164return_loc: MemArea,165}166167impl SumPairPtrsExercise {168pub fn strat() -> BoxedStrategy<Self> {169(170prop::num::i32::ANY,171prop::num::i32::ANY,172HostMemory::mem_area_strat(4),173HostMemory::mem_area_strat(4),174HostMemory::mem_area_strat(8),175HostMemory::mem_area_strat(8),176)177.prop_map(178|(179input_first,180input_second,181input_first_loc,182input_second_loc,183input_struct_loc,184return_loc,185)| SumPairPtrsExercise {186input_first,187input_second,188input_first_loc,189input_second_loc,190input_struct_loc,191return_loc,192},193)194.prop_filter("non-overlapping pointers", |e| {195MemArea::non_overlapping_set(&[196e.input_first_loc,197e.input_second_loc,198e.input_struct_loc,199e.return_loc,200])201})202.boxed()203}204pub fn test(&self) {205let mut ctx = WasiCtx::new();206let mut host_memory = HostMemory::new();207let mut memory = host_memory.guest_memory();208209memory210.write(GuestPtr::new(self.input_first_loc.ptr), self.input_first)211.expect("input_first ref");212memory213.write(GuestPtr::new(self.input_second_loc.ptr), self.input_second)214.expect("input_second ref");215216memory217.write(218GuestPtr::new(self.input_struct_loc.ptr),219self.input_first_loc.ptr,220)221.expect("input_struct ref");222memory223.write(224GuestPtr::new(self.input_struct_loc.ptr + 4),225self.input_second_loc.ptr,226)227.expect("input_struct ref");228229let res = records::sum_of_pair_of_ptrs(230&mut ctx,231&mut memory,232self.input_struct_loc.ptr as i32,233self.return_loc.ptr as i32,234)235.unwrap();236237assert_eq!(res, types::Errno::Ok as i32, "sum of pair of ptrs errno");238239let doubled: i64 = memory240.read(GuestPtr::new(self.return_loc.ptr))241.expect("return ref");242243assert_eq!(244doubled,245(self.input_first as i64) + (self.input_second as i64),246"sum of pair of ptrs return val"247);248}249}250proptest! {251#[test]252fn sum_of_pair_of_ptrs(e in SumPairPtrsExercise::strat()) {253e.test()254}255}256257#[derive(Debug)]258struct SumIntAndPtrExercise {259input_first: i32,260input_second: i32,261input_first_loc: MemArea,262input_struct_loc: MemArea,263return_loc: MemArea,264}265266impl SumIntAndPtrExercise {267pub fn strat() -> BoxedStrategy<Self> {268(269prop::num::i32::ANY,270prop::num::i32::ANY,271HostMemory::mem_area_strat(4),272HostMemory::mem_area_strat(8),273HostMemory::mem_area_strat(8),274)275.prop_map(276|(input_first, input_second, input_first_loc, input_struct_loc, return_loc)| {277SumIntAndPtrExercise {278input_first,279input_second,280input_first_loc,281input_struct_loc,282return_loc,283}284},285)286.prop_filter("non-overlapping pointers", |e| {287MemArea::non_overlapping_set(&[e.input_first_loc, e.input_struct_loc, e.return_loc])288})289.boxed()290}291pub fn test(&self) {292let mut ctx = WasiCtx::new();293let mut host_memory = HostMemory::new();294let mut memory = host_memory.guest_memory();295296memory297.write(GuestPtr::new(self.input_first_loc.ptr), self.input_first)298.expect("input_first ref");299memory300.write(301GuestPtr::new(self.input_struct_loc.ptr),302self.input_first_loc.ptr,303)304.expect("input_struct ref");305memory306.write(307GuestPtr::new(self.input_struct_loc.ptr + 4),308self.input_second,309)310.expect("input_struct ref");311312let res = records::sum_of_int_and_ptr(313&mut ctx,314&mut memory,315self.input_struct_loc.ptr as i32,316self.return_loc.ptr as i32,317)318.unwrap();319320assert_eq!(res, types::Errno::Ok as i32, "sum of int and ptr errno");321322let doubled: i64 = memory323.read(GuestPtr::new(self.return_loc.ptr))324.expect("return ref");325326assert_eq!(327doubled,328(self.input_first as i64) + (self.input_second as i64),329"sum of pair of ptrs return val"330);331}332}333proptest! {334#[test]335fn sum_of_int_and_ptr(e in SumIntAndPtrExercise::strat()) {336e.test()337}338}339340#[derive(Debug)]341struct ReturnPairInts {342pub return_loc: MemArea,343}344345impl ReturnPairInts {346pub fn strat() -> BoxedStrategy<Self> {347HostMemory::mem_area_strat(8)348.prop_map(|return_loc| ReturnPairInts { return_loc })349.boxed()350}351352pub fn test(&self) {353let mut ctx = WasiCtx::new();354let mut host_memory = HostMemory::new();355let mut memory = host_memory.guest_memory();356357let err =358records::return_pair_ints(&mut ctx, &mut memory, self.return_loc.ptr as i32).unwrap();359360assert_eq!(err, types::Errno::Ok as i32, "return struct errno");361362let return_struct: types::PairInts = memory363.read(GuestPtr::new(self.return_loc.ptr))364.expect("return ref");365366assert_eq!(367return_struct,368types::PairInts {369first: 10,370second: 20371},372"return_pair_ints return value"373);374}375}376377proptest! {378#[test]379fn return_pair_ints(e in ReturnPairInts::strat()) {380e.test();381}382}383384#[derive(Debug)]385struct ReturnPairPtrsExercise {386input_first: i32,387input_second: i32,388input_first_loc: MemArea,389input_second_loc: MemArea,390return_loc: MemArea,391}392393impl ReturnPairPtrsExercise {394pub fn strat() -> BoxedStrategy<Self> {395(396prop::num::i32::ANY,397prop::num::i32::ANY,398HostMemory::mem_area_strat(4),399HostMemory::mem_area_strat(4),400HostMemory::mem_area_strat(8),401)402.prop_map(403|(input_first, input_second, input_first_loc, input_second_loc, return_loc)| {404ReturnPairPtrsExercise {405input_first,406input_second,407input_first_loc,408input_second_loc,409return_loc,410}411},412)413.prop_filter("non-overlapping pointers", |e| {414MemArea::non_overlapping_set(&[e.input_first_loc, e.input_second_loc, e.return_loc])415})416.boxed()417}418pub fn test(&self) {419let mut ctx = WasiCtx::new();420let mut host_memory = HostMemory::new();421let mut memory = host_memory.guest_memory();422423memory424.write(GuestPtr::new(self.input_first_loc.ptr), self.input_first)425.expect("input_first ref");426memory427.write(GuestPtr::new(self.input_second_loc.ptr), self.input_second)428.expect("input_second ref");429430let res = records::return_pair_of_ptrs(431&mut ctx,432&mut memory,433self.input_first_loc.ptr as i32,434self.input_second_loc.ptr as i32,435self.return_loc.ptr as i32,436)437.unwrap();438439assert_eq!(res, types::Errno::Ok as i32, "return pair of ptrs errno");440441let ptr_pair_int_ptrs: types::PairIntPtrs = memory442.read(GuestPtr::new(self.return_loc.ptr))443.expect("failed to read return location");444let ret_first_ptr = ptr_pair_int_ptrs.first;445let ret_second_ptr = ptr_pair_int_ptrs.second;446assert_eq!(447self.input_first,448memory449.read(ret_first_ptr)450.expect("deref extracted ptr to first element")451);452assert_eq!(453self.input_second,454memory455.read(ret_second_ptr)456.expect("deref extracted ptr to second element")457);458}459}460proptest! {461#[test]462fn return_pair_of_ptrs(e in ReturnPairPtrsExercise::strat()) {463e.test()464}465}466467#[derive(Debug)]468struct SumArrayExercise {469inputs: Vec<u8>,470input_array_loc: MemArea,471input_struct_loc: MemArea,472output_loc: MemArea,473}474475impl SumArrayExercise {476pub fn strat() -> BoxedStrategy<Self> {477(0..256u32)478.prop_flat_map(|len| {479let len_usize = len as usize;480(481prop::collection::vec(prop::num::u8::ANY, len_usize..=len_usize),482HostMemory::mem_area_strat(8), // Input struct is 8 bytes - ptr and len483HostMemory::mem_area_strat(4), // Output is 4 bytes - stores a u16, but abi requires 4 byte alignment484)485})486.prop_filter(487"non-overlapping input struct and output pointers",488|(_inputs, input_struct_loc, output_loc)| {489MemArea::non_overlapping_set(&[*input_struct_loc, *output_loc])490},491)492.prop_flat_map(|(inputs, input_struct_loc, output_loc)| {493(494Just(inputs.clone()),495HostMemory::byte_slice_strat(496inputs.len() as u32,4971,498&MemAreas::from([input_struct_loc, output_loc]),499),500Just(input_struct_loc),501Just(output_loc),502)503})504.prop_map(505|(inputs, input_array_loc, input_struct_loc, output_loc)| SumArrayExercise {506inputs,507input_array_loc,508input_struct_loc,509output_loc,510},511)512.boxed()513}514pub fn test(&self) {515let mut ctx = WasiCtx::new();516let mut host_memory = HostMemory::new();517let mut memory = host_memory.guest_memory();518519// Write inputs to memory as an array520for (ix, val) in self.inputs.iter().enumerate() {521let ix = ix as u32;522memory523.write(GuestPtr::new(self.input_array_loc.ptr + ix), *val)524.expect("write val to array memory");525}526527// Write struct that contains the array528memory529.write(530GuestPtr::new(self.input_struct_loc.ptr),531self.input_array_loc.ptr,532)533.expect("write ptr to struct memory");534memory535.write(536GuestPtr::new(self.input_struct_loc.ptr + 4),537self.inputs.len() as u32,538)539.expect("write len to struct memory");540541// Call wiggle-generated func542let res = records::sum_array(543&mut ctx,544&mut memory,545self.input_struct_loc.ptr as i32,546self.output_loc.ptr as i32,547)548.unwrap();549550// should be no error - if hostcall did a GuestError it should eprintln it.551assert_eq!(res, types::Errno::Ok as i32, "reduce excuses errno");552553// Sum is inputs upcasted to u16554let expected: u16 = self.inputs.iter().map(|v| *v as u16).sum();555556// Wiggle stored output value in memory as u16557let given: u16 = memory558.read(GuestPtr::new(self.output_loc.ptr))559.expect("deref ptr to returned value");560561// Assert the two calculations match562assert_eq!(expected, given, "sum_array return val");563}564}565proptest! {566#[test]567fn sum_of_array(e in SumArrayExercise::strat()) {568e.test()569}570}571572#[test]573fn pair_ints_offsets() {574assert_eq!(types::PairInts::offset_of_first(), 0);575assert_eq!(types::PairInts::offset_of_second(), 4);576}577578#[test]579fn pair_different_ints_offsets() {580assert_eq!(types::PairDifferentInts::offset_of_first(), 0);581assert_eq!(types::PairDifferentInts::offset_of_second(), 8);582assert_eq!(types::PairDifferentInts::offset_of_third(), 10);583assert_eq!(types::PairDifferentInts::offset_of_fourth(), 12);584}585586#[test]587fn pair_int_ptrs_offsets() {588assert_eq!(types::PairIntPtrs::offset_of_first(), 0);589assert_eq!(types::PairIntPtrs::offset_of_second(), 4);590}591592#[test]593fn pair_int_and_ptr_offsets() {594assert_eq!(types::PairIntAndPtr::offset_of_first(), 0);595assert_eq!(types::PairIntAndPtr::offset_of_second(), 4);596}597598#[test]599fn pair_record_of_list_offset() {600assert_eq!(types::RecordOfList::offset_of_arr(), 0);601}602603604