atspi_common/
macros.rs

1/// Expands to implement the required methods for the [`crate::EventProperties`] trait.
2/// This depends on the struct to have an `item` field of type [`crate::ObjectRef`].
3///
4/// ```ignore
5/// impl_from_interface_event_enum_for_event!(TextCaretMovedEvent);
6/// ```
7///
8/// Expands to:
9///
10/// ```ignore
11/// impl EventProperties for TextCaretMovedEvent {
12///   fn sender(&self) -> UniqueName<'_> {
13///     self.item.name.as_ref()
14///   }
15///   fn path(&self) -> ObjectPath<'_> {
16///     self.item.path.as_ref()
17///   }
18/// }
19/// ```
20macro_rules! impl_event_properties {
21	($type:ty) => {
22		impl EventProperties for $type {
23			fn sender(&self) -> UniqueName<'_> {
24				self.item.name.as_ref()
25			}
26			fn path(&self) -> ObjectPath<'_> {
27				self.item.path.as_ref()
28			}
29		}
30	};
31}
32
33/// Expands to implement From for [`crate::ObjectRef`].
34/// This depends on the struct to have an `item` field of type [`crate::ObjectRef`].
35///
36/// ```ignore
37/// impl_from_object_ref!(TextCaretMovedEvent);
38/// ```
39///
40/// Exapnds to:
41///
42/// ```ignore
43/// impl From<ObjectRef> for TextCaretMovedItem {
44///     fn from(obj_ref: ObjectRef) -> Self {
45///         Self { item: obj_ref }
46///     }
47/// }
48/// ```
49macro_rules! impl_from_object_ref {
50	($type:ty) => {
51		impl From<crate::ObjectRef> for $type {
52			fn from(obj_ref: crate::ObjectRef) -> Self {
53				Self { item: obj_ref }
54			}
55		}
56	};
57}
58
59/// Expands to a conversion given the enclosed event type and outer `Event` variant.
60///
61/// eg
62/// ```ignore
63/// impl_from_interface_event_enum_for_event!(ObjectEvents, Event::Object);
64/// ```
65/// expands to:
66///
67/// ```ignore
68/// impl From<ObjectEvents> for Event {
69///     fn from(event_variant: ObjectEvents) -> Event {
70///         Event::Object(event_variant.into())
71///     }
72/// }
73/// ```
74macro_rules! impl_from_interface_event_enum_for_event {
75	($outer_type:ty, $outer_variant:path) => {
76		#[cfg(feature = "wrappers")]
77		impl From<$outer_type> for Event {
78			fn from(event_variant: $outer_type) -> Event {
79				$outer_variant(event_variant.into())
80			}
81		}
82	};
83}
84
85/// Expands to a conversion given the enclosed event enum type and outer `Event` variant.
86///
87/// eg
88/// ```ignore
89/// impl_try_from_event_for_interface_enum!(ObjectEvents, Event::Object);
90/// ```
91/// expands to:
92///
93/// ```ignore
94/// impl TryFrom<Event> for ObjectEvents {
95///     type Error = AtspiError;
96///     fn try_from(generic_event: Event) -> Result<ObjectEvents, Self::Error> {
97///         if let Event::Object(event_type) = generic_event {
98///             Ok(event_type)
99///         } else {
100///             Err(AtspiError::Conversion("Invalid type"))
101///         }
102///     }
103/// }
104/// ```
105macro_rules! impl_try_from_event_for_interface_enum {
106	($outer_type:ty, $outer_variant:path) => {
107		impl TryFrom<Event> for $outer_type {
108			type Error = AtspiError;
109			fn try_from(generic_event: Event) -> Result<$outer_type, Self::Error> {
110				if let $outer_variant(event_type) = generic_event {
111					Ok(event_type)
112				} else {
113					Err(AtspiError::Conversion("Invalid type"))
114				}
115			}
116		}
117	};
118}
119
120/// Expands to a conversion given the user facing event type and outer `Event::Interface(<InterfaceEnum>)` variant.,
121/// the enum type and outtermost variant.
122///
123/// ```ignore                                            user facing type,  enum type,    outer variant
124/// impl_from_user_facing_event_for_interface_event_enum!(StateChangedEvent, ObjectEvents, ObjectEvents::StateChanged);
125/// ```
126///
127/// expands to:
128///
129/// ```ignore
130/// impl From<StateChangedEvent> for ObjectEvents {
131///     fn from(specific_event: StateChangedEvent) -> ObjectEvents {
132///         ObjectEvents::StateChanged(specific_event)
133///     }
134/// }
135/// ```
136macro_rules! impl_from_user_facing_event_for_interface_event_enum {
137	($inner_type:ty, $outer_type:ty, $inner_variant:path) => {
138		impl From<$inner_type> for $outer_type {
139			fn from(specific_event: $inner_type) -> $outer_type {
140				$inner_variant(specific_event)
141			}
142		}
143	};
144}
145
146/// Expands to a conversion given two arguments,
147/// 1. the user facing event type `(inner_type)`
148///    which relies on a conversion to its interface variant enum type variant.
149/// 2. the outer `Event::<Interface(<InterfaceEnum>)>` wrapper.,
150///    the enum type and outtermost variant.
151///
152/// ```ignore                                   user facing type, outer event variant
153/// impl_from_user_facing_type_for_event_enum!(StateChangedEvent, Event::Object);
154/// ```
155///
156/// expands to:
157///
158/// ```ignore
159/// impl From<StateChangedEvent> for Event {
160///    fn from(event_variant: StateChangedEvent) -> Event {
161///       Event::Object(ObjectEvents::StateChanged(event_variant))
162///   }
163/// }
164/// ```
165macro_rules! impl_from_user_facing_type_for_event_enum {
166	($inner_type:ty, $outer_variant:path) => {
167		#[cfg(feature = "wrappers")]
168		impl From<$inner_type> for Event {
169			fn from(event_variant: $inner_type) -> Event {
170				$outer_variant(event_variant.into())
171			}
172		}
173	};
174}
175
176/// Expands to a conversion given two arguments,
177/// 1. the user facing event type `(inner_type)`
178/// 2. the outer `Event::<Interface(<InterfaceEnum>)>` wrapper.
179///
180/// eg
181/// ```ignore
182/// impl_try_from_event_for_user_facing_type!(StateChangedEvent, ObjectEvents::StateChanged);
183/// ```
184/// expands to:
185///
186/// ```ignore
187/// impl TryFrom<Event> for StateChangedEvent {
188///    type Error = AtspiError;
189///   fn try_from(generic_event: Event) -> Result<StateChangedEvent, Self::Error> {
190///      if let Event::Object(ObjectEvents::StateChanged(specific_event)) = generic_event {
191///          Ok(specific_event)
192///         } else {
193///          Err(AtspiError::Conversion("Invalid type"))
194///         }
195///   }
196/// }
197/// ```
198macro_rules! impl_try_from_event_for_user_facing_type {
199	($inner_type:ty, $inner_variant:path, $outer_variant:path) => {
200		#[cfg(feature = "wrappers")]
201		impl TryFrom<Event> for $inner_type {
202			type Error = AtspiError;
203			fn try_from(generic_event: Event) -> Result<$inner_type, Self::Error> {
204				if let $outer_variant($inner_variant(specific_event)) = generic_event {
205					Ok(specific_event)
206				} else {
207					Err(AtspiError::Conversion("Invalid type"))
208				}
209			}
210		}
211	};
212}
213
214/// Implements the `TryFrom` trait for a given event type.
215/// Converts a user facing event type into a `zbus::Message`.
216///
217/// # Example
218/// ```ignore
219/// impl_to_dbus_message!(StateChangedEvent);
220/// ```
221/// expands to:
222///
223/// ```ignore
224/// impl TryFrom<StateChangedEvent> for zbus::Message {
225///   type Error = AtspiError;
226///   fn try_from(event: StateChangedEvent) -> Result<Self, Self::Error> {
227///     Ok(zbus::Message::signal(
228///         event.path(),
229///         StateChangedEvent::DBUS_INTERFACE,
230///         StateChangedEvent::DBUS_MEMBER,
231///     )?
232///     .sender(event.sender())?
233///     .build(&event.body())?)
234///  }
235/// }
236///
237macro_rules! impl_to_dbus_message {
238	($type:ty) => {
239		#[cfg(feature = "zbus")]
240		impl TryFrom<$type> for zbus::Message {
241			type Error = AtspiError;
242			fn try_from(event: $type) -> Result<Self, Self::Error> {
243				Ok(zbus::Message::signal(
244					event.path(),
245					<$type as BusProperties>::DBUS_INTERFACE,
246					<$type as BusProperties>::DBUS_MEMBER,
247				)?
248				.sender(event.sender().to_string())?
249				.build(&event.body())?)
250			}
251		}
252	};
253}
254
255/// Implements the `TryFrom` trait for a given event type.
256/// Converts a `zbus::Message` into a user facing event type.
257///
258/// See [`crate::events::MessageConversion`] for details on implementation.
259///
260/// # Example
261/// ```ignore
262/// impl_from_dbus_message!(StateChangedEvent);
263/// ```
264/// expands to:
265///
266/// ```ignore
267/// impl TryFrom<&zbus::Message> for StateChangedEvents {
268///   type Error = AtspiError;
269///   fn try_from(msg: &zbus::Message) -> Result<Self, Self::Error> {
270///     <$type as MessageConversion>::try_from_message(msg)
271///   }
272/// }
273/// ```
274///
275/// There is also a variant that can be used for events whose [`crate::events::MessageConversion::Body`] is not
276/// [`crate::events::event_body::EventBodyOwned`]. You can call this by setting the second parameter to `Explicit`.
277macro_rules! impl_from_dbus_message {
278	($type:ty) => {
279		impl_from_dbus_message!($type, Auto);
280	};
281	($type:ty, Auto) => {
282		#[cfg(feature = "zbus")]
283		impl TryFrom<&zbus::Message> for $type {
284			type Error = AtspiError;
285			fn try_from(msg: &zbus::Message) -> Result<Self, Self::Error> {
286        use zvariant::Type;
287
288        Self::validate_interface(msg)?;
289        Self::validate_member(msg)?;
290
291        let body = msg.body();
292        let body_signature = body.signature();
293        let deser_body: <Self as MessageConversion>::Body = if body_signature == crate::events::EventBodyOwned::SIGNATURE {
294            body.deserialize_unchecked()?
295        } else if body_signature == crate::events::EventBodyQtOwned::SIGNATURE {
296			let qtbody: crate::events::EventBodyQtOwned = body.deserialize_unchecked()?;
297            qtbody.into()
298        } else {
299          return Err(AtspiError::SignatureMatch(format!(
300            "The message signature {} does not match the signal's body signature: {}",
301            body_signature,
302            <Self as MessageConversion>::Body::SIGNATURE,
303          )));
304        };
305        let item = msg.try_into()?;
306        Self::from_message_unchecked_parts(item, deser_body)
307      }
308    }
309	};
310	($type:ty, Explicit) => {
311		#[cfg(feature = "zbus")]
312		impl TryFrom<&zbus::Message> for $type {
313			type Error = AtspiError;
314			fn try_from(msg: &zbus::Message) -> Result<Self, Self::Error> {
315				<$type as MessageConversionExt<<$type as MessageConversion>::Body>>::try_from_message(msg)
316			}
317		}
318	};
319}
320
321// We decorate the macro with a `#[cfg(test)]` attribute.
322// This prevents Clippy from complaining about the macro not being used.
323// It is being used, but only in test mode.
324//
325/// Tests `Default` and `BusProperties::from_message_unchecked` for a given event struct.
326///
327/// Obtains a default for the given event struct.
328/// Asserts that the path and sender are the default.
329///
330/// Breaks the struct down into item (the associated object) and body.
331/// Then tests `BusProperties::from_message_unchecked` with the item and body.
332#[cfg(test)]
333macro_rules! generic_event_test_case {
334	($type:ty) => {
335		#[test]
336		fn generic_event_uses() {
337			let struct_event = <$type>::default();
338			assert_eq!(struct_event.path().as_str(), "/org/a11y/atspi/accessible/null");
339			assert_eq!(struct_event.sender().as_str(), ":0.0");
340			let body = struct_event.body();
341			let body2 = Message::method_call(
342				struct_event.path().as_str(),
343				<$type as BusProperties>::DBUS_MEMBER,
344			)
345			.unwrap()
346			.sender(struct_event.sender().as_str())
347			.unwrap()
348			.build(&(body,))
349			.unwrap();
350			let build_struct = <$type>::from_message_unchecked(&body2)
351				.expect("<$type as Default>'s parts should build a valid ObjectRef");
352			assert_eq!(struct_event, build_struct);
353		}
354	};
355}
356
357// We decorate the macro with a `#[cfg(test)]` attribute.
358// This prevents Clippy from complaining about the macro not being used.
359// It is being used, but only in test mode.
360//
361/// Tests conversion to and from the `Event` enum.
362///
363/// Obtains a default for the given event struct.
364/// Converts the struct into the `Event` enum, wrapping the struct.
365/// Converts the `Event` enum into the given event struct.
366/// Asserts that the original struct and the converted struct are equal.
367#[cfg(test)]
368macro_rules! event_enum_test_case {
369	($type:ty) => {
370		#[test]
371		fn event_enum_conversion() {
372			let struct_event = <$type>::default();
373			let event = Event::from(struct_event.clone());
374			let struct_event_back = <$type>::try_from(event)
375				.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");
376			assert_eq!(struct_event, struct_event_back);
377		}
378	};
379}
380
381/// Tests transparency of the `EventTypeProperties` and `EventProperties` trait on the `Event` wrapper type.
382///
383/// Obtains a default for the given event struct.
384/// Converts the struct into the `Event` enum, wrapping the struct.
385/// Checks the equality of all four functions defined in the `EventTypeProiperties` and `EventProperties` traits:
386///
387/// - `member`
388/// - `interface`
389/// - `registry_string`
390/// - `match_rule`
391/// - `path`
392/// - `sender`
393///
394/// It is imperitive that these items come through with no modifications from the wrappers.
395///
396#[cfg(test)]
397macro_rules! event_enum_transparency_test_case {
398	($type:ty) => {
399		#[test]
400		fn event_enum_transparency_test_case() {
401			let specific_event = <$type>::default();
402			let generic_event = Event::from(specific_event.clone());
403			assert_eq!(
404				specific_event.member(),
405				generic_event.member(),
406				"DBus member strings do not match."
407			);
408			assert_eq!(
409				specific_event.interface(),
410				generic_event.interface(),
411				"Registry interfaces do not match."
412			);
413			assert_eq!(
414				specific_event.registry_string(),
415				generic_event.registry_string(),
416				"Registry strings do not match."
417			);
418			assert_eq!(
419				specific_event.match_rule(),
420				generic_event.match_rule(),
421				"Match rule strings do not match."
422			);
423			assert_eq!(specific_event.path(), generic_event.path(), "Pathsdo not match.");
424			assert_eq!(specific_event.sender(), generic_event.sender(), "Senders do not match.");
425		}
426	};
427}
428
429#[cfg(test)]
430macro_rules! zbus_message_qtspi_test_case {
431    ($type:ty, Auto) => {
432      #[cfg(feature = "zbus")]
433     #[test]
434    fn zbus_message_conversion_qtspi() {
435      // in the case that the body type is EventBodyOwned, we need to also check successful
436      // conversion from a QSPI-style body.
437        let ev = <$type>::default();
438          let qt: crate::events::EventBodyQtOwned = ev.body().into();
439          let msg = zbus::Message::signal(
440            ev.path(),
441            ev.interface(),
442            ev.member(),
443          )
444          .unwrap()
445          .sender(":0.0")
446          .unwrap()
447          .build(&(qt,))
448          .unwrap();
449          <$type>::try_from(&msg).expect("Should be able to use an EventBodyQtOwned for any type whose BusProperties::Body = EventBodyOwned");
450        }
451      #[cfg(feature = "zbus")]
452     #[test]
453    fn zbus_message_conversion_qtspi_event_enum() {
454      // in the case that the body type is EventBodyOwned, we need to also check successful
455      // conversion from a QSPI-style body.
456        let ev = <$type>::default();
457          let qt: crate::events::EventBodyQtOwned = ev.body().into();
458          let msg = zbus::Message::signal(
459            ev.path(),
460            ev.interface(),
461            ev.member(),
462          )
463          .unwrap()
464          .sender(":0.0")
465          .unwrap()
466          .build(&(qt,))
467          .unwrap();
468          assert_matches!(Event::try_from(&msg), Ok(_));
469        }
470    };
471    ($type:ty, Explicit) => {};
472}
473
474// We decorate the macro with a `#[cfg(test)]` attribute.
475// This prevents Clippy from complaining about the macro not being used.
476// It is being used, but only in test mode.
477//
478/// As of writing, this macro is expanded only once: in the `event_test_cases!` macro.
479#[cfg(test)]
480macro_rules! zbus_message_test_case {
481  ($type:ty) => {
482      zbus_message_test_case!($type, Auto);
483    };
484	($type:ty, $extra:tt) => {
485    zbus_message_qtspi_test_case!($type, $extra);
486		#[cfg(feature = "zbus")]
487		#[test]
488		fn zbus_msg_conversion_to_specific_event_type() {
489			let struct_event = <$type>::default();
490			let msg: zbus::Message = zbus::Message::try_from(struct_event.clone())
491				.expect("Should convert a `$type::default()` into a message. Check the `impl_to_dbus_message` macro .");
492			let struct_event_back =
493				<$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.");
494        assert_eq!(struct_event, struct_event_back, "Events converted into a message and back must be the same");
495		}
496
497		#[cfg(feature = "zbus")]
498		#[test]
499		fn zbus_msg_conversion_to_event_enum_type() {
500			let struct_event = <$type>::default();
501			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 .");
502			let event_enum_back =
503				Event::try_from(&msg).expect("Should convert a from `$type::default()` built `Message` into an event enum. Check the `impl_from_dbus_message` macro .");
504			let event_enum: Event = struct_event.into();
505			assert_eq!(event_enum, event_enum_back);
506		}
507		// make want to consider parameterized tests here, no need for fuzz testing, but one level lower than that may be nice
508		// try having a matching member, matching interface, path, or body type, but that has some other piece which is not right
509		#[cfg(feature = "zbus")]
510		#[test]
511		fn zbus_msg_conversion_failure_fake_msg() -> () {
512			let fake_msg = zbus::Message::signal(
513				"/org/a11y/sixtynine/fourtwenty",
514				"org.a11y.atspi.technically.valid",
515				"MadeUpMember",
516			)
517			.unwrap()
518			.sender(":0.0")
519			.unwrap()
520			.build(&())
521			.unwrap();
522			let event = <$type>::try_from(&fake_msg);
523      assert_matches!(event, Err(_), "This conversion should fail");
524		}
525
526		#[cfg(feature = "zbus")]
527		#[test]
528		fn zbus_msg_conversion_validated_message_with_body() -> () {
529			let fake_msg = zbus::Message::signal(
530				"/org/a11y/sixtynine/fourtwenty",
531				"org.a11y.atspi.technically.valid",
532				"MadeUpMember",
533			)
534			.unwrap()
535			.sender(":0.0")
536			.unwrap()
537			.build(&<$type>::default().body())
538			.unwrap();
539			let event = <$type>::from_message_unchecked(&fake_msg);
540      event.expect("The from_message_unchecked function should work, despite mismatching interface and member");
541		}
542
543		#[cfg(feature = "zbus")]
544		#[test]
545		fn zbus_msg_conversion_failure_correct_interface() -> () {
546			let fake_msg = zbus::Message::signal(
547				"/org/a11y/sixtynine/fourtwenty",
548				<$type as BusProperties>::DBUS_INTERFACE,
549				"MadeUpMember",
550			)
551			.unwrap()
552			.sender(":0.0")
553			.unwrap()
554			.build(&())
555			.unwrap();
556			let event = <$type>::try_from(&fake_msg);
557      assert_matches!(event, Err(AtspiError::MemberMatch(_)), "Wrong kind of error");
558		}
559
560		#[cfg(feature = "zbus")]
561		#[test]
562		fn zbus_msg_conversion_failure_correct_interface_and_member() -> () {
563			let fake_msg = zbus::Message::signal(
564				"/org/a11y/sixtynine/fourtwenty",
565				<$type as BusProperties>::DBUS_INTERFACE,
566				<$type as BusProperties>::DBUS_MEMBER,
567			)
568			.unwrap()
569			.sender(":0.0")
570			.unwrap()
571			.build(&())
572			.unwrap();
573			let event = <$type>::try_from(&fake_msg);
574      assert_matches!(event, Err(AtspiError::SignatureMatch(_)), "Wrong kind of error");
575		}
576
577		#[cfg(feature = "zbus")]
578		#[test]
579		fn zbus_msg_conversion_failure_correct_interface_and_member_invalid_body() -> () {
580      // known invalid body for AT-SPI events
581      let invalid_body: (i32, u64, String, String) = (0, 0, String::new(), String::new());
582			let fake_msg = zbus::Message::signal(
583				"/org/a11y/sixtynine/fourtwenty",
584				<$type as BusProperties>::DBUS_INTERFACE,
585				<$type as BusProperties>::DBUS_MEMBER,
586			)
587			.unwrap()
588			.sender(":0.0")
589			.unwrap()
590			.build(&invalid_body)
591			.unwrap();
592			let event = <$type>::try_from(&fake_msg);
593      assert_matches!(event, Err(AtspiError::SignatureMatch(_)), "Wrong kind of error");
594		}
595
596		#[cfg(feature = "zbus")]
597		#[test]
598		fn zbus_msg_conversion_failure_correct_body() -> () {
599			let fake_msg = zbus::Message::signal(
600				"/org/a11y/sixtynine/fourtwenty",
601				"org.a11y.atspi.accessible.technically.valid",
602				"FakeMember",
603			)
604			.unwrap()
605			.sender(":0.0")
606			.unwrap()
607			.build(&<$type>::default().body())
608			.unwrap();
609			let event = <$type>::try_from(&fake_msg);
610      assert_matches!(event, Err(_));
611		}
612
613		#[cfg(feature = "zbus")]
614		#[test]
615		fn zbus_msg_conversion_failure_correct_body_and_member() -> () {
616			let fake_msg = zbus::Message::signal(
617				"/org/a11y/sixtynine/fourtwenty",
618				"org.a11y.atspi.accessible.technically.valid",
619				<$type as BusProperties>::DBUS_MEMBER,
620			)
621			.unwrap()
622			.sender(":0.0")
623			.unwrap()
624			.build(&<$type>::default().body())
625			.unwrap();
626			let event = <$type>::try_from(&fake_msg);
627      assert_matches!(event, Err(AtspiError::InterfaceMatch(_)), "Wrong kind of error");
628		}
629		#[cfg(feature = "zbus")]
630		#[test]
631		fn zbus_msg_conversion_failure_correct_body_and_interface() -> () {
632			let fake_msg = zbus::Message::signal(
633				"/org/a11y/sixtynine/fourtwenty",
634				<$type as BusProperties>::DBUS_INTERFACE,
635        "MadeUpMember",
636			)
637			.unwrap()
638			.sender(":0.0")
639			.unwrap()
640			.build(&<$type>::default().body())
641			.unwrap();
642			let event = <$type>::try_from(&fake_msg);
643      assert_matches!(event, Err(AtspiError::MemberMatch(_)), "Wrong kind of error");
644		}
645	};
646}
647
648/// Expands to five tests:
649///
650/// 1. `into_and_try_from_event`
651/// 2. `zbus_msg_invalid_interface`
652/// 3. `zbus_msg_invalid_member`
653/// 4. `zbus_msg_invalid_member_and_interface`
654/// 5. `zbus_msg_conversion`
655///
656/// # Examples
657///
658/// ```ignore
659/// event_wrapper_test_cases!(MouseEvents, AbsEvent);
660/// ```
661/// In the macro, its first argument `$type` is the event enum type.  
662/// The second argument `$any_subtype` is the event struct type.
663///
664/// For each of the types, the macro will create a module with the name `events_tests_{foo}`
665/// where `{foo}` is the snake case of the 'interface enum' name.
666macro_rules! event_wrapper_test_cases {
667	($type:ty, $any_subtype:ty) => {
668		#[cfg(test)]
669		#[rename_item::rename(name($type), prefix = "events_tests_", case = "snake")]
670		mod foo {
671			use super::{$any_subtype, $type, AtspiError, Event, BusProperties, MessageConversion};
672      // TODO: replace with [`std::assert_matches::assert_matches`] when stabailized
673      use assert_matches::assert_matches;
674			#[test]
675			fn into_and_try_from_event() {
676				// Create a default event struct from its type's `Default::default()` impl.
677				let sub_type = <$any_subtype>::default();
678				// Wrap the event struct in the event enum
679				let mod_type = <$type>::from(sub_type);
680				// Wrap the inner event enum into the `Event` enum.
681				let event = Event::from(mod_type.clone());
682				// Unwrap the `Event` enum into the inner event enum.
683				let mod_type2 = <$type>::try_from(event.clone())
684					.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");
685				assert_eq!(
686					mod_type, mod_type2,
687					"Events were able to be parsed and encapsulated, but they have changed value"
688				);
689			}
690			#[cfg(feature = "zbus")]
691			#[test]
692			fn zbus_msg_invalid_interface() {
693				let fake_msg = zbus::Message::signal(
694					"/org/a11y/sixtynine/fourtwenty",
695					"org.a11y.atspi.technically.valid.lol",
696					<$any_subtype as BusProperties>::DBUS_MEMBER,
697				)
698				.unwrap()
699				.sender(":0.0")
700				.unwrap()
701				.build(&<$any_subtype>::default().body())
702				.unwrap();
703
704				// It is hard to see what eventually is tested here. Let's unravel it:
705				//
706				// Below we call `TryFrom<&zbus::Message> for $type` where `$type` the interface enum name. (eg. `MouseEvents`, `ObjectEvents`, etc.) and
707				// `mod_type` is an 'interface enum' variant (eg. `MouseEvents::Abs(AbsEvent)`).
708				// This conversion is found in the `/src/events/{iface_name}.rs`` file.
709				// This conversion in turn leans on the `impl_from_dbus_message` macro.
710				// In `MouseEvents::Abs(msg.try_into()?)`, it is the `msg.try_into()?` that should fail.
711				// The `msg.try_into()?` is provided through the `impl_from_dbus_message` macro.
712        // Additioanlly, we check against the same method in `Event`; the overarchive enum that
713        // contains all other events as variants.
714				let mod_type = <$type>::try_from(&fake_msg);
715				let event_type = Event::try_from(&fake_msg);
716        assert_matches!(mod_type, Err(AtspiError::InterfaceMatch(_)), "Wrong kind of error");
717        assert_matches!(event_type, Err(AtspiError::InterfaceMatch(_)), "Wrong kind of error");
718			}
719			#[cfg(feature = "zbus")]
720			#[test]
721			fn zbus_msg_invalid_member() {
722				let fake_msg = zbus::Message::signal(
723					"/org/a11y/sixtynine/fourtwenty",
724					<$any_subtype as BusProperties>::DBUS_INTERFACE,
725					"FakeFunctionLol",
726				)
727				.unwrap()
728				.sender(":0.0")
729				.unwrap()
730				.build(&<$any_subtype>::default().body())
731				.unwrap();
732				// As above, the `msg.try_into()?` is provided through the `impl_from_dbus_message` macro.
733				let mod_type = <$type>::try_from(&fake_msg);
734        assert_matches!(mod_type, Err(AtspiError::MemberMatch(_)), "Wrong kind of error");
735			}
736			#[cfg(feature = "zbus")]
737			#[test]
738			fn zbus_msg_invalid_member_and_interface() {
739				let fake_msg = zbus::Message::signal(
740					"/org/a11y/sixtynine/fourtwenty",
741					"org.a11y.atspi.technically.allowed",
742					"FakeFunctionLol",
743				)
744				.unwrap()
745				.sender(":0.0")
746				.unwrap()
747				.build(&<$any_subtype>::default().body())
748				.unwrap();
749				// As above, the `msg.try_into()?` is provided through the `impl_from_dbus_message` macro.
750				let mod_type = <$type>::try_from(&fake_msg);
751
752				// Note that the non-matching interface is the first error, so the member match error is not reached.
753        assert_matches!(mod_type, Err(AtspiError::InterfaceMatch(_)), "Wrong kind of error");
754			}
755			#[cfg(feature = "zbus")]
756			#[test]
757			fn zbus_msg_conversion() {
758				let valid_msg = zbus::Message::signal(
759					"/org/a11y/sixtynine/fourtwenty",
760					<$any_subtype as BusProperties>::DBUS_INTERFACE,
761					<$any_subtype as BusProperties>::DBUS_MEMBER,
762				)
763				.unwrap()
764				.sender(":0.0")
765				.unwrap()
766				.build(&<$any_subtype>::default().body())
767				.unwrap();
768				// As above, the `msg.try_into()?` is provided through the `impl_from_dbus_message` macro.
769				let mod_type = <$type>::try_from(&valid_msg);
770				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.");
771			}
772		}
773	};
774}
775
776macro_rules! event_test_cases {
777  ($type:ty) => {
778      event_test_cases!($type, Auto);
779  };
780	($type:ty, $qt:tt) => {
781		#[cfg(test)]
782		#[rename_item::rename(name($type), prefix = "event_tests_", case = "snake")]
783		mod foo {
784			use crate::{EventTypeProperties, Event};
785			use super::{$type, AtspiError, BusProperties, MessageConversion, EventProperties};
786      use zbus::Message;
787      // TODO: use [`std::assert_matches::assert_matches`] when stabalized
788      use assert_matches::assert_matches;
789
790			generic_event_test_case!($type);
791			event_enum_test_case!($type);
792			zbus_message_test_case!($type, $qt);
793			event_enum_transparency_test_case!($type);
794		}
795		assert_impl_all!(
796			$type: Clone,
797			std::fmt::Debug,
798			serde::Serialize,
799			serde::Deserialize<'static>,
800			Default,
801			PartialEq,
802			Eq,
803			std::hash::Hash,
804			crate::EventProperties,
805			crate::EventTypeProperties,
806			crate::BusProperties,
807		);
808		#[cfg(feature = "zbus")]
809		assert_impl_all!(zbus::Message: TryFrom<$type>);
810	};
811}