use crate::append::{Append, BufferTooSmall, TrackedAppend, VecCursor};
use fuchsia_async::{DurationExt, OnTimeout, TimeoutExt};
use futures::Future;
pub mod fake_capabilities;
pub mod fake_features;
pub mod fake_frames;
pub mod fake_stas;
pub trait ExpectWithin: Future + Sized {
fn expect_within<S: ToString + Clone>(
self,
duration: zx::MonotonicDuration,
msg: S,
) -> OnTimeout<Self, Box<dyn FnOnce() -> Self::Output>> {
let msg = msg.to_string();
self.on_timeout(duration.after_now(), Box::new(move || panic!("{}", msg)))
}
}
impl<F: Future + Sized> ExpectWithin for F {}
pub struct FixedSizedTestBuffer(VecCursor);
impl FixedSizedTestBuffer {
pub fn new(capacity: usize) -> Self {
Self(VecCursor::with_capacity(capacity))
}
}
impl Append for FixedSizedTestBuffer {
fn append_bytes(&mut self, bytes: &[u8]) -> Result<(), BufferTooSmall> {
if !self.can_append(bytes.len()) {
return Err(BufferTooSmall);
}
self.0.append_bytes(bytes)
}
fn append_bytes_zeroed(&mut self, len: usize) -> Result<&mut [u8], BufferTooSmall> {
if !self.can_append(len) {
return Err(BufferTooSmall);
}
self.0.append_bytes_zeroed(len)
}
fn can_append(&self, bytes: usize) -> bool {
self.0.len() + bytes <= self.0.capacity()
}
}
impl TrackedAppend for FixedSizedTestBuffer {
fn bytes_appended(&self) -> usize {
self.0.bytes_appended()
}
}
#[macro_export]
macro_rules! assert_variant {
($test:expr, $variant:pat_param $( | $others:pat)* => $e:expr, $fmt:expr $(, $args:tt)* $(,)?) => {
match $test {
$variant $(| $others)* => $e,
_ => panic!($fmt, $($args,)*),
}
};
($test:expr, $variant:pat_param $( | $others:pat)* => $e:expr $(,)?) => {
match $test {
$variant $(| $others)* => $e,
other => panic!("unexpected variant: {:?}", other),
}
};
($test:expr, $variant:pat_param $( | $others:pat)* , $fmt:expr $(, $args:tt)* $(,)?) => {
$crate::assert_variant!($test, $variant $( | $others)* => {}, $fmt $(, $args)*)
};
($test:expr, $variant:pat_param $( | $others:pat)* $(,)?) => {
$crate::assert_variant!($test, $variant $( | $others)* => {})
};
}
#[macro_export]
macro_rules! assert_variant_at_idx {
($indexable:expr, $idx:expr, $variant:pat_param $( | $others:pat)* => $e:expr, $fmt:expr $(, $args:tt)* $(,)?) => {
$crate::assert_variant!(&$indexable[$idx], $variant $( | $others)* => { $e }, $fmt $(, $args)*)
};
($indexable:expr, $idx:expr, $variant:pat_param $( | $others:pat)* => $e:expr $(,)?) => {{
let indexable_name = stringify!($indexable);
$crate::assert_variant_at_idx!($indexable, $idx, $variant $( | $others)* => { $e },
"unexpected variant at {:?} in {}:\n{:#?}", $idx, indexable_name, $indexable)
}};
($indexable:expr, $idx:expr, $variant:pat_param $( | $others:pat)*, $fmt:expr $(, $args:tt)* $(,)?) => {
$crate::assert_variant_at_idx!($indexable, $idx, $variant $( | $others)* => {}, $fmt $(, $args)*)
};
($indexable:expr, $idx:expr, $variant:pat_param $( | $others:pat)* $(,)?) => {
$crate::assert_variant_at_idx!($indexable, $idx, $variant $( | $others)* => {})
};
}
#[cfg(test)]
mod tests {
use std::panic;
#[derive(Debug)]
enum Foo {
A(u8),
B {
named: u8,
#[allow(unused)]
bar: u16,
},
C,
}
#[test]
fn assert_variant_full_match_success() {
assert_variant!(Foo::A(8), Foo::A(8));
}
#[test]
fn assert_variant_no_expr_value() {
assert_variant!(0, 0);
}
#[test]
#[should_panic(expected = "unexpected variant")]
#[cfg_attr(feature = "variant_asan", ignore)]
fn assert_variant_full_match_fail_with_same_variant_different_value() {
assert_variant!(Foo::A(8), Foo::A(7));
}
#[test]
#[should_panic(expected = "unexpected variant")]
#[cfg_attr(feature = "variant_asan", ignore)]
fn assert_variant_full_match_fail_with_different_variant() {
assert_variant!(Foo::A(8), Foo::C);
}
#[test]
fn assert_variant_multi_variant_success() {
assert_variant!(Foo::A(8), Foo::A(8) | Foo::C);
assert_variant!(Foo::C, Foo::A(8) | Foo::C);
}
#[test]
#[should_panic(expected = "unexpected variant")]
#[cfg_attr(feature = "variant_asan", ignore)]
fn assert_variant_multi_variant_failure() {
assert_variant!(Foo::C, Foo::A(_) | Foo::B { .. });
}
#[test]
fn assert_variant_partial_match_success() {
assert_variant!(Foo::A(8), Foo::A(_));
assert_variant!(Foo::B { named: 7, bar: 8 }, Foo::B { .. });
assert_variant!(Foo::B { named: 7, bar: 8 }, Foo::B { named: 7, .. });
}
#[test]
#[should_panic(expected = "unexpected variant")]
#[cfg_attr(feature = "variant_asan", ignore)]
fn assert_variant_partial_match_failure() {
assert_variant!(Foo::A(8), Foo::B { .. });
}
#[test]
fn assert_variant_expr() {
assert_variant!(Foo::A(8), Foo::A(value) => {
assert_eq!(value, 8);
});
assert_variant!(Foo::B { named: 7, bar: 8 }, Foo::B { named, .. } => {
assert_eq!(named, 7);
});
let named = assert_variant!(Foo::B { named: 7, bar: 8 }, Foo::B { named, .. } => named);
assert_eq!(named, 7);
let named = assert_variant!(Foo::B { named: 7, bar: 8 }, Foo::B { named, .. } => named, "custom error message");
assert_eq!(named, 7);
assert_variant!(Foo::B { named: 7, bar: 8 }, Foo::B { .. } => (), "custom error message");
}
#[test]
fn assert_variant_custom_message_success() {
assert_variant!(Foo::A(8), Foo::A(_), "custom error message");
}
#[test]
#[should_panic(expected = "custom error message")]
#[cfg_attr(feature = "variant_asan", ignore)]
fn assert_variant_custom_message_failure() {
assert_variant!(Foo::A(8), Foo::B { .. }, "custom error message");
}
#[test]
#[should_panic(expected = "custom error message token1 token2")]
#[cfg_attr(feature = "variant_asan", ignore)]
fn assert_variant_custom_message_with_multiple_fmt_tokens_failure() {
assert_variant!(Foo::A(8), Foo::B { .. }, "custom error message {} {}", "token1", "token2");
}
#[test]
fn assert_variant_at_idx_success() {
let v = vec![0, 2];
assert_variant_at_idx!(v, 0, 0);
}
#[test]
fn assert_variant_at_idx_no_expr_value() {
let v = vec![0, 2];
assert_variant_at_idx!(v, 0, 0);
}
#[test]
#[should_panic(expected = "unexpected variant at 0 in v:\n[\n 0,\n 2,\n]")]
#[cfg_attr(feature = "variant_asan", ignore)]
fn assert_variant_at_idx_failure() {
let v = vec![0, 2];
assert_variant_at_idx!(v, 0, 2);
}
#[test]
fn assert_variant_at_idx_custom_message_success() {
let v = vec![0, 2];
assert_variant_at_idx!(v, 0, 0, "custom error message");
}
#[test]
#[should_panic(expected = "custom error message")]
#[cfg_attr(feature = "variant_asan", ignore)]
fn assert_variant_at_idx_custom_message_failure() {
let v = vec![0, 2];
assert_variant_at_idx!(v, 0, 2, "custom error message");
}
#[test]
#[should_panic(expected = "custom error message token1 token2")]
#[cfg_attr(feature = "variant_asan", ignore)]
fn assert_variant_at_idx_custom_message_with_multiple_tokens_failure() {
let v = vec![0, 2];
assert_variant_at_idx!(v, 0, 2, "custom error message {} {}", "token1", "token2");
}
#[test]
fn assert_variant_at_idx_expr() {
let v = vec![0, 2];
assert_variant_at_idx!(v, 0, 0 => {
assert_eq!(1, 1);
});
let named = assert_variant_at_idx!(v, 0, 0 => 1);
assert_eq!(named, 1);
let named = assert_variant_at_idx!(v, 0, 0 => 1, "custom error message");
assert_eq!(named, 1);
assert_variant_at_idx!(v, 0, 0 => (), "custom error message");
}
}