| 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 | |