wlan_common/test_utils/
mod.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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
15/// A trait which allows to expect a future to terminate within a given time or panic otherwise.
16pub 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 to assert a value matches a variant.
63/// This macro is particularly useful when partially matching a variant.
64///
65/// Example:
66/// ```
67/// // Basic matching:
68/// let foo = Foo::B(42);
69/// assert_variant!(foo, Foo::B(_)); // Success
70/// assert_variant!(foo, Foo::A); // Panics: "unexpected variant: B(42)"
71///
72/// // Multiple variants matching:
73/// let foo = Foo::B(42);
74/// assert_variant!(foo, Foo::A | Foo::B(_)); // Success
75/// assert_variant!(foo, Foo::A | Foo::C); // Panics: "unexpected variant: B(42)"
76///
77/// // Advanced matching:
78/// let foo: Result<Option<u8>, u8> = Result::Ok(Some(5));
79/// assert_variant!(foo, Result::Ok(Some(1...5))); // Success
80/// assert_variant!(foo, Result::Ok(Some(1...4))); // Panics: "unexpected variant: Ok(Some(5))"
81///
82/// // Custom message
83/// let foo = Foo::B(42);
84/// // Panics: "expected Foo::A, actual: B(42)"
85/// assert_variant!(foo, Foo::A, "expected Foo::A, actual: {:?}", foo);
86///
87/// // Optional expression:
88/// let foo = Foo::B(...);
89/// assert_variant!(foo, Foo::B(v) => {
90///     assert_eq!(v.id, 5);
91///     ...
92/// });
93///
94/// // Unwrapping partially matched variant:
95/// let foo = Foo::B(...);
96/// let bar = assert_variant!(foo, Foo::B(bar) => bar);
97/// let xyz = bar.foo_bar(...);
98/// assert_eq!(xyz, ...);
99/// ```
100#[macro_export]
101macro_rules! assert_variant {
102    // Use custom formatting when panicking.
103    ($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    // Use default message when panicking.
110    ($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    // Custom error message.
117    ($test:expr, $variant:pat_param $( | $others:pat)* , $fmt:expr $(, $args:tt)* $(,)?) => {
118        $crate::assert_variant!($test, $variant $( | $others)* => {}, $fmt $(, $args)*)
119    };
120    // Default error message.
121    ($test:expr, $variant:pat_param $( | $others:pat)* $(,)?) => {
122        $crate::assert_variant!($test, $variant $( | $others)* => {})
123    };
124}
125
126/// Asserts the value at a particular index of an expression
127/// evaluating to a type implementing the Index trait. This macro
128/// is effectively a thin wrapper around `assert_variant` that will
129/// pretty-print the entire indexable value if the assertion fails.
130///
131/// This macro is particularly useful when failure to assert a single
132/// value in a Vec requires more context to debug the failure.
133///
134/// # Examples
135///
136/// ```
137/// let v = vec![0, 2];
138/// // Success
139/// assert_variant_at_idx!(v, 0, 0);
140/// // Panics: "unexpected variant at 0 in v:
141/// // [
142/// //   0,
143/// //   2,
144/// // ]"
145/// assert_variant_at_idx!(v, 0, 2);
146/// ```
147#[macro_export]
148macro_rules! assert_variant_at_idx {
149    // Use custom formatting when panicking.
150    ($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    // Use default message when panicking.
154    ($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    // Custom error message.
160    ($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    // Default error message.
164    ($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            // We never read this field, but it is used in tests to ensure we can extract `named`
179            // when there is another field in the struct next to it.
180            #[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    // TODO(https://fxbug.dev/42169733): LeakSanitizer flags leaks caused by panic.
199    #[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    // TODO(https://fxbug.dev/42169733): LeakSanitizer flags leaks caused by panic.
207    #[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    // TODO(https://fxbug.dev/42169733): LeakSanitizer flags leaks caused by panic.
221    #[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    // TODO(https://fxbug.dev/42169733): LeakSanitizer flags leaks caused by panic.
236    #[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    // TODO(https://fxbug.dev/42169733): LeakSanitizer flags leaks caused by panic.
267    #[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    // TODO(https://fxbug.dev/42169733): LeakSanitizer flags leaks caused by panic.
275    #[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    // TODO(https://fxbug.dev/42169733): LeakSanitizer flags leaks caused by panic.
295    #[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    // TODO(https://fxbug.dev/42169733): LeakSanitizer flags leaks caused by panic.
310    #[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    // TODO(https://fxbug.dev/42169733): LeakSanitizer flags leaks caused by panic.
319    #[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}