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 `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 | /// ``` |
20 | macro_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 a conversion given the enclosed event type and outer `Event` variant. |
34 | /// |
35 | /// eg |
36 | /// ```ignore |
37 | /// impl_from_interface_event_enum_for_event!(ObjectEvents, Event::Object); |
38 | /// ``` |
39 | /// expands to: |
40 | /// |
41 | /// ```ignore |
42 | /// impl From<ObjectEvents> for Event { |
43 | /// fn from(event_variant: ObjectEvents) -> Event { |
44 | /// Event::Object(event_variant.into()) |
45 | /// } |
46 | /// } |
47 | /// ``` |
48 | macro_rules! impl_from_interface_event_enum_for_event { |
49 | ($outer_type:ty, $outer_variant:path) => { |
50 | impl From<$outer_type> for Event { |
51 | fn from(event_variant: $outer_type) -> Event { |
52 | $outer_variant(event_variant.into()) |
53 | } |
54 | } |
55 | }; |
56 | } |
57 | |
58 | /// Expands to a conversion given the enclosed event enum type and outer `Event` variant. |
59 | /// |
60 | /// eg |
61 | /// ```ignore |
62 | /// impl_try_from_event_for_user_facing_event_type!(ObjectEvents, Event::Object); |
63 | /// ``` |
64 | /// expands to: |
65 | /// |
66 | /// ```ignore |
67 | /// impl TryFrom<Event> for ObjectEvents { |
68 | /// type Error = AtspiError; |
69 | /// fn try_from(generic_event: Event) -> Result<ObjectEvents, Self::Error> { |
70 | /// if let Event::Object(event_type) = generic_event { |
71 | /// Ok(event_type) |
72 | /// } else { |
73 | /// Err(AtspiError::Conversion("Invalid type" )) |
74 | /// } |
75 | /// } |
76 | /// } |
77 | /// ``` |
78 | macro_rules! impl_try_from_event_for_user_facing_event_type { |
79 | ($outer_type:ty, $outer_variant:path) => { |
80 | impl TryFrom<Event> for $outer_type { |
81 | type Error = AtspiError; |
82 | fn try_from(generic_event: Event) -> Result<$outer_type, Self::Error> { |
83 | if let $outer_variant(event_type) = generic_event { |
84 | Ok(event_type) |
85 | } else { |
86 | Err(AtspiError::Conversion("Invalid type" )) |
87 | } |
88 | } |
89 | } |
90 | }; |
91 | } |
92 | |
93 | /// Expands to a conversion given the user facing event type and outer `Event::Interface(<InterfaceEnum>)` variant., |
94 | /// the enum type and outtermost variant. |
95 | /// |
96 | /// ```ignore user facing type, enum type, outer variant |
97 | /// impl_from_user_facing_event_for_interface_event_enum!(StateChangedEvent, ObjectEvents, ObjectEvents::StateChanged); |
98 | /// ``` |
99 | /// |
100 | /// expands to: |
101 | /// |
102 | /// ```ignore |
103 | /// impl From<StateChangedEvent> for ObjectEvents { |
104 | /// fn from(specific_event: StateChangedEvent) -> ObjectEvents { |
105 | /// ObjectEvents::StateChanged(specific_event) |
106 | /// } |
107 | /// } |
108 | /// ``` |
109 | macro_rules! impl_from_user_facing_event_for_interface_event_enum { |
110 | ($inner_type:ty, $outer_type:ty, $inner_variant:path) => { |
111 | impl From<$inner_type> for $outer_type { |
112 | fn from(specific_event: $inner_type) -> $outer_type { |
113 | $inner_variant(specific_event) |
114 | } |
115 | } |
116 | }; |
117 | } |
118 | |
119 | /// Expands to a conversion given two arguments, |
120 | /// 1. the user facing event type `(inner_type)` |
121 | /// which relies on a conversion to its interface variant enum type variant. |
122 | /// 2. the outer `Event::<Interface(<InterfaceEnum>)>` wrapper., |
123 | /// the enum type and outtermost variant. |
124 | /// |
125 | /// ```ignore user facing type, outer event variant |
126 | /// impl_from_user_facing_type_for_event_enum!(StateChangedEvent, Event::Object); |
127 | /// ``` |
128 | /// |
129 | /// expands to: |
130 | /// |
131 | /// ```ignore |
132 | /// impl From<StateChangedEvent> for Event { |
133 | /// fn from(event_variant: StateChangedEvent) -> Event { |
134 | /// Event::Object(ObjectEvents::StateChanged(event_variant)) |
135 | /// } |
136 | /// } |
137 | /// ``` |
138 | macro_rules! impl_from_user_facing_type_for_event_enum { |
139 | ($inner_type:ty, $outer_variant:path) => { |
140 | impl From<$inner_type> for Event { |
141 | fn from(event_variant: $inner_type) -> Event { |
142 | $outer_variant(event_variant.into()) |
143 | } |
144 | } |
145 | }; |
146 | } |
147 | |
148 | /// Expands to a conversion given two arguments, |
149 | /// 1. the user facing event type `(inner_type)` |
150 | /// 2. the outer `Event::<Interface(<InterfaceEnum>)>` wrapper. |
151 | /// |
152 | /// eg |
153 | /// ```ignore |
154 | /// impl_try_from_event_for_user_facing_type!(StateChangedEvent, ObjectEvents::StateChanged); |
155 | /// ``` |
156 | /// expands to: |
157 | /// |
158 | /// ```ignore |
159 | /// impl TryFrom<Event> for StateChangedEvent { |
160 | /// type Error = AtspiError; |
161 | /// fn try_from(generic_event: Event) -> Result<StateChangedEvent, Self::Error> { |
162 | /// if let Event::Object(ObjectEvents::StateChanged(specific_event)) = generic_event { |
163 | /// Ok(specific_event) |
164 | /// } else { |
165 | /// Err(AtspiError::Conversion("Invalid type" )) |
166 | /// } |
167 | /// } |
168 | /// } |
169 | /// ``` |
170 | macro_rules! impl_try_from_event_for_user_facing_type { |
171 | ($inner_type:ty, $inner_variant:path, $outer_variant:path) => { |
172 | impl TryFrom<Event> for $inner_type { |
173 | type Error = AtspiError; |
174 | fn try_from(generic_event: Event) -> Result<$inner_type, Self::Error> { |
175 | if let $outer_variant($inner_variant(specific_event)) = generic_event { |
176 | Ok(specific_event) |
177 | } else { |
178 | Err(AtspiError::Conversion("Invalid type" )) |
179 | } |
180 | } |
181 | } |
182 | }; |
183 | } |
184 | |
185 | /// Implements the `TryFrom` trait for a given event type. |
186 | /// Converts a user facing event type into a `zbus::Message`. |
187 | /// |
188 | /// # Example |
189 | /// ```ignore |
190 | /// impl_to_dbus_message!(StateChangedEvent); |
191 | /// ``` |
192 | /// expands to: |
193 | /// |
194 | /// ```ignore |
195 | /// impl TryFrom<StateChangedEvent> for zbus::Message { |
196 | /// type Error = AtspiError; |
197 | /// fn try_from(event: StateChangedEvent) -> Result<Self, Self::Error> { |
198 | /// Ok(zbus::Message::signal( |
199 | /// event.path(), |
200 | /// StateChangedEvent::DBUS_INTERFACE, |
201 | /// StateChangedEvent::DBUS_MEMBER, |
202 | /// )? |
203 | /// .sender(event.sender())? |
204 | /// .build(&event.body())?) |
205 | /// } |
206 | /// } |
207 | /// |
208 | macro_rules! impl_to_dbus_message { |
209 | ($type:ty) => { |
210 | #[cfg(feature = "zbus" )] |
211 | impl TryFrom<$type> for zbus::Message { |
212 | type Error = AtspiError; |
213 | fn try_from(event: $type) -> Result<Self, Self::Error> { |
214 | Ok(zbus::Message::signal( |
215 | event.path(), |
216 | <$type as BusProperties>::DBUS_INTERFACE, |
217 | <$type as BusProperties>::DBUS_MEMBER, |
218 | )? |
219 | .sender(event.sender().to_string())? |
220 | .build(&event.body())?) |
221 | } |
222 | } |
223 | }; |
224 | } |
225 | |
226 | /// Implements the `TryFrom` trait for a given event type. |
227 | /// Converts a `zbus::Message` into a user facing event type. |
228 | /// |
229 | /// # Example |
230 | /// ```ignore |
231 | /// impl_from_dbus_message!(StateChangedEvent); |
232 | /// ``` |
233 | /// expands to: |
234 | /// |
235 | /// ```ignore |
236 | /// impl TryFrom<&zbus::Message> for StateChangedEvent { |
237 | /// type Error = AtspiError; |
238 | /// fn try_from(msg: &zbus::Message) -> Result<Self, Self::Error> { |
239 | /// if msg.header().interface().ok_or(AtspiError::MissingInterface)? != StateChangedEvent::DBUS_INTERFACE { |
240 | /// return Err(AtspiError::InterfaceMatch(format!("The interface {} does not match the signal's interface: {}" , |
241 | /// msg.header().interface().unwrap(), |
242 | /// StateChangedEvent::DBUS_INTERFACE))); |
243 | /// } |
244 | /// if msg.header().member().ok_or(AtspiError::MissingMember)? != StateChangedEvent::DBUS_MEMBER { |
245 | /// return Err(AtspiError::MemberMatch(format!("The member {} does not match the signal's member: {}" , |
246 | /// msg.header().member().unwrap(), |
247 | /// StateChangedEvent::DBUS_MEMBER))); |
248 | /// } |
249 | /// StateChangedEvent::from_message_parts(msg.try_into()?, msg.body().deserialize::<StateChangedEvent::Body>()?) |
250 | /// } |
251 | /// } |
252 | /// ``` |
253 | macro_rules! impl_from_dbus_message { |
254 | ($type:ty) => { |
255 | #[cfg(feature = "zbus" )] |
256 | impl TryFrom<&zbus::Message> for $type { |
257 | type Error = AtspiError; |
258 | fn try_from(msg: &zbus::Message) -> Result<Self, Self::Error> { |
259 | let header = msg.header(); |
260 | if header.interface().ok_or(AtspiError::MissingInterface)? |
261 | != <$type as BusProperties>::DBUS_INTERFACE |
262 | { |
263 | return Err(AtspiError::InterfaceMatch(format!( |
264 | "The interface {} does not match the signal's interface: {}" , |
265 | header.interface().unwrap(), |
266 | <$type as BusProperties>::DBUS_INTERFACE |
267 | ))); |
268 | } |
269 | if header.member().ok_or(AtspiError::MissingMember)? != <$type>::DBUS_MEMBER { |
270 | return Err(AtspiError::MemberMatch(format!( |
271 | "The member {} does not match the signal's member: {}" , |
272 | // unwrap is safe here because of guard above |
273 | header.member().unwrap(), |
274 | <$type as BusProperties>::DBUS_MEMBER |
275 | ))); |
276 | } |
277 | <$type>::from_message_parts( |
278 | msg.try_into()?, |
279 | msg.body().deserialize::<<$type as BusProperties>::Body>()?, |
280 | ) |
281 | } |
282 | } |
283 | }; |
284 | } |
285 | |
286 | // We decorate the macro with a `#[cfg(test)]` attribute. |
287 | // This prevents Clippy from complaining about the macro not being used. |
288 | // It is being used, but only in test mode. |
289 | // |
290 | /// Tests `Default` and `BusProperties::from_message_parts` for a given event struct. |
291 | /// |
292 | /// Obtains a default for the given event struct. |
293 | /// Asserts that the path and sender are the default. |
294 | /// |
295 | /// Breaks the struct down into item (the associated object) and body. |
296 | /// Then tests `BusProperties::from_message_parts` with the item and body. |
297 | #[cfg (test)] |
298 | macro_rules! generic_event_test_case { |
299 | ($type:ty) => { |
300 | #[test] |
301 | fn generic_event_uses() { |
302 | let struct_event = <$type>::default(); |
303 | assert_eq!(struct_event.path().as_str(), "/org/a11y/atspi/accessible/null" ); |
304 | assert_eq!(struct_event.sender().as_str(), ":0.0" ); |
305 | let item = struct_event.item.clone(); |
306 | let body = struct_event.body(); |
307 | let build_struct = <$type>::from_message_parts(item, body) |
308 | .expect("<$type as Default>'s parts should build a valid ObjectRef" ); |
309 | assert_eq!(struct_event, build_struct); |
310 | } |
311 | }; |
312 | } |
313 | |
314 | // We decorate the macro with a `#[cfg(test)]` attribute. |
315 | // This prevents Clippy from complaining about the macro not being used. |
316 | // It is being used, but only in test mode. |
317 | // |
318 | /// Tests conversion to and from the `Event` enum. |
319 | /// |
320 | /// Obtains a default for the given event struct. |
321 | /// Converts the struct into the `Event` enum, wrapping the struct. |
322 | /// Converts the `Event` enum into the given event struct. |
323 | /// Asserts that the original struct and the converted struct are equal. |
324 | #[cfg (test)] |
325 | macro_rules! event_enum_test_case { |
326 | ($type:ty) => { |
327 | #[test] |
328 | fn event_enum_conversion() { |
329 | let struct_event = <$type>::default(); |
330 | let event = Event::from(struct_event.clone()); |
331 | let struct_event_back = <$type>::try_from(event) |
332 | .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" ); |
333 | assert_eq!(struct_event, struct_event_back); |
334 | } |
335 | }; |
336 | } |
337 | |
338 | /// Tests transparency of the `EventTypeProperties` and `EventProperties` trait on the `Event` wrapper type. |
339 | /// |
340 | /// Obtains a default for the given event struct. |
341 | /// Converts the struct into the `Event` enum, wrapping the struct. |
342 | /// Checks the equality of all four functions defined in the `EventTypeProiperties` and `EventProperties` traits: |
343 | /// |
344 | /// - `member` |
345 | /// - `interface` |
346 | /// - `registry_string` |
347 | /// - `match_rule` |
348 | /// - `path` |
349 | /// - `sender` |
350 | /// |
351 | /// It is imperitive that these items come through with no modifications from the wrappers. |
352 | /// |
353 | #[cfg (test)] |
354 | macro_rules! event_enum_transparency_test_case { |
355 | ($type:ty) => { |
356 | #[test] |
357 | fn event_enum_transparency_test_case() { |
358 | let specific_event = <$type>::default(); |
359 | let generic_event = Event::from(specific_event.clone()); |
360 | assert_eq!( |
361 | specific_event.member(), |
362 | generic_event.member(), |
363 | "DBus member strings do not match." |
364 | ); |
365 | assert_eq!( |
366 | specific_event.interface(), |
367 | generic_event.interface(), |
368 | "Registry interfaces do not match." |
369 | ); |
370 | assert_eq!( |
371 | specific_event.registry_string(), |
372 | generic_event.registry_string(), |
373 | "Registry strings do not match." |
374 | ); |
375 | assert_eq!( |
376 | specific_event.match_rule(), |
377 | generic_event.match_rule(), |
378 | "Match rule strings do not match." |
379 | ); |
380 | assert_eq!(specific_event.path(), generic_event.path(), "Pathsdo not match." ); |
381 | assert_eq!(specific_event.sender(), generic_event.sender(), "Senders do not match." ); |
382 | } |
383 | }; |
384 | } |
385 | |
386 | // We decorate the macro with a `#[cfg(test)]` attribute. |
387 | // This prevents Clippy from complaining about the macro not being used. |
388 | // It is being used, but only in test mode. |
389 | // |
390 | /// As of writing, this macro is expanded only once: in the `event_test_cases!` macro. |
391 | #[cfg (test)] |
392 | macro_rules! zbus_message_test_case { |
393 | ($type:ty) => { |
394 | #[cfg(feature = "zbus" )] |
395 | #[test] |
396 | fn zbus_msg_conversion_to_specific_event_type() { |
397 | let struct_event = <$type>::default(); |
398 | let msg: zbus::Message = zbus::Message::try_from(struct_event.clone()) |
399 | .expect("Should convert a `$type::default()` into a message. Check the `impl_to_dbus_message` macro ." ); |
400 | let struct_event_back = |
401 | <$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." ); |
402 | assert_eq!(struct_event, struct_event_back); |
403 | } |
404 | |
405 | #[cfg(feature = "zbus" )] |
406 | #[test] |
407 | fn zbus_msg_conversion_to_event_enum_type() { |
408 | let struct_event = <$type>::default(); |
409 | 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 ." ); |
410 | let event_enum_back = |
411 | Event::try_from(&msg).expect("Should convert a from `$type::default()` built `Message` into an event enum. Check the `impl_from_dbus_message` macro ." ); |
412 | let event_enum: Event = struct_event.into(); |
413 | assert_eq!(event_enum, event_enum_back); |
414 | } |
415 | // make want to consider parameterized tests here, no need for fuzz testing, but one level lower than that may be nice |
416 | // try having a matching member, matching interface, path, or body type, but that has some other piece which is not right |
417 | #[cfg(feature = "zbus" )] |
418 | #[test] |
419 | #[should_panic(expected = "Should panic" )] |
420 | fn zbus_msg_conversion_failure_fake_msg() -> () { |
421 | let fake_msg = zbus::Message::signal( |
422 | "/org/a11y/sixtynine/fourtwenty" , |
423 | "org.a11y.atspi.technically.valid" , |
424 | "MadeUpMember" , |
425 | ) |
426 | .unwrap() |
427 | .sender(":0.0" ) |
428 | .unwrap() |
429 | .build(&()) |
430 | .unwrap(); |
431 | let event = <$type>::try_from(&fake_msg); |
432 | event.expect("Should panic" ); |
433 | } |
434 | |
435 | #[cfg(feature = "zbus" )] |
436 | #[test] |
437 | #[should_panic(expected = "Should panic" )] |
438 | fn zbus_msg_conversion_failure_correct_interface() -> () { |
439 | let fake_msg = zbus::Message::signal( |
440 | "/org/a11y/sixtynine/fourtwenty" , |
441 | <$type as BusProperties>::DBUS_INTERFACE, |
442 | "MadeUpMember" , |
443 | ) |
444 | .unwrap() |
445 | .sender(":0.0" ) |
446 | .unwrap() |
447 | .build(&()) |
448 | .unwrap(); |
449 | let event = <$type>::try_from(&fake_msg); |
450 | event.expect("Should panic" ); |
451 | } |
452 | |
453 | #[cfg(feature = "zbus" )] |
454 | #[test] |
455 | #[should_panic(expected = "Should panic" )] |
456 | fn zbus_msg_conversion_failure_correct_interface_and_member() -> () { |
457 | let fake_msg = zbus::Message::signal( |
458 | "/org/a11y/sixtynine/fourtwenty" , |
459 | <$type as BusProperties>::DBUS_INTERFACE, |
460 | <$type as BusProperties>::DBUS_MEMBER, |
461 | ) |
462 | .unwrap() |
463 | .sender(":0.0" ) |
464 | .unwrap() |
465 | .build(&()) |
466 | .unwrap(); |
467 | let event = <$type>::try_from(&fake_msg); |
468 | event.expect("Should panic" ); |
469 | } |
470 | |
471 | #[cfg(feature = "zbus" )] |
472 | #[test] |
473 | #[should_panic(expected = "Should panic" )] |
474 | fn zbus_msg_conversion_failure_correct_body() -> () { |
475 | let fake_msg = zbus::Message::signal( |
476 | "/org/a11y/sixtynine/fourtwenty" , |
477 | "org.a11y.atspi.accessible.technically.valid" , |
478 | "FakeMember" , |
479 | ) |
480 | .unwrap() |
481 | .sender(":0.0" ) |
482 | .unwrap() |
483 | .build(&<$type>::default().body()) |
484 | .unwrap(); |
485 | let event = <$type>::try_from(&fake_msg); |
486 | event.expect("Should panic" ); |
487 | } |
488 | |
489 | #[cfg(feature = "zbus" )] |
490 | #[test] |
491 | #[should_panic(expected = "Should panic" )] |
492 | fn zbus_msg_conversion_failure_correct_body_and_member() -> () { |
493 | let fake_msg = zbus::Message::signal( |
494 | "/org/a11y/sixtynine/fourtwenty" , |
495 | "org.a11y.atspi.accessible.technically.valid" , |
496 | <$type as BusProperties>::DBUS_MEMBER, |
497 | ) |
498 | .unwrap() |
499 | .sender(":0.0" ) |
500 | .unwrap() |
501 | .build(&<$type>::default().body()) |
502 | .unwrap(); |
503 | let event = <$type>::try_from(&fake_msg); |
504 | event.expect("Should panic" ); |
505 | } |
506 | }; |
507 | } |
508 | |
509 | /// Expands to five tests: |
510 | /// |
511 | /// 1. `into_and_try_from_event` |
512 | /// 2. `zbus_msg_invalid_interface` |
513 | /// 3. `zbus_msg_invalid_member` |
514 | /// 4. `zbus_msg_invalid_member_and_interface` |
515 | /// 5. `zbus_msg_conversion` |
516 | /// |
517 | /// # Examples |
518 | /// |
519 | /// ```ignore |
520 | /// event_wrapper_test_cases!(MouseEvents, AbsEvent); |
521 | /// ``` |
522 | /// In the macro, its first argument `$type` is the event enum type. |
523 | /// The second argument `$any_subtype` is the event struct type. |
524 | /// |
525 | /// For each of the types, the macro will create a module with the name `events_tests_{foo}` |
526 | /// where `{foo}` is the snake case of the 'interface enum' name. |
527 | macro_rules! event_wrapper_test_cases { |
528 | ($type:ty, $any_subtype:ty) => { |
529 | #[cfg(test)] |
530 | #[rename_item::rename(name($type), prefix = "events_tests_" , case = "snake" )] |
531 | mod foo { |
532 | use super::{$any_subtype, $type, Event, BusProperties}; |
533 | #[test] |
534 | fn into_and_try_from_event() { |
535 | // Create a default event struct from its type's `Default::default()` impl. |
536 | let sub_type = <$any_subtype>::default(); |
537 | // Wrap the event struct in the event enum |
538 | let mod_type = <$type>::from(sub_type); |
539 | // Wrap the inner event enum into the `Event` enum. |
540 | let event = Event::from(mod_type.clone()); |
541 | // Unwrap the `Event` enum into the inner event enum. |
542 | let mod_type2 = <$type>::try_from(event.clone()) |
543 | .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" ); |
544 | assert_eq!( |
545 | mod_type, mod_type2, |
546 | "Events were able to be parsed and encapsulated, but they have changed value" |
547 | ); |
548 | } |
549 | #[cfg(feature = "zbus" )] |
550 | #[test] |
551 | #[should_panic(expected = "Should panic" )] |
552 | fn zbus_msg_invalid_interface() { |
553 | let fake_msg = zbus::Message::signal( |
554 | "/org/a11y/sixtynine/fourtwenty" , |
555 | "org.a11y.atspi.technically.valid.lol" , |
556 | <$any_subtype as BusProperties>::DBUS_MEMBER, |
557 | ) |
558 | .unwrap() |
559 | .sender(":0.0" ) |
560 | .unwrap() |
561 | .build(&<$any_subtype>::default().body()) |
562 | .unwrap(); |
563 | |
564 | // It is hard to see what eventually is tested here. Let's unravel it: |
565 | // |
566 | // Below we call `TryFrom<&zbus::Message> for $type` where `$type` the interface enum name. (eg. `MouseEvents`, `ObjectEvents`, etc.) and |
567 | // `mod_type` is an 'interface enum' variant (eg. `MouseEvents::Abs(AbsEvent)`). |
568 | // This conversion is found in the `/src/events/{iface_name}.rs`` file. |
569 | // This conversion in turn leans on the `impl_from_dbus_message` macro. |
570 | // In `MouseEvents::Abs(msg.try_into()?)`, it is the `msg.try_into()?` that should fail. |
571 | // The `msg.try_into()?` is provided through the `impl_from_dbus_message` macro. |
572 | let mod_type = <$type>::try_from(&fake_msg); |
573 | mod_type.expect("Should panic" ); |
574 | } |
575 | #[cfg(feature = "zbus" )] |
576 | #[test] |
577 | #[should_panic(expected = "Should panic" )] |
578 | fn zbus_msg_invalid_member() { |
579 | let fake_msg = zbus::Message::signal( |
580 | "/org/a11y/sixtynine/fourtwenty" , |
581 | <$any_subtype as BusProperties>::DBUS_INTERFACE, |
582 | "FakeFunctionLol" , |
583 | ) |
584 | .unwrap() |
585 | .sender(":0.0" ) |
586 | .unwrap() |
587 | .build(&<$any_subtype>::default().body()) |
588 | .unwrap(); |
589 | // As above, the `msg.try_into()?` is provided through the `impl_from_dbus_message` macro. |
590 | let mod_type = <$type>::try_from(&fake_msg); |
591 | mod_type.expect("Should panic" ); |
592 | } |
593 | #[cfg(feature = "zbus" )] |
594 | #[test] |
595 | #[should_panic(expected = "Should panic" )] |
596 | fn zbus_msg_invalid_member_and_interface() { |
597 | let fake_msg = zbus::Message::signal( |
598 | "/org/a11y/sixtynine/fourtwenty" , |
599 | "org.a11y.atspi.technically.allowed" , |
600 | "FakeFunctionLol" , |
601 | ) |
602 | .unwrap() |
603 | .sender(":0.0" ) |
604 | .unwrap() |
605 | .build(&<$any_subtype>::default().body()) |
606 | .unwrap(); |
607 | // As above, the `msg.try_into()?` is provided through the `impl_from_dbus_message` macro. |
608 | let mod_type = <$type>::try_from(&fake_msg); |
609 | |
610 | // Note that the non-matching interface is the first error, so the member match error is not reached. |
611 | mod_type.expect("Should panic" ); |
612 | } |
613 | #[cfg(feature = "zbus" )] |
614 | #[test] |
615 | fn zbus_msg_conversion() { |
616 | let valid_msg = zbus::Message::signal( |
617 | "/org/a11y/sixtynine/fourtwenty" , |
618 | <$any_subtype as BusProperties>::DBUS_INTERFACE, |
619 | <$any_subtype as BusProperties>::DBUS_MEMBER, |
620 | ) |
621 | .unwrap() |
622 | .sender(":0.0" ) |
623 | .unwrap() |
624 | .build(&<$any_subtype>::default().body()) |
625 | .unwrap(); |
626 | // As above, the `msg.try_into()?` is provided through the `impl_from_dbus_message` macro. |
627 | let mod_type = <$type>::try_from(&valid_msg); |
628 | 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." ); |
629 | } |
630 | } |
631 | }; |
632 | } |
633 | |
634 | macro_rules! event_test_cases { |
635 | ($type:ty) => { |
636 | #[cfg(test)] |
637 | #[rename_item::rename(name($type), prefix = "event_tests_" , case = "snake" )] |
638 | mod foo { |
639 | use super::{$type, Event, BusProperties, EventProperties, EventTypeProperties}; |
640 | |
641 | generic_event_test_case!($type); |
642 | event_enum_test_case!($type); |
643 | zbus_message_test_case!($type); |
644 | event_enum_transparency_test_case!($type); |
645 | } |
646 | assert_impl_all!( |
647 | $type: Clone, |
648 | std::fmt::Debug, |
649 | serde::Serialize, |
650 | serde::Deserialize<'static>, |
651 | Default, |
652 | PartialEq, |
653 | Eq, |
654 | std::hash::Hash, |
655 | crate::EventProperties, |
656 | crate::EventTypeProperties, |
657 | crate::BusProperties, |
658 | ); |
659 | #[cfg(feature = "zbus" )] |
660 | assert_impl_all!(zbus::Message: TryFrom<$type>); |
661 | }; |
662 | } |
663 | |