Path: blob/main/crates/wiggle/tests/variant.rs
1692 views
use proptest::prelude::*;1use wiggle::{GuestMemory, GuestPtr, GuestType};2use wiggle_test::{HostMemory, MemArea, WasiCtx, impl_errno};34wiggle::from_witx!({5witx: ["tests/variant.witx"],6});78impl_errno!(types::Errno);910// Avoid panics on overflow11fn mult_lose_overflow(a: i32, b: u32) -> i32 {12let a_64: i64 = a as i64;13let b_64: i64 = b as i64;14let product = a_64 * b_64;15product as i3216}1718// Avoid assert_eq(NaN, NaN) failures19fn mult_zero_nan(a: f32, b: u32) -> f32 {20if a.is_nan() {210.022} else {23let product = a * b as f32;24if product.is_nan() { 0.0 } else { product }25}26}2728impl<'a> variant_example::VariantExample for WasiCtx<'a> {29fn get_tag(30&mut self,31_memory: &mut GuestMemory<'_>,32u: &types::Reason,33) -> Result<types::Excuse, types::Errno> {34println!("GET TAG: {u:?}");35match u {36types::Reason::DogAte { .. } => Ok(types::Excuse::DogAte),37types::Reason::Traffic { .. } => Ok(types::Excuse::Traffic),38types::Reason::Sleeping { .. } => Ok(types::Excuse::Sleeping),39}40}41fn reason_mult(42&mut self,43memory: &mut GuestMemory<'_>,44u: &types::ReasonMut,45multiply_by: u32,46) -> Result<(), types::Errno> {47match u {48types::ReasonMut::DogAte(fptr) => {49let val = memory.read(*fptr).expect("valid pointer");50println!("REASON MULT DogAte({val})");51memory52.write(*fptr, mult_zero_nan(val, multiply_by))53.expect("valid pointer");54}55types::ReasonMut::Traffic(iptr) => {56let val = memory.read(*iptr).expect("valid pointer");57println!("REASON MULT Traffic({val})");58memory59.write(*iptr, mult_lose_overflow(val, multiply_by))60.expect("valid pointer");61}62types::ReasonMut::Sleeping => {63println!("REASON MULT Sleeping");64}65}66Ok(())67}68}6970fn reason_strat() -> impl Strategy<Value = types::Reason> {71prop_oneof![72prop::num::f32::ANY.prop_map(|v| types::Reason::DogAte(v)),73prop::num::i32::ANY.prop_map(|v| types::Reason::Traffic(v)),74Just(types::Reason::Sleeping),75]76.boxed()77}7879fn reason_tag(r: &types::Reason) -> types::Excuse {80match r {81types::Reason::DogAte { .. } => types::Excuse::DogAte,82types::Reason::Traffic { .. } => types::Excuse::Traffic,83types::Reason::Sleeping { .. } => types::Excuse::Sleeping,84}85}8687#[derive(Debug)]88struct GetTagExercise {89pub input: types::Reason,90pub input_loc: MemArea,91pub return_loc: MemArea,92}9394impl GetTagExercise {95pub fn strat() -> BoxedStrategy<Self> {96(97reason_strat(),98HostMemory::mem_area_strat(types::Reason::guest_size()),99HostMemory::mem_area_strat(types::Excuse::guest_size()),100)101.prop_map(|(input, input_loc, return_loc)| GetTagExercise {102input,103input_loc,104return_loc,105})106.prop_filter("non-overlapping pointers", |e| {107MemArea::non_overlapping_set(&[e.input_loc, e.return_loc])108})109.boxed()110}111112pub fn test(&self) {113let mut ctx = WasiCtx::new();114let mut host_memory = HostMemory::new();115let mut memory = host_memory.guest_memory();116117let discriminant = reason_tag(&self.input) as u8;118memory119.write(GuestPtr::new(self.input_loc.ptr), discriminant)120.expect("input discriminant ptr");121match self.input {122types::Reason::DogAte(f) => {123memory124.write(GuestPtr::new(self.input_loc.ptr + 4), f)125.expect("input contents ref_mut");126}127types::Reason::Traffic(v) => memory128.write(GuestPtr::new(self.input_loc.ptr + 4), v)129.expect("input contents ref_mut"),130types::Reason::Sleeping => {} // Do nothing131}132let e = variant_example::get_tag(133&mut ctx,134&mut memory,135self.input_loc.ptr as i32,136self.return_loc.ptr as i32,137)138.unwrap();139140assert_eq!(e, types::Errno::Ok as i32, "get_tag errno");141142let return_val: types::Excuse = memory143.read(GuestPtr::new(self.return_loc.ptr))144.expect("return ref");145146assert_eq!(return_val, reason_tag(&self.input), "get_tag return value");147}148}149150proptest! {151#[test]152fn get_tag(e in GetTagExercise::strat()) {153e.test();154}155}156157#[derive(Debug)]158struct ReasonMultExercise {159pub input: types::Reason,160pub input_loc: MemArea,161pub input_pointee_loc: MemArea,162pub multiply_by: u32,163}164165impl ReasonMultExercise {166pub fn strat() -> BoxedStrategy<Self> {167(168reason_strat(),169HostMemory::mem_area_strat(types::Reason::guest_size()),170HostMemory::mem_area_strat(4),171prop::num::u32::ANY,172)173.prop_map(174|(input, input_loc, input_pointee_loc, multiply_by)| ReasonMultExercise {175input,176input_loc,177input_pointee_loc,178multiply_by,179},180)181.prop_filter("non-overlapping pointers", |e| {182MemArea::non_overlapping_set(&[e.input_loc, e.input_pointee_loc])183})184.boxed()185}186187pub fn test(&self) {188let mut ctx = WasiCtx::new();189let mut host_memory = HostMemory::new();190let mut memory = host_memory.guest_memory();191192let discriminant = reason_tag(&self.input) as u8;193memory194.write(GuestPtr::new(self.input_loc.ptr), discriminant)195.expect("input discriminant ref_mut");196memory197.write(198GuestPtr::new(self.input_loc.ptr + 4),199self.input_pointee_loc.ptr,200)201.expect("input pointer ref_mut");202203match self.input {204types::Reason::DogAte(f) => {205memory206.write(GuestPtr::new(self.input_pointee_loc.ptr), f)207.expect("input contents ref_mut");208}209types::Reason::Traffic(v) => {210memory211.write(GuestPtr::new(self.input_pointee_loc.ptr), v)212.expect("input contents ref_mut");213}214types::Reason::Sleeping => {} // Do nothing215}216let e = variant_example::reason_mult(217&mut ctx,218&mut memory,219self.input_loc.ptr as i32,220self.multiply_by as i32,221)222.unwrap();223224assert_eq!(e, types::Errno::Ok as i32, "reason_mult errno");225226match self.input {227types::Reason::DogAte(f) => {228let f_result: f32 = memory229.read(GuestPtr::new(self.input_pointee_loc.ptr))230.expect("input contents ref_mut");231assert_eq!(232mult_zero_nan(f, self.multiply_by),233f_result,234"DogAte result"235)236}237types::Reason::Traffic(v) => {238let v_result: i32 = memory239.read(GuestPtr::new(self.input_pointee_loc.ptr))240.expect("input contents ref_mut");241assert_eq!(242mult_lose_overflow(v, self.multiply_by),243v_result,244"Traffic result"245)246}247types::Reason::Sleeping => {} // Do nothing248}249}250}251252proptest! {253#[test]254fn reason_mult(e in ReasonMultExercise::strat()) {255e.test();256}257}258259260