1#[macro_export]
2
3/// Expands to a conversion given the enclosed event type and outer `Event` variant.
4///
5/// eg
6/// ```ignore
7/// impl_from_interface_event_enum_for_event!(ObjectEvents, Event::Object);
8/// ```
9/// expands to:
10///
11/// ```ignore
12/// impl From<ObjectEvents> for Event {
13/// fn from(event_variant: ObjectEvents) -> Event {
14/// Event::Object(event_variant.into())
15/// }
16/// }
17/// ```
18macro_rules! impl_from_interface_event_enum_for_event {
19 ($outer_type:ty, $outer_variant:path) => {
20 impl From<$outer_type> for Event {
21 fn from(event_variant: $outer_type) -> Event {
22 $outer_variant(event_variant.into())
23 }
24 }
25 };
26}
27
28/// Expands to a conversion given the enclosed event enum type and outer `Event` variant.
29///
30/// eg
31/// ```ignore
32/// impl_try_from_event_for_user_facing_event_type!(ObjectEvents, Event::Object);
33/// ```
34/// expands to:
35///
36/// ```ignore
37/// impl TryFrom<Event> for ObjectEvents {
38/// type Error = AtspiError;
39/// fn try_from(generic_event: Event) -> Result<ObjectEvents, Self::Error> {
40/// if let Event::Object(event_type) = generic_event {
41/// Ok(event_type)
42/// } else {
43/// Err(AtspiError::Conversion("Invalid type"))
44/// }
45/// }
46/// }
47/// ```
48macro_rules! impl_try_from_event_for_user_facing_event_type {
49 ($outer_type:ty, $outer_variant:path) => {
50 impl TryFrom<Event> for $outer_type {
51 type Error = AtspiError;
52 fn try_from(generic_event: Event) -> Result<$outer_type, Self::Error> {
53 if let $outer_variant(event_type) = generic_event {
54 Ok(event_type)
55 } else {
56 Err(AtspiError::Conversion("Invalid type"))
57 }
58 }
59 }
60 };
61}
62
63/// Expands to a conversion given the user facing event type and outer `Event::Interface(<InterfaceEnum>)` variant.,
64/// the enum type and outtermost variant.
65///
66/// ```ignore user facing type, enum type, outer variant
67/// impl_from_user_facing_event_for_interface_event_enum!(StateChangedEvent, ObjectEvents, ObjectEvents::StateChanged);
68/// ```
69///
70/// expands to:
71///
72/// ```ignore
73/// impl From<StateChangedEvent> for ObjectEvents {
74/// fn from(specific_event: StateChangedEvent) -> ObjectEvents {
75/// ObjectEvents::StateChanged(specific_event)
76/// }
77/// }
78/// ```
79macro_rules! impl_from_user_facing_event_for_interface_event_enum {
80 ($inner_type:ty, $outer_type:ty, $inner_variant:path) => {
81 impl From<$inner_type> for $outer_type {
82 fn from(specific_event: $inner_type) -> $outer_type {
83 $inner_variant(specific_event)
84 }
85 }
86 };
87}
88
89/// Expands to a conversion given two arguments,
90/// 1. the user facing event type `(inner_type)`
91/// which relies on a conversion to its interface variant enum type variant.
92/// 2. the outer `Event::<Interface(<InterfaceEnum>)>` wrapper.,
93/// the enum type and outtermost variant.
94///
95/// ```ignore user facing type, outer event variant
96/// impl_from_user_facing_type_for_event_enum!(StateChangedEvent, Event::Object);
97/// ```
98///
99/// expands to:
100///
101/// ```ignore
102/// impl From<StateChangedEvent> for Event {
103/// fn from(event_variant: StateChangedEvent) -> Event {
104/// Event::Object(ObjectEvents::StateChanged(event_variant))
105/// }
106/// }
107/// ```
108macro_rules! impl_from_user_facing_type_for_event_enum {
109 ($inner_type:ty, $outer_variant:path) => {
110 impl From<$inner_type> for Event {
111 fn from(event_variant: $inner_type) -> Event {
112 $outer_variant(event_variant.into())
113 }
114 }
115 };
116}
117
118/// Expands to a conversion given two arguments,
119/// 1. the user facing event type `(inner_type)`
120/// 2. the outer `Event::<Interface(<InterfaceEnum>)>` wrapper.
121///
122/// eg
123/// ```ignore
124/// impl_try_from_event_for_user_facing_type!(StateChangedEvent, ObjectEvents::StateChanged);
125/// ```
126/// expands to:
127///
128/// ```ignore
129/// impl TryFrom<Event> for StateChangedEvent {
130/// type Error = AtspiError;
131/// fn try_from(generic_event: Event) -> Result<StateChangedEvent, Self::Error> {
132/// if let Event::Object(ObjectEvents::StateChanged(specific_event)) = generic_event {
133/// Ok(specific_event)
134/// } else {
135/// Err(AtspiError::Conversion("Invalid type"))
136/// }
137/// }
138/// }
139/// ```
140macro_rules! impl_try_from_event_for_user_facing_type {
141 ($inner_type:ty, $inner_variant:path, $outer_variant:path) => {
142 impl TryFrom<Event> for $inner_type {
143 type Error = AtspiError;
144 fn try_from(generic_event: Event) -> Result<$inner_type, Self::Error> {
145 if let $outer_variant($inner_variant(specific_event)) = generic_event {
146 Ok(specific_event)
147 } else {
148 Err(AtspiError::Conversion("Invalid type"))
149 }
150 }
151 }
152 };
153}
154
155/// Implements the `TryFrom` trait for a given event type.
156/// Converts a user facing event type into a `zbus::Message`.
157///
158/// # Example
159/// ```ignore
160/// impl_to_dbus_message!(StateChangedEvent);
161/// ```
162/// expands to:
163///
164/// ```ignore
165/// impl TryFrom<StateChangedEvent> for zbus::Message {
166/// type Error = AtspiError;
167/// fn try_from(event: StateChangedEvent) -> Result<Self, Self::Error> {
168/// Ok(zbus::MessageBuilder::signal(
169/// event.path(),
170/// StateChangedEvent::DBUS_INTERFACE,
171/// StateChangedEvent::DBUS_MEMBER,
172/// )?
173/// .sender(event.sender())?
174/// .build(&event.body())?)
175/// }
176/// }
177///
178macro_rules! impl_to_dbus_message {
179 ($type:ty) => {
180 #[cfg(feature = "zbus")]
181 impl TryFrom<$type> for zbus::Message {
182 type Error = AtspiError;
183 fn try_from(event: $type) -> Result<Self, Self::Error> {
184 Ok(zbus::MessageBuilder::signal(
185 event.path(),
186 <$type as GenericEvent>::DBUS_INTERFACE,
187 <$type as GenericEvent>::DBUS_MEMBER,
188 )?
189 .sender(event.sender())?
190 .build(&event.body())?)
191 }
192 }
193 };
194}
195
196/// Implements the `TryFrom` trait for a given event type.
197/// Converts a `zbus::Message` into a user facing event type.
198///
199/// # Example
200/// ```ignore
201/// impl_from_dbus_message!(StateChangedEvent);
202/// ```
203/// expands to:
204///
205/// ```ignore
206/// impl TryFrom<&zbus::Message> for StateChangedEvent {
207/// type Error = AtspiError;
208/// fn try_from(msg: &zbus::Message) -> Result<Self, Self::Error> {
209/// if msg.interface().ok_or(AtspiError::MissingInterface)? != StateChangedEvent::DBUS_INTERFACE {
210/// return Err(AtspiError::InterfaceMatch(format!("The interface {} does not match the signal's interface: {}",
211/// msg.interface().unwrap(),
212/// StateChangedEvent::DBUS_INTERFACE)));
213/// }
214/// if msg.member().ok_or(AtspiError::MissingMember)? != StateChangedEvent::DBUS_MEMBER {
215/// return Err(AtspiError::MemberMatch(format!("The member {} does not match the signal's member: {}",
216/// msg.member().unwrap(),
217/// StateChangedEvent::DBUS_MEMBER)));
218/// }
219/// StateChangedEvent::build(msg.try_into()?, msg.body::<StateChangedEvent::Body>()?)
220/// }
221/// }
222/// ```
223macro_rules! impl_from_dbus_message {
224 ($type:ty) => {
225 #[cfg(feature = "zbus")]
226 impl TryFrom<&zbus::Message> for $type {
227 type Error = AtspiError;
228 fn try_from(msg: &zbus::Message) -> Result<Self, Self::Error> {
229 if msg.interface().ok_or(AtspiError::MissingInterface)?
230 != <$type as GenericEvent>::DBUS_INTERFACE
231 {
232 return Err(AtspiError::InterfaceMatch(format!(
233 "The interface {} does not match the signal's interface: {}",
234 msg.interface().unwrap(),
235 <$type as GenericEvent>::DBUS_INTERFACE
236 )));
237 }
238 if msg.member().ok_or(AtspiError::MissingMember)? != <$type>::DBUS_MEMBER {
239 return Err(AtspiError::MemberMatch(format!(
240 "The member {} does not match the signal's member: {}",
241 // unwrap is safe here because of guard above
242 msg.member().unwrap(),
243 <$type as GenericEvent>::DBUS_MEMBER
244 )));
245 }
246 <$type>::build(msg.try_into()?, msg.body::<<$type as GenericEvent>::Body>()?)
247 }
248 }
249 };
250}
251
252/// Tests `Default` and `GenericEvent::build` for a given event struct.
253///
254/// Obtains a default for the given event struct.
255/// Asserts that the path and sender are the default.
256///
257/// Breaks the struct down into item (the associated object) and body.
258/// Then tests `GenericEvent::build` with the item and body.
259#[cfg(test)]
260macro_rules! generic_event_test_case {
261 ($type:ty) => {
262 #[test]
263 fn generic_event_uses() {
264 let struct_event = <$type>::default();
265 assert_eq!(struct_event.path().as_str(), "/org/a11y/atspi/accessible/null");
266 assert_eq!(struct_event.sender().as_str(), ":0.0");
267 let item = struct_event.item.clone();
268 let body = struct_event.body();
269 let build_struct = <$type>::build(item, body).expect("Could not build type from parts");
270 assert_eq!(struct_event, build_struct);
271 }
272 };
273}
274
275/// Tests conversion to and from the `Event` enum.
276///
277/// Obtains a default for the given event struct.
278/// Converts the struct into the `Event` enum, wrapping the struct.
279/// Converts the `Event` enum into the given event struct.
280/// Asserts that the original struct and the converted struct are equal.
281#[cfg(test)]
282macro_rules! event_enum_test_case {
283 ($type:ty) => {
284 #[test]
285 fn event_enum_conversion() {
286 let struct_event = <$type>::default();
287 let event = Event::from(struct_event.clone());
288 let struct_event_back = <$type>::try_from(event)
289 .expect("Could not convert from `Event` back to specific event type");
290 assert_eq!(struct_event, struct_event_back);
291 }
292 };
293}
294
295#[cfg(test)]
296macro_rules! zbus_message_test_case {
297 ($type:ty) => {
298 #[cfg(feature = "zbus")]
299 #[test]
300 fn zbus_msg_conversion_to_specific_event_type() {
301 let struct_event = <$type>::default();
302 let msg: zbus::Message = zbus::Message::try_from(struct_event.clone())
303 .expect("Could not convert event into a message");
304 let struct_event_back =
305 <$type>::try_from(&msg).expect("Could not convert message into an event");
306 assert_eq!(struct_event, struct_event_back);
307 }
308 #[cfg(feature = "zbus")]
309 #[test]
310 fn zbus_msg_conversion_to_event_enum_type() {
311 let struct_event = <$type>::default();
312 let msg: zbus::Message = zbus::Message::try_from(struct_event.clone())
313 .expect("Could not convert event into a message");
314 let event_enum_back =
315 Event::try_from(&msg).expect("Could not convert message into an event");
316 let event_enum: Event = struct_event.into();
317 assert_eq!(event_enum, event_enum_back);
318 }
319 // make want to consider parameterized tests here, no need for fuzz testing, but one level lower than that may be nice
320 // try having a matching member, matching interface, path, or body type, but that has some other piece which is not right
321 #[cfg(feature = "zbus")]
322 #[test]
323 #[should_panic(expected = "should panic")]
324 fn zbus_msg_conversion_failure_fake_msg() -> () {
325 let fake_msg = zbus::MessageBuilder::signal(
326 "/org/a11y/sixtynine/fourtwenty",
327 "org.a11y.atspi.technically.valid",
328 "MadeUpMember",
329 )
330 .unwrap()
331 .sender(":0.0")
332 .unwrap()
333 .build(&())
334 .unwrap();
335 let event = <$type>::try_from(&fake_msg);
336 event.expect("This should panic! Invalid event.");
337 }
338 #[cfg(feature = "zbus")]
339 #[test]
340 #[should_panic(expected = "should panic")]
341 fn zbus_msg_conversion_failure_correct_interface() -> () {
342 let fake_msg = zbus::MessageBuilder::signal(
343 "/org/a11y/sixtynine/fourtwenty",
344 <$type as GenericEvent>::DBUS_INTERFACE,
345 "MadeUpMember",
346 )
347 .unwrap()
348 .sender(":0.0")
349 .unwrap()
350 .build(&())
351 .unwrap();
352 let event = <$type>::try_from(&fake_msg);
353 event.expect("This should panic! Invalid event.");
354 }
355 #[cfg(feature = "zbus")]
356 #[test]
357 #[should_panic(expected = "should panic")]
358 fn zbus_msg_conversion_failure_correct_interface_and_member() -> () {
359 let fake_msg = zbus::MessageBuilder::signal(
360 "/org/a11y/sixtynine/fourtwenty",
361 <$type as GenericEvent>::DBUS_INTERFACE,
362 <$type as GenericEvent>::DBUS_MEMBER,
363 )
364 .unwrap()
365 .sender(":0.0")
366 .unwrap()
367 .build(&())
368 .unwrap();
369 let event = <$type>::try_from(&fake_msg);
370 event.expect("This should panic! Invalid event.");
371 }
372 #[cfg(feature = "zbus")]
373 #[test]
374 #[should_panic(expected = "should panic")]
375 fn zbus_msg_conversion_failure_correct_body() -> () {
376 let fake_msg = zbus::MessageBuilder::signal(
377 "/org/a11y/sixtynine/fourtwenty",
378 "org.a11y.atspi.accessible.technically.valid",
379 "FakeMember",
380 )
381 .unwrap()
382 .sender(":0.0")
383 .unwrap()
384 .build(&<$type>::default().body())
385 .unwrap();
386 let event = <$type>::try_from(&fake_msg);
387 event.expect("This should panic! Invalid event.");
388 }
389 #[cfg(feature = "zbus")]
390 #[test]
391 #[should_panic(expected = "should panic")]
392 fn zbus_msg_conversion_failure_correct_body_and_member() -> () {
393 let fake_msg = zbus::MessageBuilder::signal(
394 "/org/a11y/sixtynine/fourtwenty",
395 "org.a11y.atspi.accessible.technically.valid",
396 <$type as GenericEvent>::DBUS_MEMBER,
397 )
398 .unwrap()
399 .sender(":0.0")
400 .unwrap()
401 .build(&<$type>::default().body())
402 .unwrap();
403 let event = <$type>::try_from(&fake_msg);
404 event.expect("This should panic! Invalid event.");
405 }
406 };
407}
408
409macro_rules! event_wrapper_test_cases {
410 ($type:ty, $any_subtype:ty) => {
411 #[cfg(test)]
412 #[rename_item::rename(name($type), prefix = "events_tests_", case = "snake")]
413 mod foo {
414 use super::{$any_subtype, $type, Event, GenericEvent};
415 #[test]
416 fn into_and_try_from_event() {
417 let sub_type = <$any_subtype>::default();
418 let mod_type = <$type>::from(sub_type);
419 let event = Event::from(mod_type.clone());
420 let mod_type2 = <$type>::try_from(event.clone())
421 .expect("Could not create event type from event");
422 assert_eq!(
423 mod_type, mod_type2,
424 "Events were able to be parsed and encapsulated, but they have changed value"
425 );
426 }
427 #[cfg(feature = "zbus")]
428 #[test]
429 #[should_panic(expected = "should panic")]
430 fn zbus_msg_invalid_interface() {
431 let fake_msg = zbus::MessageBuilder::signal(
432 "/org/a11y/sixtynine/fourtwenty",
433 "org.a11y.atspi.technically.valid.lol",
434 <$any_subtype as GenericEvent>::DBUS_MEMBER,
435 )
436 .unwrap()
437 .sender(":0.0")
438 .unwrap()
439 .build(&<$any_subtype>::default().body())
440 .unwrap();
441 let mod_type = <$type>::try_from(&fake_msg);
442 mod_type.expect(
443 "This should panic! Could not convert message into a event wrapper type",
444 );
445 }
446 #[cfg(feature = "zbus")]
447 #[test]
448 #[should_panic(expected = "should panic")]
449 fn zbus_msg_invalid_member() {
450 let fake_msg = zbus::MessageBuilder::signal(
451 "/org/a11y/sixtynine/fourtwenty",
452 <$any_subtype as GenericEvent>::DBUS_INTERFACE,
453 "FakeFunctionLol",
454 )
455 .unwrap()
456 .sender(":0.0")
457 .unwrap()
458 .build(&<$any_subtype>::default().body())
459 .unwrap();
460 let mod_type = <$type>::try_from(&fake_msg);
461 mod_type.expect(
462 "This should panic! Could not convert message into a event wrapper type",
463 );
464 }
465 #[cfg(feature = "zbus")]
466 #[test]
467 #[should_panic(expected = "should panic")]
468 fn zbus_msg_invalid_member_and_interface() {
469 let fake_msg = zbus::MessageBuilder::signal(
470 "/org/a11y/sixtynine/fourtwenty",
471 "org.a11y.atspi.technically.allowed",
472 "FakeFunctionLol",
473 )
474 .unwrap()
475 .sender(":0.0")
476 .unwrap()
477 .build(&<$any_subtype>::default().body())
478 .unwrap();
479 let mod_type = <$type>::try_from(&fake_msg);
480 mod_type.expect(
481 "This should panic! Could not convert message into a event wrapper type",
482 );
483 }
484 #[cfg(feature = "zbus")]
485 #[test]
486 fn zbus_msg_conversion() {
487 let valid_msg = zbus::MessageBuilder::signal(
488 "/org/a11y/sixtynine/fourtwenty",
489 <$any_subtype as GenericEvent>::DBUS_INTERFACE,
490 <$any_subtype as GenericEvent>::DBUS_MEMBER,
491 )
492 .unwrap()
493 .sender(":0.0")
494 .unwrap()
495 .build(&<$any_subtype>::default().body())
496 .unwrap();
497 let mod_type = <$type>::try_from(&valid_msg);
498 mod_type.expect("Could not convert message into a event wrapper type");
499 }
500 }
501 };
502}
503
504macro_rules! event_test_cases {
505 ($type:ty) => {
506 #[cfg(test)]
507 #[rename_item::rename(name($type), prefix = "event_tests_", case = "snake")]
508 mod foo {
509 use super::{$type, Event, GenericEvent};
510
511 generic_event_test_case!($type);
512 event_enum_test_case!($type);
513 zbus_message_test_case!($type);
514 }
515 assert_impl_all!(
516 $type: Clone,
517 std::fmt::Debug,
518 serde::Serialize,
519 serde::Deserialize<'static>,
520 Default,
521 PartialEq,
522 Eq,
523 std::hash::Hash,
524 );
525 #[cfg(feature = "zbus")]
526 assert_impl_all!(zbus::Message: TryFrom<$type>);
527 };
528}
529
530/// Asserts that the signatures are equal, but ignores the outer parentheses as
531/// the difference between marshalled and unmarshalled signatures is often just one set of outer parentheses.
532#[macro_export]
533macro_rules! assert_eq_signatures {
534 ($lhs_sig:expr, $rhs_sig:expr) => {
535 assert!(
536 signatures_are_eq($lhs_sig, $rhs_sig),
537 "Signatures are not equal (Lhs: {}, Rhs: {})",
538 $lhs_sig,
539 $rhs_sig
540 );
541 };
542}
543