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 | /// ``` |
18 | macro_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 | /// ``` |
48 | macro_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 | /// ``` |
79 | macro_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 | /// ``` |
108 | macro_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 | /// ``` |
140 | macro_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 | /// |
178 | macro_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 | /// ``` |
223 | macro_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)] |
260 | macro_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)] |
282 | macro_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)] |
296 | macro_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 | |
409 | macro_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 | |
504 | macro_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 ] |
533 | macro_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 | |