atspi_common/
macros.rs

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}