diff --git a/crates/wiggle/tests/strings.rs b/crates/wiggle/tests/strings.rs index cff55d92d0..ed176f6f62 100644 --- a/crates/wiggle/tests/strings.rs +++ b/crates/wiggle/tests/strings.rs @@ -34,9 +34,12 @@ impl<'a> strings::Strings for WasiCtx<'a> { } } -fn test_string_strategy() -> impl Strategy { +fn unicode_string_strategy() -> impl Strategy { "\\p{Greek}{1,256}" } +fn ascii_string_strategy() -> impl Strategy { + "[a-zA-Z0..9]{1,256}" +} #[derive(Debug)] struct HelloStringExercise { @@ -47,7 +50,7 @@ struct HelloStringExercise { impl HelloStringExercise { pub fn strat() -> BoxedStrategy { - (test_string_strategy(),) + (unicode_string_strategy(),) .prop_flat_map(|(test_word,)| { ( Just(test_word.clone()), @@ -115,9 +118,9 @@ struct MultiStringExercise { impl MultiStringExercise { pub fn strat() -> BoxedStrategy { ( - test_string_strategy(), - test_string_strategy(), - test_string_strategy(), + unicode_string_strategy(), + unicode_string_strategy(), + unicode_string_strategy(), HostMemory::mem_area_strat(4), ) .prop_flat_map(|(a, b, c, return_ptr_loc)| { @@ -221,3 +224,85 @@ proptest! { e.test() } } + +#[derive(Debug)] +struct OverlappingStringExercise { + a: String, + sa_ptr_loc: MemArea, + offset_b: u32, + offset_c: u32, + return_ptr_loc: MemArea, +} + +impl OverlappingStringExercise { + pub fn strat() -> BoxedStrategy { + // using ascii so we can window into it without worrying about codepoints + (ascii_string_strategy(), HostMemory::mem_area_strat(4)) + .prop_flat_map(|(a, return_ptr_loc)| { + ( + Just(a.clone()), + HostMemory::mem_area_strat(a.len() as u32), + 0..(a.len() as u32), + 0..(a.len() as u32), + Just(return_ptr_loc), + ) + }) + .prop_map(|(a, sa_ptr_loc, offset_b, offset_c, return_ptr_loc)| Self { + a, + sa_ptr_loc, + offset_b, + offset_c, + return_ptr_loc, + }) + .prop_filter("non-overlapping pointers", |e| { + MemArea::non_overlapping_set(&[e.sa_ptr_loc, e.return_ptr_loc]) + }) + .boxed() + } + + pub fn test(&self) { + let ctx = WasiCtx::new(); + let host_memory = HostMemory::new(); + + let write_string = |val: &str, loc: MemArea| { + let ptr = host_memory.ptr::((loc.ptr, val.len() as u32)); + for (slot, byte) in ptr.as_bytes().iter().zip(val.bytes()) { + slot.expect("should be valid pointer") + .write(byte) + .expect("failed to write"); + } + }; + + write_string(&self.a, self.sa_ptr_loc); + + let a_len = self.a.as_bytes().len() as i32; + let res = strings::multi_string( + &ctx, + &host_memory, + self.sa_ptr_loc.ptr as i32, + a_len, + (self.sa_ptr_loc.ptr + self.offset_b) as i32, + a_len - self.offset_b as i32, + (self.sa_ptr_loc.ptr + self.offset_c) as i32, + a_len - self.offset_c as i32, + self.return_ptr_loc.ptr as i32, + ); + assert_eq!(res, types::Errno::Ok.into(), "multi string errno"); + + let given = host_memory + .ptr::(self.return_ptr_loc.ptr) + .read() + .expect("deref ptr to return value"); + assert_eq!( + ((3 * a_len) - (self.offset_b as i32 + self.offset_c as i32)) as u32, + given + ); + } +} + +proptest! { + #[test] + fn overlapping_string(e in OverlappingStringExercise::strat()) { + e.test() + } +}