1use crate::append::{Append, BufferTooSmall, TrackedAppend, VecCursor};
6use fuchsia_async::{DurationExt, OnTimeout, TimeoutExt};
7
8use futures::Future;
9
10pub mod fake_capabilities;
11pub mod fake_features;
12pub mod fake_frames;
13pub mod fake_stas;
14
15pub trait ExpectWithin: Future + Sized {
17 fn expect_within<S: ToString + Clone>(
18 self,
19 duration: zx::MonotonicDuration,
20 msg: S,
21 ) -> OnTimeout<Self, Box<dyn FnOnce() -> Self::Output>> {
22 let msg = msg.to_string();
23 self.on_timeout(duration.after_now(), Box::new(move || panic!("{}", msg)))
24 }
25}
26
27impl<F: Future + Sized> ExpectWithin for F {}
28
29pub struct FixedSizedTestBuffer(VecCursor);
30impl FixedSizedTestBuffer {
31 pub fn new(capacity: usize) -> Self {
32 Self(VecCursor::with_capacity(capacity))
33 }
34}
35
36impl Append for FixedSizedTestBuffer {
37 fn append_bytes(&mut self, bytes: &[u8]) -> Result<(), BufferTooSmall> {
38 if !self.can_append(bytes.len()) {
39 return Err(BufferTooSmall);
40 }
41 self.0.append_bytes(bytes)
42 }
43
44 fn append_bytes_zeroed(&mut self, len: usize) -> Result<&mut [u8], BufferTooSmall> {
45 if !self.can_append(len) {
46 return Err(BufferTooSmall);
47 }
48 self.0.append_bytes_zeroed(len)
49 }
50
51 fn can_append(&self, bytes: usize) -> bool {
52 self.0.len() + bytes <= self.0.capacity()
53 }
54}
55
56impl TrackedAppend for FixedSizedTestBuffer {
57 fn bytes_appended(&self) -> usize {
58 self.0.bytes_appended()
59 }
60}
61
62#[macro_export]
101macro_rules! assert_variant {
102 ($test:expr, $variant:pat_param $( | $others:pat)* => $e:expr, $fmt:expr $(, $args:tt)* $(,)?) => {
104 match $test {
105 $variant $(| $others)* => $e,
106 _ => panic!($fmt, $($args,)*),
107 }
108 };
109 ($test:expr, $variant:pat_param $( | $others:pat)* => $e:expr $(,)?) => {
111 match $test {
112 $variant $(| $others)* => $e,
113 other => panic!("unexpected variant: {:?}", other),
114 }
115 };
116 ($test:expr, $variant:pat_param $( | $others:pat)* , $fmt:expr $(, $args:tt)* $(,)?) => {
118 $crate::assert_variant!($test, $variant $( | $others)* => {}, $fmt $(, $args)*)
119 };
120 ($test:expr, $variant:pat_param $( | $others:pat)* $(,)?) => {
122 $crate::assert_variant!($test, $variant $( | $others)* => {})
123 };
124}
125
126#[macro_export]
148macro_rules! assert_variant_at_idx {
149 ($indexable:expr, $idx:expr, $variant:pat_param $( | $others:pat)* => $e:expr, $fmt:expr $(, $args:tt)* $(,)?) => {
151 $crate::assert_variant!(&$indexable[$idx], $variant $( | $others)* => { $e }, $fmt $(, $args)*)
152 };
153 ($indexable:expr, $idx:expr, $variant:pat_param $( | $others:pat)* => $e:expr $(,)?) => {{
155 let indexable_name = stringify!($indexable);
156 $crate::assert_variant_at_idx!($indexable, $idx, $variant $( | $others)* => { $e },
157 "unexpected variant at {:?} in {}:\n{:#?}", $idx, indexable_name, $indexable)
158 }};
159 ($indexable:expr, $idx:expr, $variant:pat_param $( | $others:pat)*, $fmt:expr $(, $args:tt)* $(,)?) => {
161 $crate::assert_variant_at_idx!($indexable, $idx, $variant $( | $others)* => {}, $fmt $(, $args)*)
162 };
163 ($indexable:expr, $idx:expr, $variant:pat_param $( | $others:pat)* $(,)?) => {
165 $crate::assert_variant_at_idx!($indexable, $idx, $variant $( | $others)* => {})
166 };
167}
168
169#[cfg(test)]
170mod tests {
171 use std::panic;
172
173 #[derive(Debug)]
174 enum Foo {
175 A(u8),
176 B {
177 named: u8,
178 #[allow(unused)]
181 bar: u16,
182 },
183 C,
184 }
185
186 #[test]
187 fn assert_variant_full_match_success() {
188 assert_variant!(Foo::A(8), Foo::A(8));
189 }
190
191 #[test]
192 fn assert_variant_no_expr_value() {
193 assert_variant!(0, 0);
194 }
195
196 #[test]
197 #[should_panic(expected = "unexpected variant")]
198 #[cfg_attr(feature = "variant_asan", ignore)]
200 fn assert_variant_full_match_fail_with_same_variant_different_value() {
201 assert_variant!(Foo::A(8), Foo::A(7));
202 }
203
204 #[test]
205 #[should_panic(expected = "unexpected variant")]
206 #[cfg_attr(feature = "variant_asan", ignore)]
208 fn assert_variant_full_match_fail_with_different_variant() {
209 assert_variant!(Foo::A(8), Foo::C);
210 }
211
212 #[test]
213 fn assert_variant_multi_variant_success() {
214 assert_variant!(Foo::A(8), Foo::A(8) | Foo::C);
215 assert_variant!(Foo::C, Foo::A(8) | Foo::C);
216 }
217
218 #[test]
219 #[should_panic(expected = "unexpected variant")]
220 #[cfg_attr(feature = "variant_asan", ignore)]
222 fn assert_variant_multi_variant_failure() {
223 assert_variant!(Foo::C, Foo::A(_) | Foo::B { .. });
224 }
225
226 #[test]
227 fn assert_variant_partial_match_success() {
228 assert_variant!(Foo::A(8), Foo::A(_));
229 assert_variant!(Foo::B { named: 7, bar: 8 }, Foo::B { .. });
230 assert_variant!(Foo::B { named: 7, bar: 8 }, Foo::B { named: 7, .. });
231 }
232
233 #[test]
234 #[should_panic(expected = "unexpected variant")]
235 #[cfg_attr(feature = "variant_asan", ignore)]
237 fn assert_variant_partial_match_failure() {
238 assert_variant!(Foo::A(8), Foo::B { .. });
239 }
240
241 #[test]
242 fn assert_variant_expr() {
243 assert_variant!(Foo::A(8), Foo::A(value) => {
244 assert_eq!(value, 8);
245 });
246 assert_variant!(Foo::B { named: 7, bar: 8 }, Foo::B { named, .. } => {
247 assert_eq!(named, 7);
248 });
249
250 let named = assert_variant!(Foo::B { named: 7, bar: 8 }, Foo::B { named, .. } => named);
251 assert_eq!(named, 7);
252
253 let named = assert_variant!(Foo::B { named: 7, bar: 8 }, Foo::B { named, .. } => named, "custom error message");
254 assert_eq!(named, 7);
255
256 assert_variant!(Foo::B { named: 7, bar: 8 }, Foo::B { .. } => (), "custom error message");
257 }
258
259 #[test]
260 fn assert_variant_custom_message_success() {
261 assert_variant!(Foo::A(8), Foo::A(_), "custom error message");
262 }
263
264 #[test]
265 #[should_panic(expected = "custom error message")]
266 #[cfg_attr(feature = "variant_asan", ignore)]
268 fn assert_variant_custom_message_failure() {
269 assert_variant!(Foo::A(8), Foo::B { .. }, "custom error message");
270 }
271
272 #[test]
273 #[should_panic(expected = "custom error message token1 token2")]
274 #[cfg_attr(feature = "variant_asan", ignore)]
276 fn assert_variant_custom_message_with_multiple_fmt_tokens_failure() {
277 assert_variant!(Foo::A(8), Foo::B { .. }, "custom error message {} {}", "token1", "token2");
278 }
279
280 #[test]
281 fn assert_variant_at_idx_success() {
282 let v = vec![0, 2];
283 assert_variant_at_idx!(v, 0, 0);
284 }
285
286 #[test]
287 fn assert_variant_at_idx_no_expr_value() {
288 let v = vec![0, 2];
289 assert_variant_at_idx!(v, 0, 0);
290 }
291
292 #[test]
293 #[should_panic(expected = "unexpected variant at 0 in v:\n[\n 0,\n 2,\n]")]
294 #[cfg_attr(feature = "variant_asan", ignore)]
296 fn assert_variant_at_idx_failure() {
297 let v = vec![0, 2];
298 assert_variant_at_idx!(v, 0, 2);
299 }
300
301 #[test]
302 fn assert_variant_at_idx_custom_message_success() {
303 let v = vec![0, 2];
304 assert_variant_at_idx!(v, 0, 0, "custom error message");
305 }
306
307 #[test]
308 #[should_panic(expected = "custom error message")]
309 #[cfg_attr(feature = "variant_asan", ignore)]
311 fn assert_variant_at_idx_custom_message_failure() {
312 let v = vec![0, 2];
313 assert_variant_at_idx!(v, 0, 2, "custom error message");
314 }
315
316 #[test]
317 #[should_panic(expected = "custom error message token1 token2")]
318 #[cfg_attr(feature = "variant_asan", ignore)]
320 fn assert_variant_at_idx_custom_message_with_multiple_tokens_failure() {
321 let v = vec![0, 2];
322 assert_variant_at_idx!(v, 0, 2, "custom error message {} {}", "token1", "token2");
323 }
324
325 #[test]
326 fn assert_variant_at_idx_expr() {
327 let v = vec![0, 2];
328 assert_variant_at_idx!(v, 0, 0 => {
329 assert_eq!(1, 1);
330 });
331
332 let named = assert_variant_at_idx!(v, 0, 0 => 1);
333 assert_eq!(named, 1);
334
335 let named = assert_variant_at_idx!(v, 0, 0 => 1, "custom error message");
336 assert_eq!(named, 1);
337
338 assert_variant_at_idx!(v, 0, 0 => (), "custom error message");
339 }
340}