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
14///             .name()
15///             .expect("Events are constructed with valid ObjetRef")
16///             .as_ref()
17///     }
18///     fn path(&self) -> ObjectPath<'_> {
19///         self.item.path().as_ref()
20///     }
21/// }
22/// ```
23macro_rules! impl_event_properties {
24	($type:ty) => {
25		impl crate::EventProperties for $type {
26			fn sender(&self) -> zbus_names::UniqueName<'_> {
27				self.item
28					.name()
29					.expect("Events are received with valid ObjetRef")
30					.as_ref()
31			}
32
33			fn path(&self) -> zvariant::ObjectPath<'_> {
34				self.item.path().as_ref()
35			}
36		}
37	};
38}
39
40/// Expands to implement From for [`crate::ObjectRef`].
41/// This depends on the struct to have an `item` field of type [`crate::ObjectRef`].
42///
43/// ```ignore
44/// impl_from_object_ref!(TextAttributesChangedEvent);
45/// ```
46///
47/// Exapnds to:
48///
49/// ```ignore
50/// impl From<ObjectRef> for TextAttributesChangedEvent {
51///     fn from(obj_ref: ObjectRef) -> Self {
52///         Self { item: obj_ref.into() }
53///     }
54/// }
55/// ```
56macro_rules! impl_from_object_ref {
57	($type:ty) => {
58		impl From<crate::ObjectRef<'_>> for $type {
59			fn from(obj_ref: crate::ObjectRef) -> Self {
60				Self { item: obj_ref.into() }
61			}
62		}
63	};
64}
65
66#[cfg(feature = "wrappers")]
67/// Expands to a conversion given the enclosed event type and outer `Event` variant.
68///
69/// eg
70/// ```ignore
71/// impl_from_interface_event_enum_for_event!(ObjectEvents, Event::Object);
72/// ```
73/// expands to:
74///
75/// ```ignore
76/// impl From<ObjectEvents> for Event {
77///     fn from(event_variant: ObjectEvents) -> Event {
78///         Event::Object(event_variant.into())
79///     }
80/// }
81/// ```
82macro_rules! impl_from_interface_event_enum_for_event {
83	($outer_type:ty, $outer_variant:path) => {
84		#[cfg(feature = "wrappers")]
85		impl From<$outer_type> for Event {
86			fn from(event_variant: $outer_type) -> Event {
87				$outer_variant(event_variant.into())
88			}
89		}
90	};
91}
92
93#[cfg(feature = "wrappers")]
94/// Expands to a conversion given the enclosed event enum type and outer `Event` variant.
95///
96/// eg
97/// ```ignore
98/// impl_try_from_event_for_interface_enum!(ObjectEvents, Event::Object);
99/// ```
100/// expands to:
101///
102/// ```ignore
103/// impl TryFrom<Event> for ObjectEvents {
104///     type Error = AtspiError;
105///     fn try_from(generic_event: Event) -> Result<ObjectEvents, Self::Error> {
106///         if let Event::Object(event_type) = generic_event {
107///             Ok(event_type)
108///         } else {
109///             Err(AtspiError::Conversion("Invalid type"))
110///         }
111///     }
112/// }
113/// ```
114macro_rules! impl_try_from_event_for_interface_enum {
115	($outer_type:ty, $outer_variant:path) => {
116		impl TryFrom<Event> for $outer_type {
117			type Error = AtspiError;
118			fn try_from(generic_event: Event) -> Result<$outer_type, Self::Error> {
119				if let $outer_variant(event_type) = generic_event {
120					Ok(event_type)
121				} else {
122					Err(AtspiError::Conversion("Invalid type"))
123				}
124			}
125		}
126	};
127}
128
129#[cfg(feature = "wrappers")]
130/// Expands to a conversion given the user facing event type,
131/// the wrapping interface enum variant, and the outer `Event` variant.
132///
133/// ```ignore
134/// impl_from_user_facing_event_for_interface_event_enum!(StateChangedEvent, ObjectEvents, ObjectEvents::StateChanged);
135/// ```
136///
137/// expands to:
138///
139/// ```ignore
140/// impl From<StateChangedEvent> for ObjectEvents {
141///     fn from(specific_event: StateChangedEvent) -> ObjectEvents {
142///         ObjectEvents::StateChanged(specific_event)
143///     }
144/// }
145/// ```
146macro_rules! impl_from_user_facing_event_for_interface_event_enum {
147	($inner_type:ty, $outer_type:ty, $inner_variant:path) => {
148		impl From<$inner_type> for $outer_type {
149			fn from(specific_event: $inner_type) -> $outer_type {
150				$inner_variant(specific_event)
151			}
152		}
153	};
154}
155
156#[cfg(feature = "wrappers")]
157/// Expands to a conversion given two arguments,
158/// 1. the user facing event type `(inner_type)`
159///    which relies on a conversion to its interface variant enum type variant.
160/// 2. the outer `Event::<Interface(<InterfaceEnum>)>` wrapper.,
161///    the enum type and outtermost variant.
162///
163/// ```ignore                                   user facing type, outer event variant
164/// impl_from_user_facing_type_for_event_enum!(StateChangedEvent, Event::Object);
165/// ```
166///
167/// expands to:
168///
169/// ```ignore
170/// impl From<StateChangedEvent> for Event {
171///    fn from(event_variant: StateChangedEvent) -> Event {
172///       Event::Object(ObjectEvents::StateChanged(event_variant))
173///   }
174/// }
175/// ```
176macro_rules! impl_from_user_facing_type_for_event_enum {
177	($inner_type:ty, $outer_variant:path) => {
178		#[cfg(feature = "wrappers")]
179		impl From<$inner_type> for Event {
180			fn from(event_variant: $inner_type) -> Event {
181				$outer_variant(event_variant.into())
182			}
183		}
184	};
185}
186
187#[cfg(feature = "wrappers")]
188/// Expands to a `TryFrom<Event> for T` where T is the user facing type.
189/// The macro takes three arguments:
190///
191/// 1. The user facing type.
192/// 2. The inner variant of the user facing type.
193/// 3. The outer variant of the `Event` enum.
194///
195/// ```ignore
196/// impl_try_from_event_for_user_facing_type!(
197///     StateChangedEvent,
198///     ObjectEvents::StateChanged,
199///     Event::Object
200/// );
201/// ```
202/// expands to:
203///
204/// ```ignore
205/// impl TryFrom<Event> for StateChangedEvent {
206///     type Error = AtspiError;
207///     fn try_from(generic_event: Event) -> Result<StateChangedEvent, Self::Error> {
208///         if let Event::Object(ObjectEvents::StateChanged(specific_event)) = generic_event {
209///             Ok(specific_event)
210///         } else {
211///             Err(AtspiError::Conversion("Invalid type"))
212///         }
213///     }
214/// }
215/// ```
216///
217macro_rules! impl_try_from_event_for_user_facing_type {
218	($inner_type:ty, $inner_variant:path, $outer_variant:path) => {
219		#[cfg(feature = "wrappers")]
220		impl TryFrom<crate::Event> for $inner_type {
221			type Error = AtspiError;
222			fn try_from(generic_event: crate::Event) -> Result<$inner_type, Self::Error> {
223				if let $outer_variant($inner_variant(specific_event)) = generic_event {
224					Ok(specific_event)
225				} else {
226					Err(AtspiError::Conversion("Invalid type"))
227				}
228			}
229		}
230	};
231}
232
233/// Implements the `TryFrom` trait for a given event type.
234/// Converts a user facing event type into a `zbus::Message`.
235///
236/// # Example
237/// ```ignore
238/// impl_to_dbus_message!(StateChangedEvent);
239/// ```
240/// expands to:
241///
242/// ```ignore
243/// impl TryFrom<StateChangedEvent> for zbus::Message {
244///   type Error = AtspiError;
245///   fn try_from(event: StateChangedEvent) -> Result<Self, Self::Error> {
246///     Ok(zbus::Message::signal(
247///         event.path(),
248///         StateChangedEvent::DBUS_INTERFACE,
249///         StateChangedEvent::DBUS_MEMBER,
250///     )?
251///     .sender(event.sender())?
252///     .build(&event.body())?)
253///  }
254/// }
255///
256macro_rules! impl_to_dbus_message {
257	($type:ty) => {
258		#[cfg(feature = "zbus")]
259		impl TryFrom<$type> for zbus::Message {
260			type Error = AtspiError;
261			fn try_from(event: $type) -> Result<Self, Self::Error> {
262				use crate::events::{DBusInterface, DBusMember, MessageConversion};
263				Ok(zbus::Message::signal(
264					event.path(),
265					<$type as DBusInterface>::DBUS_INTERFACE,
266					<$type as DBusMember>::DBUS_MEMBER,
267				)?
268				.sender(event.sender().to_string())?
269				.build(&event.body())?)
270			}
271		}
272	};
273}
274
275/// Implements the `TryFrom` trait for a given event type.
276/// Converts a `zbus::Message` into a user facing event type.
277///
278/// See [`crate::events::MessageConversion`] for details on implementation.
279///
280/// # Example
281/// ```ignore
282/// impl_from_dbus_message!(StateChangedEvent);
283/// ```
284/// expands to:
285///
286/// ```ignore
287/// impl TryFrom<&zbus::Message> for StateChangedEvents {
288///   type Error = AtspiError;
289///   fn try_from(msg: &zbus::Message) -> Result<Self, Self::Error> {
290///    let hdr = msg.header();
291///     <$type as MessageConversion>::try_from_message(msg, hdr)
292///   }
293/// }
294/// ```
295///
296/// There is also a variant that can be used for events whose [`crate::events::MessageConversion::Body`] is not
297/// [`crate::events::event_body::EventBodyOwned`]. You can call this by setting the second parameter to `Explicit`.
298macro_rules! impl_from_dbus_message {
299	($type:ty) => {
300		impl_from_dbus_message!($type, Auto);
301	};
302
303	($type:ty, Auto) => {
304		#[cfg(feature = "zbus")]
305		impl<'msg> TryFrom<&'msg zbus::Message> for $type {
306			type Error = AtspiError;
307			fn try_from(msg: &'msg zbus::Message) -> Result<Self, Self::Error> {
308				use crate::events::{EventBody, EventBodyQtBorrowed};
309				use crate::events::traits::{MessageConversion, MessageConversionExt};
310				use zvariant::Type;
311				use crate::ObjectRef;
312
313				let hdr = msg.header();
314				<Self as MessageConversionExt<<Self as MessageConversion>::Body<'_>>>::validate_interface(&hdr)?;
315				<Self as MessageConversionExt<<Self as MessageConversion>::Body<'_>>>::validate_member(&hdr)?;
316				let item = ObjectRef::try_from(&hdr)?;
317
318				let body = msg.body();
319				let signature = body.signature();
320
321				if signature == EventBody::SIGNATURE || signature == EventBodyQtBorrowed::SIGNATURE {
322					Ok(Self::from_message_unchecked_parts(item, body)?)
323				} else {
324					Err(AtspiError::SignatureMatch(format!(
325						"signature mismatch: expected: {}, signal body: {}",
326						msg.body().signature(),
327						<Self as MessageConversion>::Body::SIGNATURE,
328					)))
329				}
330			}
331		}
332	};
333
334	($type:ty, Explicit) => {
335		#[cfg(feature = "zbus")]
336		impl TryFrom<&zbus::Message> for $type {
337			type Error = crate::AtspiError;
338			fn try_from(msg: &zbus::Message) -> Result<Self, Self::Error> {
339				let hdr = msg.header();
340				<$type as crate::events::MessageConversionExt<<$type as MessageConversion>::Body<'_>>>::try_from_message(msg, &hdr)
341			}
342		}
343	};
344}
345
346// We decorate the macro with a `#[cfg(test)]` attribute.
347// This prevents Clippy from complaining about the macro not being used.
348// It is being used, but only in test mode.
349//
350/// Tests `Default` and `BusProperties::from_message_unchecked` for a given event struct.
351///
352/// Obtains a default for the given event struct.
353/// Asserts that the path and sender are the default.
354///
355/// Breaks the struct down into item (the associated object) and body.
356/// Then tests `BusProperties::from_message_unchecked` with the item and body.
357#[cfg(test)]
358macro_rules! generic_event_test_case {
359	($type:ty) => {
360		#[test]
361		fn generic_event_uses() {
362			use crate::events::traits::MessageConversion;
363
364			let event_struct = <$type>::default();
365			assert_eq!(event_struct.path().as_str(), crate::object_ref::TEST_OBJECT_PATH_STR);
366			assert_eq!(event_struct.sender().as_str(), crate::object_ref::TEST_OBJECT_BUS_NAME);
367			let body = event_struct.body();
368			let body2 = Message::method_call(
369				event_struct.path().as_str(),
370				<$type as crate::events::DBusMember>::DBUS_MEMBER,
371			)
372			.unwrap()
373			.sender(event_struct.sender().as_str())
374			.unwrap()
375			.build(&(body,))
376			.unwrap();
377			let header = body2.header();
378			let build_struct = <$type>::from_message_unchecked(&body2, &header)
379				.expect("<$type as Default>'s parts should build a valid ObjectRef");
380			assert_eq!(event_struct, build_struct);
381		}
382	};
383}
384
385// We decorate the macro with a `#[cfg(test)]` attribute.
386// This prevents Clippy from complaining about the macro not being used.
387// It is being used, but only in test mode.
388//
389/// Tests conversion to and from the `Event` enum.
390///
391/// Obtains a default for the given event struct.
392/// Converts the struct into the `Event` enum, wrapping the struct.
393/// Converts the `Event` enum into the given event struct.
394/// Asserts that the original struct and the converted struct are equal.
395#[cfg(test)]
396macro_rules! event_has_matching_xml_definition {
397	($type:ty) => {
398		#[test]
399		fn event_has_matching_xml_definition() {
400
401	    use zbus_xml;
402		use crate::events::{DBusInterface, DBusMember};
403
404		let fname = match <$type>::DBUS_INTERFACE.split(".").last().expect("Has last section") {
405			"Cache" => "xml/Cache.xml",
406			"Socket" => "xml/Socket.xml",
407			"Registry" => "xml/Registry.xml",
408			_ => "xml/Event.xml",
409		};
410
411		let reader = std::fs::File::open(fname).expect("Valid file path!");
412		let xml = zbus_xml::Node::from_reader(reader).expect("Valid DBus XML file!");
413		let Some(interface) = xml.interfaces().iter().find(|int| int.name() == <$type>::DBUS_INTERFACE) else {
414
415	    let possible_names: Vec<String> = xml.interfaces().iter().map(|int| int.name().as_str().to_string()).collect();
416        panic!("{} has interface name {}, but it was not found in the list of interfaces defined in the XML: {:?}", std::any::type_name::<$type>(), <$type>::DBUS_INTERFACE, possible_names);
417      };
418        let Some(_member) = interface.signals().iter().find(|mem| mem.name() == <$type>::DBUS_MEMBER) else {
419        let possible_names: Vec<String> = interface.signals().iter().map(|mem| mem.name().as_str().to_string()).collect();
420        panic!("{} has interface name {} and member name {}, but it was not found in the list of members defined in the corresponding interface in the XML: {:?}", std::any::type_name::<$type>(), <$type>::DBUS_INTERFACE, <$type>::DBUS_MEMBER, possible_names);
421      };
422		}
423	};
424}
425
426#[cfg(test)]
427macro_rules! zbus_message_qtspi_test_case {
428    ($type:ty, Auto) => {
429      #[cfg(feature = "zbus")]
430     #[test]
431    fn zbus_message_conversion_qtspi() {
432	  use crate::events::EventTypeProperties;
433	  use crate::events::MessageConversion;
434
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	  use crate::events::EventTypeProperties;
455	  use crate::events::MessageConversion;
456	  use crate::Event;
457
458      // in the case that the body type is EventBodyOwned, we need to also check successful
459      // conversion from a QSPI-style body.
460      let ev = <$type>::default();
461      let qt: crate::events::EventBodyQtOwned = ev.body().into();
462      let msg = zbus::Message::signal(
463        ev.path(),
464        ev.interface(),
465        ev.member(),
466      )
467        .unwrap()
468        .sender(":0.0")
469        .unwrap()
470        .build(&(qt,))
471        .unwrap();
472        assert_matches!(Event::try_from(&msg), Ok(_));
473     }
474    };
475    ($type:ty, Explicit) => {};
476}
477
478// We decorate the macro with a `#[cfg(test)]` attribute.
479// This prevents Clippy from complaining about the macro not being used.
480// It is being used, but only in test mode.
481//
482/// As of writing, this macro is expanded only once: in the `event_test_cases!` macro.
483#[cfg(test)]
484macro_rules! zbus_message_test_case {
485  ($type:ty) => {
486      zbus_message_test_case!($type, Auto);
487    };
488	($type:ty, $extra:tt) => {
489    zbus_message_qtspi_test_case!($type, $extra);
490		#[cfg(feature = "zbus")]
491		#[test]
492		fn zbus_msg_conversion_to_specific_event_type() {
493			let struct_event = <$type>::default();
494			let msg: zbus::Message = zbus::Message::try_from(<$type>::default()).expect("Should convert a `$type::default()` into a message. Check the `impl_to_dbus_message` macro .");
495
496			let struct_event_back =
497				<$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.");
498        	assert_eq!(struct_event, struct_event_back, "Events converted into a message and back must be the same");
499		}
500
501		#[cfg(feature = "zbus")]
502		#[test]
503		fn zbus_msg_conversion_to_event_enum_type() {
504			let struct_event = <$type>::default();
505			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.");
506			let event_enum_back =
507				crate::Event::try_from(&msg).expect("Should convert a from `$type::default()` built `Message` into an event enum. Check the `impl_from_dbus_message` macro.");
508			let event_enum: crate::Event = struct_event.into();
509			assert_eq!(event_enum, event_enum_back);
510		}
511		// may want to consider parameterized tests here, no need for fuzz testing, but one level lower than that may be nice
512		// try having a matching member, matching interface, path, or body type, but that has some other piece which is not right
513		#[cfg(feature = "zbus")]
514		#[test]
515		fn zbus_msg_conversion_failure_fake_msg() -> () {
516			let fake_msg = zbus::Message::signal(
517				"/org/a11y/sixtynine/fourtwenty",
518				"org.a11y.atspi.technically.valid",
519				"MadeUpMember",
520			)
521			.unwrap()
522			.sender(":0.0")
523			.unwrap()
524			.build(&())
525			.unwrap();
526			let event = <$type>::try_from(&fake_msg);
527      		assert_matches!(event, Err(_), "This conversion should fail");
528		}
529
530		#[cfg(feature = "zbus")]
531		#[test]
532		fn zbus_msg_conversion_validated_message_with_body() -> () {
533			use crate::events::MessageConversion;
534
535			let fake_msg = zbus::Message::signal(
536				"/org/a11y/sixtynine/fourtwenty",
537				"org.a11y.atspi.technically.valid",
538				"MadeUpMember",
539			)
540			.unwrap()
541			.sender(":0.0")
542			.unwrap()
543			.build(&<$type>::default().body())
544			.unwrap();
545			let hdr = fake_msg.header();
546			let event = <$type>::from_message_unchecked(&fake_msg, &hdr);
547      event.expect("The from_message_unchecked function should work, despite mismatching interface and member");
548		}
549
550		#[cfg(feature = "zbus")]
551		#[test]
552		fn zbus_msg_conversion_failure_correct_interface() -> () {
553			let fake_msg = zbus::Message::signal(
554				"/org/a11y/sixtynine/fourtwenty",
555				<$type as crate::events::DBusInterface>::DBUS_INTERFACE,
556				"MadeUpMember",
557			)
558			.unwrap()
559			.sender(":0.0")
560			.unwrap()
561			.build(&())
562			.unwrap();
563			let event = <$type>::try_from(&fake_msg);
564      assert_matches!(event, Err(AtspiError::MemberMatch(_)), "Wrong kind of error");
565		}
566
567		#[cfg(feature = "zbus")]
568		#[test]
569		fn zbus_msg_conversion_failure_correct_interface_and_member() -> () {
570			let fake_msg = zbus::Message::signal(
571				"/org/a11y/sixtynine/fourtwenty",
572				<$type as crate::events::DBusInterface>::DBUS_INTERFACE,
573				<$type as crate::events::DBusMember>::DBUS_MEMBER,
574			)
575			.unwrap()
576			.sender(":0.0")
577			.unwrap()
578			.build(&())
579			.unwrap();
580			let event = <$type>::try_from(&fake_msg);
581      assert_matches!(event, Err(AtspiError::SignatureMatch(_)), "Wrong kind of error");
582		}
583
584		#[cfg(feature = "zbus")]
585		#[test]
586		fn zbus_msg_conversion_failure_correct_interface_and_member_invalid_body() -> () {
587      // known invalid body for AT-SPI events
588      let invalid_body: (i32, u64, String, String) = (0, 0, String::new(), String::new());
589			let fake_msg = zbus::Message::signal(
590				"/org/a11y/sixtynine/fourtwenty",
591				<$type as crate::events::DBusInterface>::DBUS_INTERFACE,
592				<$type as crate::events::DBusMember>::DBUS_MEMBER,
593			)
594			.unwrap()
595			.sender(":0.0")
596			.unwrap()
597			.build(&invalid_body)
598			.unwrap();
599			let event = <$type>::try_from(&fake_msg);
600      assert_matches!(event, Err(AtspiError::SignatureMatch(_)), "Wrong kind of error");
601		}
602
603		#[cfg(feature = "zbus")]
604		#[test]
605		fn zbus_msg_conversion_failure_correct_body() -> () {
606			use crate::events::MessageConversion;
607			let fake_msg = zbus::Message::signal(
608				"/org/a11y/sixtynine/fourtwenty",
609				"org.a11y.atspi.accessible.technically.valid",
610				"FakeMember",
611			)
612			.unwrap()
613			.sender(":0.0")
614			.unwrap()
615			.build(&<$type>::default().body())
616			.unwrap();
617			let event = <$type>::try_from(&fake_msg);
618      assert_matches!(event, Err(_));
619		}
620
621		#[cfg(feature = "zbus")]
622		#[test]
623		fn zbus_msg_conversion_failure_correct_body_and_member() -> () {
624			use crate::events::MessageConversion;
625
626			let fake_msg = zbus::Message::signal(
627				"/org/a11y/sixtynine/fourtwenty",
628				"org.a11y.atspi.accessible.technically.valid",
629				<$type as crate::events::DBusMember>::DBUS_MEMBER,
630			)
631			.unwrap()
632			.sender(":0.0")
633			.unwrap()
634			.build(&<$type>::default().body())
635			.unwrap();
636			let event = <$type>::try_from(&fake_msg);
637      assert_matches!(event, Err(AtspiError::InterfaceMatch(_)), "Wrong kind of error");
638		}
639		#[cfg(feature = "zbus")]
640		#[test]
641		fn zbus_msg_conversion_failure_correct_body_and_interface() -> () {
642			use crate::events::MessageConversion;
643
644			let fake_msg = zbus::Message::signal(
645				"/org/a11y/sixtynine/fourtwenty",
646				<$type as crate::events::DBusInterface>::DBUS_INTERFACE,
647				"MadeUpMember",
648			)
649			.unwrap()
650			.sender(":0.0")
651			.unwrap()
652			.build(&<$type>::default().body())
653			.unwrap();
654			let event = <$type>::try_from(&fake_msg);
655      assert_matches!(event, Err(AtspiError::MemberMatch(_)), "Wrong kind of error");
656		}
657	};
658}
659
660#[cfg(feature = "wrappers")]
661/// Expands to five tests:
662///
663/// 1. `into_and_try_from_event`
664/// 2. `zbus_msg_invalid_interface`
665/// 3. `zbus_msg_invalid_member`
666/// 4. `zbus_msg_invalid_member_and_interface`
667/// 5. `zbus_msg_conversion`
668///
669/// The macro takes two arguments:
670/// 1. The event's interface enum type.
671/// 2. Any user facing event type that is wrapped by the interface enum.
672///
673/// # Examples
674///
675/// ```ignore
676/// event_wrapper_test_cases!(MouseEvents, AbsEvent);
677/// ```
678///
679/// For each of the types, the macro will create a module with the name `events_tests_{foo}`
680/// where `{foo}` is the snake case of the 'interface enum' name.
681macro_rules! event_wrapper_test_cases {
682	// The macro takes two arguments: the interface enum type and the user facing event type (ufet).
683	($iface_enum:ty, $ufet:ty) => {
684		#[cfg(test)]
685		#[rename_item::rename(name($iface_enum), prefix = "events_tests_", case = "snake")]
686		mod foo {
687		use super::{$ufet, $iface_enum, AtspiError, Event, MessageConversion};
688
689		// TODO: replace with [`std::assert_matches::assert_matches`] when stabilized
690		use assert_matches::assert_matches;
691
692		#[test]
693		fn into_and_try_from_user_facing_event() {
694			// Create a default event struct from its type's `Default::default()` impl.
695			let sub_type = <$ufet>::default();
696
697			// Wrap the event struct in the event enum
698			let mod_type = <$iface_enum>::from(sub_type);
699			let hint_iface = "Check macro `impl_from_user_facing_event_for_interface_event_enum!`";
700
701			// Wrap the inner event enum into the `Event` enum.
702			let event = Event::from(mod_type.clone());
703			let hint_event = "Check macro `impl_from_interface_event_enum_for_event!`";
704
705			// Unwrap the `Event` enum into the inner event enum.
706			let hint_event_try = "Check macro `impl_try_from_event_for_interface_enum!`";
707			let mod_type2 = <$iface_enum>::try_from(event.clone())
708				.expect("Should convert outer `Event` enum into interface enum. hints: {hint_event} and {hint_event_try}");
709
710			assert_eq!(
711				mod_type, mod_type2,
712				"Interface enums should match. hint: {hint_iface}, {hint_event} and {hint_event_try}"
713			);
714		}
715
716		#[cfg(feature = "zbus")]
717		#[test]
718		fn zbus_msg_invalid_interface() {
719			let fake_msg = zbus::Message::signal(
720				"/org/a11y/sixtynine/fourtwenty",
721				"org.a11y.atspi.technically.valid.lol",
722				<$ufet as crate::events::DBusMember>::DBUS_MEMBER,
723			)
724			.unwrap()
725			.sender(":0.0")
726			.unwrap()
727			.build(&<$ufet>::default().body())
728			.unwrap();
729
730			// It is hard to see what eventually is tested here. Let's unravel it:
731			//
732			// Below we call `TryFrom<&zbus::Message> for $type` where `$type` the interface enum name. (eg. `MouseEvents`, `ObjectEvents`, etc.) and
733			// `mod_type` is an 'interface enum' variant (eg. `MouseEvents::Abs(AbsEvent)`).
734			// This conversion is found in the `/src/events/{iface_name}.rs`` file.
735			// This conversion in turn leans on the `impl_from_dbus_message` macro.
736			// In `MouseEvents::Abs(msg.try_into()?)`, it is the `msg.try_into()?` that should fail.
737			// The `msg.try_into()?` is provided through the `impl_from_dbus_message` macro.
738
739			// Additioanlly, we check against the same method in `Event`; the overarchive enum that
740			// contains all other events as variants.
741
742			let mod_type = <$iface_enum>::try_from(&fake_msg);
743			let event_type = Event::try_from(&fake_msg);
744
745			assert_matches!(mod_type, Err(AtspiError::InterfaceMatch(_)), "Wrong kind of error");
746			assert_matches!(event_type, Err(AtspiError::InterfaceMatch(_)), "Wrong kind of error");
747			}
748
749			#[cfg(feature = "zbus")]
750			#[test]
751			fn zbus_msg_invalid_member() {
752				let fake_msg = zbus::Message::signal(
753					"/org/a11y/sixtynine/fourtwenty",
754					<$ufet as crate::events::DBusInterface>::DBUS_INTERFACE,
755					"FakeFunctionLol",
756				)
757				.unwrap()
758				.sender(":0.0")
759				.unwrap()
760				.build(&<$ufet>::default().body())
761				.unwrap();
762				// As above, the `msg.try_into()?` is provided through the `impl_from_dbus_message` macro.
763				let mod_type = <$iface_enum>::try_from(&fake_msg);
764        		assert_matches!(mod_type, Err(AtspiError::MemberMatch(_)), "Wrong kind of error");
765			}
766			#[cfg(feature = "zbus")]
767			#[test]
768			fn zbus_msg_invalid_member_and_interface() {
769				let fake_msg = zbus::Message::signal(
770					"/org/a11y/sixtynine/fourtwenty",
771					"org.a11y.atspi.technically.allowed",
772					"FakeFunctionLol",
773				)
774				.unwrap()
775				.sender(":0.0")
776				.unwrap()
777				.build(&<$ufet>::default().body())
778				.unwrap();
779				// As above, the `msg.try_into()?` is provided through the `impl_from_dbus_message` macro.
780				let mod_type = <$iface_enum>::try_from(&fake_msg);
781
782				// Note that the non-matching interface is the first error, so the member match error is not reached.
783        		assert_matches!(mod_type, Err(AtspiError::InterfaceMatch(_)), "Wrong kind of error");
784			}
785
786			#[cfg(feature = "zbus")]
787			#[test]
788			fn zbus_msg_conversion() {
789				let valid_msg = zbus::Message::signal(
790					"/org/a11y/sixtynine/fourtwenty",
791					<$ufet as crate::events::DBusInterface>::DBUS_INTERFACE,
792					<$ufet as crate::events::DBusMember>::DBUS_MEMBER,
793				)
794				.unwrap()
795				.sender(":0.0")
796				.unwrap()
797				.build(&<$ufet>::default().body())
798				.unwrap();
799				// As above, the `msg.try_into()?` is provided through the `impl_from_dbus_message` macro.
800				let mod_type = <$iface_enum>::try_from(&valid_msg);
801				mod_type.expect("Should convert from `$ufet::default()` built `Message` back into a interface event enum variant wrapping an inner type. Check the `impl_from_dbus_message` macro.");
802			}
803
804
805		}
806	};
807}
808
809macro_rules! event_test_cases {
810  ($ufet:ty) => {
811      event_test_cases!($ufet, Auto);
812  };
813	($ufet:ty, $qt:tt) => {
814		#[cfg(test)]
815		#[rename_item::rename(name($ufet), prefix = "event_tests_", case = "snake")]
816		mod foo {
817		use super::{$ufet, AtspiError, EventProperties };
818		use crate::events::traits::EventTypeProperties;
819		#[cfg(feature = "zbus")]
820        use zbus::Message;
821		use crate::Event;
822
823        // TODO: use [`std::assert_matches::assert_matches`] when stabilized
824        use assert_matches::assert_matches;
825
826			#[test]
827			#[cfg(feature = "wrappers")]
828			fn event_enum_conversion() {
829				let event_struct = <$ufet>::default();
830				let event_enum = Event::from(event_struct.clone());
831				let event_struct_back = <$ufet>::try_from(event_enum)
832					.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");
833				assert_eq!(event_struct, event_struct_back);
834			}
835
836			#[test]
837			#[cfg(feature = "wrappers")]
838			fn event_enum_transparency_test_case() {
839			let specific_event = <$ufet>::default();
840
841			let generic_event = Event::from(specific_event.clone());
842			let hint = "Check macro `impl_from_user_facing_type_for_event_enum!`.";
843
844			assert_eq!(
845				specific_event.member(),
846				generic_event.member(),
847				"DBus members do not match. hint: {hint}"
848			);
849			assert_eq!(
850				specific_event.interface(),
851				generic_event.interface(),
852				"DBus interfaces do not match. hint: {hint}"
853			);
854			assert_eq!(
855				specific_event.registry_string(),
856				generic_event.registry_string(),
857				"Registry strings do not match. hint: {hint}"
858			);
859			assert_eq!(
860				specific_event.match_rule(),
861				generic_event.match_rule(),
862				"Match rule strings do not match. hint: {hint}"
863			);
864			assert_eq!(specific_event.path(), generic_event.path(), "Paths do not match. hint: {hint}");
865			assert_eq!(specific_event.sender(), generic_event.sender(), "Senders do not match. hint: {hint}");
866			}
867
868			zbus_message_test_case!($ufet, $qt);
869      event_has_matching_xml_definition!($ufet);
870			generic_event_test_case!($ufet);
871		}
872		assert_impl_all!(
873			$ufet: Clone,
874			std::fmt::Debug,
875			serde::Serialize,
876			serde::Deserialize<'static>,
877			Default,
878			PartialEq,
879			Eq,
880			std::hash::Hash,
881			crate::events::traits::EventProperties,
882			crate::events::traits::EventTypeProperties,
883			crate::events::traits::DBusInterface,
884			crate::events::traits::DBusMember,
885			crate::events::traits::DBusMatchRule,
886			crate::events::traits::RegistryEventString
887		);
888
889		#[cfg(feature = "zbus")]
890		assert_impl_all!(zbus::Message: TryFrom<$ufet>);
891	};
892}
893
894/// Implements `MessageConversionExt` for a given target event type with a given body type.
895///
896/// # Example
897/// ```ignore
898/// # // 'ignore'd for bevity's sake because `impl`s require that the *example crate* defines traits `MessageConversionExt`,
899/// # // `MessageConversion` as well as the body and target types.
900///
901/// impl_msg_conversion_ext_for_target_type_with_specified_body_type!(target: RemoveAccessibleEvent, body: ObjectRef);
902/// ```
903/// expands to:
904///
905/// ```ignore
906/// #[cfg(feature = "zbus")]
907/// impl<'a> MessageConversionExt<'_, ObjectRef> for RemoveAccessibleEvent {
908///     fn try_from_message(msg: &zbus::Message, hdr: &Header) -> Result<Self, AtspiError> {
909///         <Self as MessageConversionExt<$body_type>>::validate_interface(hdr)?;
910///         <Self as MessageConversionExt<$body_type>>::validate_member(hdr)?;
911///         <Self as MessageConversionExt<$body_type>>::validate_body(msg)?;
912///         <Self as MessageConversion<'a>>::from_message_unchecked(msg, hdr)
913///     }
914/// }
915/// ```
916macro_rules! impl_msg_conversion_ext_for_target_type_with_specified_body_type {
917	(target: $target_type:ty, body: $body_type:ty) => {
918		#[cfg(feature = "zbus")]
919		impl<'a> crate::events::MessageConversionExt<'a, $body_type> for $target_type {
920			fn try_from_message(msg: &zbus::Message, hdr: &Header) -> Result<Self, AtspiError> {
921				use crate::events::MessageConversionExt;
922				<Self as MessageConversionExt<$body_type>>::validate_interface(hdr)?;
923				<Self as MessageConversionExt<$body_type>>::validate_member(hdr)?;
924				<Self as MessageConversionExt<$body_type>>::validate_body(msg)?;
925				<Self as MessageConversion<'a>>::from_message_unchecked(msg, hdr)
926			}
927		}
928	};
929}
930
931/// Implements `MessageConversionExt` for a given target event type.
932///
933/// # Example
934///
935/// ```ignore
936/// impl_msg_conversion_ext_for_target_type!(LoadCompleteEvent);
937/// ```
938/// expands to:
939///
940/// ```ignore
941/// #[cfg(feature = "zbus")]
942/// impl<'msg> MessageConversionExt<'msg, EventBody<'msg>> for LoadCompleteEvent {
943///     fn try_from_message(msg: &'msg zbus::Message, header: &Header) -> Result<Self, AtspiError> {
944///         Self::validate_interface(header)?;
945///         Self::validate_member(header)?;
946///
947///         let item = ObjectRefOwned::try_from(header)?;
948///         let msg_body = msg.body();
949///         let signature = msg_body.signature();
950///
951///         if signature == crate::events::EventBodyOwned::SIGNATURE
952///             || signature == crate::events::EventBodyQtOwned::SIGNATURE
953///         {
954///             Self::from_message_unchecked_parts(item, msg_body)
955///         } else {
956///             Err(AtspiError::SignatureMatch(format!(
957///                 "The message signature {} does not match a valid signal body signature: {} or {}",
958///                 msg.body().signature(),
959///                 crate::events::EventBodyOwned::SIGNATURE,
960///                 crate::events::EventBodyQtOwned::SIGNATURE,
961///             )))
962///         }
963///     }
964/// }
965/// ```
966macro_rules! impl_msg_conversion_ext_for_target_type {
967	($target_type:ty) => {
968		#[cfg(feature = "zbus")]
969		impl<'msg> crate::events::MessageConversionExt<'msg, crate::events::EventBody<'msg>> for $target_type {
970			fn try_from_message(msg: &'msg zbus::Message, header: &Header) -> Result<Self, AtspiError> {
971				use zvariant::Type;
972				use crate::events::traits::MessageConversion;
973				Self::validate_interface(header)?;
974				Self::validate_member(header)?;
975
976				let item = ObjectRefOwned::try_from(header)?;
977				let msg_body = msg.body();
978				let signature = msg_body.signature();
979
980				if signature == crate::events::EventBodyOwned::SIGNATURE
981					|| signature == crate::events::EventBodyQtOwned::SIGNATURE
982				{
983					Self::from_message_unchecked_parts(item.into_inner(), msg_body)
984				} else {
985					Err(AtspiError::SignatureMatch(format!(
986						"The message signature {} does not match a valid signal body signature: {} or {}",
987						msg.body().signature(),
988						crate::events::EventBodyOwned::SIGNATURE,
989						crate::events::EventBodyQtOwned::SIGNATURE,
990					)))
991				}
992			}
993		}
994	};
995}
996
997#[cfg(feature = "wrappers")]
998/// Implements `TryFromMessage` for a given event wrapper type.
999///
1000/// # Example
1001/// ```ignore
1002/// impl_tryfrommessage_for_event_wrapper!(StateChangedEvent);
1003/// ```
1004/// expands to:
1005///
1006/// ```ignore
1007/// #[cfg(feature = "zbus")]
1008/// impl TryFromMessage for StateChangedEvent {
1009///     fn try_from_message(msg: &zbus::Message) -> Result<StateChangedEvent, AtspiError> {
1010///        let header = msg.header();
1011///        let interface = header.interface().ok_or(AtspiError::MissingInterface)?;
1012///        if interface != Self::DBUS_INTERFACE {
1013///            return Err(AtspiError::InterfaceMatch(format!(
1014///                "Interface {} does not match require interface for event: {}",
1015///                interface,
1016///                Self::DBUS_INTERFACE
1017///            )));
1018///        }
1019///        Self::try_from_message_interface_checked(msg, &header)
1020///     }
1021/// }
1022/// ```
1023macro_rules! impl_tryfrommessage_for_event_wrapper {
1024	($wrapper:ty) => {
1025		#[cfg(feature = "zbus")]
1026		impl crate::events::traits::TryFromMessage for $wrapper {
1027			fn try_from_message(msg: &zbus::Message) -> Result<$wrapper, AtspiError> {
1028				use crate::events::traits::EventWrapperMessageConversion;
1029
1030				let header = msg.header();
1031				let interface = header.interface().ok_or(AtspiError::MissingInterface)?;
1032				if interface != Self::DBUS_INTERFACE {
1033					return Err(AtspiError::InterfaceMatch(format!(
1034						"Interface {} does not match require interface for event: {}",
1035						interface,
1036						Self::DBUS_INTERFACE
1037					)));
1038				}
1039				Self::try_from_message_interface_checked(msg, &header)
1040			}
1041		}
1042	};
1043}
1044
1045/// Implement the `MessageConversion` trait for the given types.
1046///
1047/// This macro is used to implement the `MessageConversion` trait for types that are built from an
1048/// `ObjectRef` and a `zbus::message::Body` only - no `EventBody` needed.
1049///
1050/// # Example
1051///
1052/// ```ignore
1053/// impl_msg_conversion_for_types_built_from_object_ref!(FocusEvent, FocusEvents);
1054/// ```
1055///
1056/// This will generate the following implementations:
1057///
1058/// ```ignore
1059/// #[cfg(feature = "zbus")]
1060/// impl MessageConversion<'_> for FocusEvent {
1061///     type Body<'msg> = crate::events::EventBody<'msg>;
1062///
1063///     fn from_message_unchecked_parts(
1064///         obj_ref: ObjectRefOwned,
1065///         _body: zbus::message::Body,
1066///     ) -> Result<Self, AtspiError> {
1067///         Ok(obj_ref.into())
1068///     }
1069///
1070///     fn from_message_unchecked(_: &zbus::Message, header: &Header) -> Result<Self, AtspiError> {
1071///         let obj_ref: ObjectRefOwned = header.try_into()?;
1072///         Ok(obj_ref.into())
1073///     }
1074///
1075///     fn body(&self) -> Self::Body<'_> {
1076///         crate::events::EventBodyOwned::default().into()
1077///     }
1078/// }
1079/// ```
1080macro_rules! impl_msg_conversion_for_types_built_from_object_ref {
1081	($($type:ty),*) => {
1082		$(
1083			#[cfg(feature = "zbus")]
1084			impl crate::events::MessageConversion<'_> for $type {
1085				type Body<'msg> = crate::events::EventBody<'msg>;
1086
1087				fn from_message_unchecked_parts(
1088					obj_ref: crate::object_ref::ObjectRef<'_>,
1089					_body: zbus::message::Body,
1090				) -> Result<Self, AtspiError> {
1091					Ok(obj_ref.into())
1092				}
1093
1094				fn from_message_unchecked(_: &zbus::Message, header: &Header) -> Result<Self, AtspiError> {
1095					let obj_ref: ObjectRefOwned = header.try_into()?;
1096					Ok( Self { item: obj_ref })
1097				}
1098
1099				fn body(&self) -> Self::Body<'_> {
1100					crate::events::EventBodyOwned::default().into()
1101				}
1102			}
1103		)*
1104	};
1105}
1106
1107/// Implement `DBusMember`, `DBusInterface`, `DBusMatchRule`, and `RegistryEventString`
1108/// for a given event type.
1109///
1110/// This macro takes 5 arguments in the order:
1111/// - The target type
1112/// - The member string
1113/// - The interface string
1114/// - The registry string
1115/// - The match rule string
1116///
1117/// # Example
1118/// ```ignore
1119/// impl_member_interface_registry_string_and_match_rule_for_event!(
1120/// FocusEvent, "Focus", "org.a11y.atspi.Event.Focus", "focus",
1121/// "type='signal',interface='org.a11y.atspi.Event.Focus'");
1122/// ```
1123/// expands to:
1124///
1125/// ```ignore
1126/// impl DBusMember for FocusEvent {
1127///    const DBUS_MEMBER: &'static str = "Focus";
1128/// }
1129/// impl DBusInterface for FocusEvent {
1130///   const DBUS_INTERFACE: &'static str = "org.a11y.atspi.Event.Focus";
1131/// }
1132/// impl MatchRule for FocusEvent {
1133///  const MATCH_RULE: &'static str = "type='signal',interface='org.a11y.atspi.Event.Focus'";
1134/// }
1135/// impl RegistryEventString for FocusEvent {
1136///  const REGISTRY_STRING: &'static str = "focus";
1137/// }
1138/// impl DBusProperties for FocusEvent {}
1139/// ```
1140macro_rules! impl_member_interface_registry_string_and_match_rule_for_event {
1141	($target_type:ty, $member_str:literal, $interface_str:literal, $registry_str:literal, $match_rule_str:literal) => {
1142		impl crate::events::DBusMember for $target_type {
1143			const DBUS_MEMBER: &'static str = $member_str;
1144		}
1145		impl crate::events::DBusInterface for $target_type {
1146			const DBUS_INTERFACE: &'static str = $interface_str;
1147		}
1148		impl crate::events::DBusMatchRule for $target_type {
1149			const MATCH_RULE_STRING: &'static str = $match_rule_str;
1150		}
1151		impl crate::events::RegistryEventString for $target_type {
1152			const REGISTRY_EVENT_STRING: &'static str = $registry_str;
1153		}
1154		impl crate::events::DBusProperties for $target_type {}
1155	};
1156}
1157
1158/// Implement `EventTypeProperties` for a given event type.
1159///
1160/// This macro takes one argument: the target type.
1161///
1162/// # Example
1163/// ```ignore
1164/// impl_event_type_properties_for_event!(FocusEvent);
1165/// ```
1166/// expands to:
1167///
1168/// ```ignore
1169/// impl EventTypeProperties for FocusEvent {
1170/// fn member(&self) -> &'static str {
1171///   Self::DBUS_MEMBER
1172/// }
1173/// fn interface(&self) -> &'static str {
1174///   Self::DBUS_INTERFACE
1175/// }
1176/// fn registry_string(&self) -> &'static str {
1177///   Self::REGISTRY_EVENT_STRING
1178/// }
1179/// fn match_rule(&self) -> &'static str {
1180///     Self::MATCH_RULE_STRING
1181///   }
1182/// }
1183///
1184macro_rules! impl_event_type_properties_for_event {
1185	($target_type:ty) => {
1186		impl crate::events::EventTypeProperties for $target_type {
1187			fn member(&self) -> &'static str {
1188				Self::DBUS_MEMBER
1189			}
1190
1191			fn interface(&self) -> &'static str {
1192				Self::DBUS_INTERFACE
1193			}
1194
1195			fn registry_string(&self) -> &'static str {
1196				Self::REGISTRY_EVENT_STRING
1197			}
1198
1199			fn match_rule(&self) -> &'static str {
1200				Self::MATCH_RULE_STRING
1201			}
1202		}
1203	};
1204}