macro_rules! impl_event_properties {
($type:ty) => {
impl EventProperties for $type {
fn sender(&self) -> UniqueName<'_> {
self.item.name.as_ref()
}
fn path(&self) -> ObjectPath<'_> {
self.item.path.as_ref()
}
}
};
}
macro_rules! impl_from_interface_event_enum_for_event {
($outer_type:ty, $outer_variant:path) => {
impl From<$outer_type> for Event {
fn from(event_variant: $outer_type) -> Event {
$outer_variant(event_variant.into())
}
}
};
}
macro_rules! impl_try_from_event_for_user_facing_event_type {
($outer_type:ty, $outer_variant:path) => {
impl TryFrom<Event> for $outer_type {
type Error = AtspiError;
fn try_from(generic_event: Event) -> Result<$outer_type, Self::Error> {
if let $outer_variant(event_type) = generic_event {
Ok(event_type)
} else {
Err(AtspiError::Conversion("Invalid type"))
}
}
}
};
}
macro_rules! impl_from_user_facing_event_for_interface_event_enum {
($inner_type:ty, $outer_type:ty, $inner_variant:path) => {
impl From<$inner_type> for $outer_type {
fn from(specific_event: $inner_type) -> $outer_type {
$inner_variant(specific_event)
}
}
};
}
macro_rules! impl_from_user_facing_type_for_event_enum {
($inner_type:ty, $outer_variant:path) => {
impl From<$inner_type> for Event {
fn from(event_variant: $inner_type) -> Event {
$outer_variant(event_variant.into())
}
}
};
}
macro_rules! impl_try_from_event_for_user_facing_type {
($inner_type:ty, $inner_variant:path, $outer_variant:path) => {
impl TryFrom<Event> for $inner_type {
type Error = AtspiError;
fn try_from(generic_event: Event) -> Result<$inner_type, Self::Error> {
if let $outer_variant($inner_variant(specific_event)) = generic_event {
Ok(specific_event)
} else {
Err(AtspiError::Conversion("Invalid type"))
}
}
}
};
}
macro_rules! impl_to_dbus_message {
($type:ty) => {
#[cfg(feature = "zbus")]
impl TryFrom<$type> for zbus::Message {
type Error = AtspiError;
fn try_from(event: $type) -> Result<Self, Self::Error> {
Ok(zbus::Message::signal(
event.path(),
<$type as BusProperties>::DBUS_INTERFACE,
<$type as BusProperties>::DBUS_MEMBER,
)?
.sender(event.sender().to_string())?
.build(&event.body())?)
}
}
};
}
macro_rules! impl_from_dbus_message {
($type:ty) => {
#[cfg(feature = "zbus")]
impl TryFrom<&zbus::Message> for $type {
type Error = AtspiError;
fn try_from(msg: &zbus::Message) -> Result<Self, Self::Error> {
let header = msg.header();
if header.interface().ok_or(AtspiError::MissingInterface)?
!= <$type as BusProperties>::DBUS_INTERFACE
{
return Err(AtspiError::InterfaceMatch(format!(
"The interface {} does not match the signal's interface: {}",
header.interface().unwrap(),
<$type as BusProperties>::DBUS_INTERFACE
)));
}
if header.member().ok_or(AtspiError::MissingMember)? != <$type>::DBUS_MEMBER {
return Err(AtspiError::MemberMatch(format!(
"The member {} does not match the signal's member: {}",
header.member().unwrap(),
<$type as BusProperties>::DBUS_MEMBER
)));
}
<$type>::from_message_parts(
msg.try_into()?,
msg.body().deserialize::<<$type as BusProperties>::Body>()?,
)
}
}
};
}
#[cfg(test)]
macro_rules! generic_event_test_case {
($type:ty) => {
#[test]
fn generic_event_uses() {
let struct_event = <$type>::default();
assert_eq!(struct_event.path().as_str(), "/org/a11y/atspi/accessible/null");
assert_eq!(struct_event.sender().as_str(), ":0.0");
let item = struct_event.item.clone();
let body = struct_event.body();
let build_struct = <$type>::from_message_parts(item, body)
.expect("<$type as Default>'s parts should build a valid ObjectRef");
assert_eq!(struct_event, build_struct);
}
};
}
#[cfg(test)]
macro_rules! event_enum_test_case {
($type:ty) => {
#[test]
fn event_enum_conversion() {
let struct_event = <$type>::default();
let event = Event::from(struct_event.clone());
let struct_event_back = <$type>::try_from(event)
.expect("Should convert event enum into specific event type because it was created from it. Check the `impl_from_interface_event_enum_for_event` macro");
assert_eq!(struct_event, struct_event_back);
}
};
}
#[cfg(test)]
macro_rules! event_enum_transparency_test_case {
($type:ty) => {
#[test]
fn event_enum_transparency_test_case() {
let specific_event = <$type>::default();
let generic_event = Event::from(specific_event.clone());
assert_eq!(
specific_event.member(),
generic_event.member(),
"DBus member strings do not match."
);
assert_eq!(
specific_event.interface(),
generic_event.interface(),
"Registry interfaces do not match."
);
assert_eq!(
specific_event.registry_string(),
generic_event.registry_string(),
"Registry strings do not match."
);
assert_eq!(
specific_event.match_rule(),
generic_event.match_rule(),
"Match rule strings do not match."
);
assert_eq!(specific_event.path(), generic_event.path(), "Pathsdo not match.");
assert_eq!(specific_event.sender(), generic_event.sender(), "Senders do not match.");
}
};
}
#[cfg(test)]
macro_rules! zbus_message_test_case {
($type:ty) => {
#[cfg(feature = "zbus")]
#[test]
fn zbus_msg_conversion_to_specific_event_type() {
let struct_event = <$type>::default();
let msg: zbus::Message = zbus::Message::try_from(struct_event.clone())
.expect("Should convert a `$type::default()` into a message. Check the `impl_to_dbus_message` macro .");
let struct_event_back =
<$type>::try_from(&msg).expect("Should convert from `$type::default()` originated `Message` back into a specific event type. Check the `impl_from_dbus_message` macro.");
assert_eq!(struct_event, struct_event_back);
}
#[cfg(feature = "zbus")]
#[test]
fn zbus_msg_conversion_to_event_enum_type() {
let struct_event = <$type>::default();
let msg: zbus::Message = zbus::Message::try_from(struct_event.clone()).expect("Should convert a `$type::default()` into a message. Check the `impl_to_dbus_message` macro .");
let event_enum_back =
Event::try_from(&msg).expect("Should convert a from `$type::default()` built `Message` into an event enum. Check the `impl_from_dbus_message` macro .");
let event_enum: Event = struct_event.into();
assert_eq!(event_enum, event_enum_back);
}
#[cfg(feature = "zbus")]
#[test]
#[should_panic(expected = "Should panic")]
fn zbus_msg_conversion_failure_fake_msg() -> () {
let fake_msg = zbus::Message::signal(
"/org/a11y/sixtynine/fourtwenty",
"org.a11y.atspi.technically.valid",
"MadeUpMember",
)
.unwrap()
.sender(":0.0")
.unwrap()
.build(&())
.unwrap();
let event = <$type>::try_from(&fake_msg);
event.expect("Should panic");
}
#[cfg(feature = "zbus")]
#[test]
#[should_panic(expected = "Should panic")]
fn zbus_msg_conversion_failure_correct_interface() -> () {
let fake_msg = zbus::Message::signal(
"/org/a11y/sixtynine/fourtwenty",
<$type as BusProperties>::DBUS_INTERFACE,
"MadeUpMember",
)
.unwrap()
.sender(":0.0")
.unwrap()
.build(&())
.unwrap();
let event = <$type>::try_from(&fake_msg);
event.expect("Should panic");
}
#[cfg(feature = "zbus")]
#[test]
#[should_panic(expected = "Should panic")]
fn zbus_msg_conversion_failure_correct_interface_and_member() -> () {
let fake_msg = zbus::Message::signal(
"/org/a11y/sixtynine/fourtwenty",
<$type as BusProperties>::DBUS_INTERFACE,
<$type as BusProperties>::DBUS_MEMBER,
)
.unwrap()
.sender(":0.0")
.unwrap()
.build(&())
.unwrap();
let event = <$type>::try_from(&fake_msg);
event.expect("Should panic");
}
#[cfg(feature = "zbus")]
#[test]
#[should_panic(expected = "Should panic")]
fn zbus_msg_conversion_failure_correct_body() -> () {
let fake_msg = zbus::Message::signal(
"/org/a11y/sixtynine/fourtwenty",
"org.a11y.atspi.accessible.technically.valid",
"FakeMember",
)
.unwrap()
.sender(":0.0")
.unwrap()
.build(&<$type>::default().body())
.unwrap();
let event = <$type>::try_from(&fake_msg);
event.expect("Should panic");
}
#[cfg(feature = "zbus")]
#[test]
#[should_panic(expected = "Should panic")]
fn zbus_msg_conversion_failure_correct_body_and_member() -> () {
let fake_msg = zbus::Message::signal(
"/org/a11y/sixtynine/fourtwenty",
"org.a11y.atspi.accessible.technically.valid",
<$type as BusProperties>::DBUS_MEMBER,
)
.unwrap()
.sender(":0.0")
.unwrap()
.build(&<$type>::default().body())
.unwrap();
let event = <$type>::try_from(&fake_msg);
event.expect("Should panic");
}
};
}
macro_rules! event_wrapper_test_cases {
($type:ty, $any_subtype:ty) => {
#[cfg(test)]
#[rename_item::rename(name($type), prefix = "events_tests_", case = "snake")]
mod foo {
use super::{$any_subtype, $type, Event, BusProperties};
#[test]
fn into_and_try_from_event() {
let sub_type = <$any_subtype>::default();
let mod_type = <$type>::from(sub_type);
let event = Event::from(mod_type.clone());
let mod_type2 = <$type>::try_from(event.clone())
.expect("Should convert outer `Event` enum into interface enum because it was created from it. Check the `impl_try_from_event_for_user_facing_event_type` macro");
assert_eq!(
mod_type, mod_type2,
"Events were able to be parsed and encapsulated, but they have changed value"
);
}
#[cfg(feature = "zbus")]
#[test]
#[should_panic(expected = "Should panic")]
fn zbus_msg_invalid_interface() {
let fake_msg = zbus::Message::signal(
"/org/a11y/sixtynine/fourtwenty",
"org.a11y.atspi.technically.valid.lol",
<$any_subtype as BusProperties>::DBUS_MEMBER,
)
.unwrap()
.sender(":0.0")
.unwrap()
.build(&<$any_subtype>::default().body())
.unwrap();
let mod_type = <$type>::try_from(&fake_msg);
mod_type.expect("Should panic");
}
#[cfg(feature = "zbus")]
#[test]
#[should_panic(expected = "Should panic")]
fn zbus_msg_invalid_member() {
let fake_msg = zbus::Message::signal(
"/org/a11y/sixtynine/fourtwenty",
<$any_subtype as BusProperties>::DBUS_INTERFACE,
"FakeFunctionLol",
)
.unwrap()
.sender(":0.0")
.unwrap()
.build(&<$any_subtype>::default().body())
.unwrap();
let mod_type = <$type>::try_from(&fake_msg);
mod_type.expect("Should panic");
}
#[cfg(feature = "zbus")]
#[test]
#[should_panic(expected = "Should panic")]
fn zbus_msg_invalid_member_and_interface() {
let fake_msg = zbus::Message::signal(
"/org/a11y/sixtynine/fourtwenty",
"org.a11y.atspi.technically.allowed",
"FakeFunctionLol",
)
.unwrap()
.sender(":0.0")
.unwrap()
.build(&<$any_subtype>::default().body())
.unwrap();
let mod_type = <$type>::try_from(&fake_msg);
mod_type.expect("Should panic");
}
#[cfg(feature = "zbus")]
#[test]
fn zbus_msg_conversion() {
let valid_msg = zbus::Message::signal(
"/org/a11y/sixtynine/fourtwenty",
<$any_subtype as BusProperties>::DBUS_INTERFACE,
<$any_subtype as BusProperties>::DBUS_MEMBER,
)
.unwrap()
.sender(":0.0")
.unwrap()
.build(&<$any_subtype>::default().body())
.unwrap();
let mod_type = <$type>::try_from(&valid_msg);
mod_type.expect("Should convert from `$any_subtype::default()` built `Message` back into a interface event enum variant wrapping an inner type. Check the `impl_from_dbus_message` macro.");
}
}
};
}
macro_rules! event_test_cases {
($type:ty) => {
#[cfg(test)]
#[rename_item::rename(name($type), prefix = "event_tests_", case = "snake")]
mod foo {
use super::{$type, Event, BusProperties, EventProperties, EventTypeProperties};
generic_event_test_case!($type);
event_enum_test_case!($type);
zbus_message_test_case!($type);
event_enum_transparency_test_case!($type);
}
assert_impl_all!(
$type: Clone,
std::fmt::Debug,
serde::Serialize,
serde::Deserialize<'static>,
Default,
PartialEq,
Eq,
std::hash::Hash,
crate::EventProperties,
crate::EventTypeProperties,
crate::BusProperties,
);
#[cfg(feature = "zbus")]
assert_impl_all!(zbus::Message: TryFrom<$type>);
};
}