Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/wiggle/tests/variant.rs
1692 views
1
use proptest::prelude::*;
2
use wiggle::{GuestMemory, GuestPtr, GuestType};
3
use wiggle_test::{HostMemory, MemArea, WasiCtx, impl_errno};
4
5
wiggle::from_witx!({
6
witx: ["tests/variant.witx"],
7
});
8
9
impl_errno!(types::Errno);
10
11
// Avoid panics on overflow
12
fn mult_lose_overflow(a: i32, b: u32) -> i32 {
13
let a_64: i64 = a as i64;
14
let b_64: i64 = b as i64;
15
let product = a_64 * b_64;
16
product as i32
17
}
18
19
// Avoid assert_eq(NaN, NaN) failures
20
fn mult_zero_nan(a: f32, b: u32) -> f32 {
21
if a.is_nan() {
22
0.0
23
} else {
24
let product = a * b as f32;
25
if product.is_nan() { 0.0 } else { product }
26
}
27
}
28
29
impl<'a> variant_example::VariantExample for WasiCtx<'a> {
30
fn get_tag(
31
&mut self,
32
_memory: &mut GuestMemory<'_>,
33
u: &types::Reason,
34
) -> Result<types::Excuse, types::Errno> {
35
println!("GET TAG: {u:?}");
36
match u {
37
types::Reason::DogAte { .. } => Ok(types::Excuse::DogAte),
38
types::Reason::Traffic { .. } => Ok(types::Excuse::Traffic),
39
types::Reason::Sleeping { .. } => Ok(types::Excuse::Sleeping),
40
}
41
}
42
fn reason_mult(
43
&mut self,
44
memory: &mut GuestMemory<'_>,
45
u: &types::ReasonMut,
46
multiply_by: u32,
47
) -> Result<(), types::Errno> {
48
match u {
49
types::ReasonMut::DogAte(fptr) => {
50
let val = memory.read(*fptr).expect("valid pointer");
51
println!("REASON MULT DogAte({val})");
52
memory
53
.write(*fptr, mult_zero_nan(val, multiply_by))
54
.expect("valid pointer");
55
}
56
types::ReasonMut::Traffic(iptr) => {
57
let val = memory.read(*iptr).expect("valid pointer");
58
println!("REASON MULT Traffic({val})");
59
memory
60
.write(*iptr, mult_lose_overflow(val, multiply_by))
61
.expect("valid pointer");
62
}
63
types::ReasonMut::Sleeping => {
64
println!("REASON MULT Sleeping");
65
}
66
}
67
Ok(())
68
}
69
}
70
71
fn reason_strat() -> impl Strategy<Value = types::Reason> {
72
prop_oneof![
73
prop::num::f32::ANY.prop_map(|v| types::Reason::DogAte(v)),
74
prop::num::i32::ANY.prop_map(|v| types::Reason::Traffic(v)),
75
Just(types::Reason::Sleeping),
76
]
77
.boxed()
78
}
79
80
fn reason_tag(r: &types::Reason) -> types::Excuse {
81
match r {
82
types::Reason::DogAte { .. } => types::Excuse::DogAte,
83
types::Reason::Traffic { .. } => types::Excuse::Traffic,
84
types::Reason::Sleeping { .. } => types::Excuse::Sleeping,
85
}
86
}
87
88
#[derive(Debug)]
89
struct GetTagExercise {
90
pub input: types::Reason,
91
pub input_loc: MemArea,
92
pub return_loc: MemArea,
93
}
94
95
impl GetTagExercise {
96
pub fn strat() -> BoxedStrategy<Self> {
97
(
98
reason_strat(),
99
HostMemory::mem_area_strat(types::Reason::guest_size()),
100
HostMemory::mem_area_strat(types::Excuse::guest_size()),
101
)
102
.prop_map(|(input, input_loc, return_loc)| GetTagExercise {
103
input,
104
input_loc,
105
return_loc,
106
})
107
.prop_filter("non-overlapping pointers", |e| {
108
MemArea::non_overlapping_set(&[e.input_loc, e.return_loc])
109
})
110
.boxed()
111
}
112
113
pub fn test(&self) {
114
let mut ctx = WasiCtx::new();
115
let mut host_memory = HostMemory::new();
116
let mut memory = host_memory.guest_memory();
117
118
let discriminant = reason_tag(&self.input) as u8;
119
memory
120
.write(GuestPtr::new(self.input_loc.ptr), discriminant)
121
.expect("input discriminant ptr");
122
match self.input {
123
types::Reason::DogAte(f) => {
124
memory
125
.write(GuestPtr::new(self.input_loc.ptr + 4), f)
126
.expect("input contents ref_mut");
127
}
128
types::Reason::Traffic(v) => memory
129
.write(GuestPtr::new(self.input_loc.ptr + 4), v)
130
.expect("input contents ref_mut"),
131
types::Reason::Sleeping => {} // Do nothing
132
}
133
let e = variant_example::get_tag(
134
&mut ctx,
135
&mut memory,
136
self.input_loc.ptr as i32,
137
self.return_loc.ptr as i32,
138
)
139
.unwrap();
140
141
assert_eq!(e, types::Errno::Ok as i32, "get_tag errno");
142
143
let return_val: types::Excuse = memory
144
.read(GuestPtr::new(self.return_loc.ptr))
145
.expect("return ref");
146
147
assert_eq!(return_val, reason_tag(&self.input), "get_tag return value");
148
}
149
}
150
151
proptest! {
152
#[test]
153
fn get_tag(e in GetTagExercise::strat()) {
154
e.test();
155
}
156
}
157
158
#[derive(Debug)]
159
struct ReasonMultExercise {
160
pub input: types::Reason,
161
pub input_loc: MemArea,
162
pub input_pointee_loc: MemArea,
163
pub multiply_by: u32,
164
}
165
166
impl ReasonMultExercise {
167
pub fn strat() -> BoxedStrategy<Self> {
168
(
169
reason_strat(),
170
HostMemory::mem_area_strat(types::Reason::guest_size()),
171
HostMemory::mem_area_strat(4),
172
prop::num::u32::ANY,
173
)
174
.prop_map(
175
|(input, input_loc, input_pointee_loc, multiply_by)| ReasonMultExercise {
176
input,
177
input_loc,
178
input_pointee_loc,
179
multiply_by,
180
},
181
)
182
.prop_filter("non-overlapping pointers", |e| {
183
MemArea::non_overlapping_set(&[e.input_loc, e.input_pointee_loc])
184
})
185
.boxed()
186
}
187
188
pub fn test(&self) {
189
let mut ctx = WasiCtx::new();
190
let mut host_memory = HostMemory::new();
191
let mut memory = host_memory.guest_memory();
192
193
let discriminant = reason_tag(&self.input) as u8;
194
memory
195
.write(GuestPtr::new(self.input_loc.ptr), discriminant)
196
.expect("input discriminant ref_mut");
197
memory
198
.write(
199
GuestPtr::new(self.input_loc.ptr + 4),
200
self.input_pointee_loc.ptr,
201
)
202
.expect("input pointer ref_mut");
203
204
match self.input {
205
types::Reason::DogAte(f) => {
206
memory
207
.write(GuestPtr::new(self.input_pointee_loc.ptr), f)
208
.expect("input contents ref_mut");
209
}
210
types::Reason::Traffic(v) => {
211
memory
212
.write(GuestPtr::new(self.input_pointee_loc.ptr), v)
213
.expect("input contents ref_mut");
214
}
215
types::Reason::Sleeping => {} // Do nothing
216
}
217
let e = variant_example::reason_mult(
218
&mut ctx,
219
&mut memory,
220
self.input_loc.ptr as i32,
221
self.multiply_by as i32,
222
)
223
.unwrap();
224
225
assert_eq!(e, types::Errno::Ok as i32, "reason_mult errno");
226
227
match self.input {
228
types::Reason::DogAte(f) => {
229
let f_result: f32 = memory
230
.read(GuestPtr::new(self.input_pointee_loc.ptr))
231
.expect("input contents ref_mut");
232
assert_eq!(
233
mult_zero_nan(f, self.multiply_by),
234
f_result,
235
"DogAte result"
236
)
237
}
238
types::Reason::Traffic(v) => {
239
let v_result: i32 = memory
240
.read(GuestPtr::new(self.input_pointee_loc.ptr))
241
.expect("input contents ref_mut");
242
assert_eq!(
243
mult_lose_overflow(v, self.multiply_by),
244
v_result,
245
"Traffic result"
246
)
247
}
248
types::Reason::Sleeping => {} // Do nothing
249
}
250
}
251
}
252
253
proptest! {
254
#[test]
255
fn reason_mult(e in ReasonMultExercise::strat()) {
256
e.test();
257
}
258
}
259
260