From fdf87a38a219933ffe99b17baf87841a79702f28 Mon Sep 17 00:00:00 2001 From: "Ragotzy.devin" Date: Tue, 23 Jun 2020 16:33:37 -0400 Subject: [PATCH] Generate stub/stripped Any*Event enums in event_enum! macro * Conditionally emit tokens for content enum in event_enum! and the path for each Any*Event variant contents. * Add tests for redaction events now that they are part of Any*Event enums. * Fix any tests that used Any*EventContent. --- ruma-events-macros/src/event_enum.rs | 187 +++++++++++++++++---------- ruma-events/src/enums.rs | 76 ++++------- ruma-events/src/lib.rs | 19 ++- ruma-events/src/room/redaction.rs | 4 + ruma-events/tests/custom.rs | 52 +++++++- ruma-events/tests/enums.rs | 29 ++--- ruma-events/tests/redaction.rs | 73 +++++++++++ ruma-events/tests/stripped.rs | 46 +++++-- 8 files changed, 333 insertions(+), 153 deletions(-) create mode 100644 ruma-events/tests/redaction.rs diff --git a/ruma-events-macros/src/event_enum.rs b/ruma-events-macros/src/event_enum.rs index 689c3338..d3806ed0 100644 --- a/ruma-events-macros/src/event_enum.rs +++ b/ruma-events-macros/src/event_enum.rs @@ -9,71 +9,56 @@ use syn::{ /// Create a content enum from `EventEnumInput`. pub fn expand_event_enum(input: EventEnumInput) -> syn::Result { - let attrs = &input.attrs; let ident = &input.name; - let event_type_str = &input.events; - let event_struct = Ident::new(&ident.to_string().trim_start_matches("Any"), ident.span()); - let variants = input.events.iter().map(to_camel_case).collect::>>()?; - let content = input.events.iter().map(to_event_path).collect::>(); + let event_enum = expand_any_enum_with_deserialize(&input, ident)?; - let event_enum = quote! { - #( #attrs )* - #[derive(Clone, Debug, ::serde::Serialize)] - #[serde(untagged)] - #[allow(clippy::large_enum_variant)] - pub enum #ident { - #( - #[doc = #event_type_str] - #variants(#content), - )* - /// An event not defined by the Matrix specification - Custom(::ruma_events::#event_struct<::ruma_events::custom::CustomEventContent>), - } - }; + let needs_event_content = ident == "AnyStateEvent" + || ident == "AnyMessageEvent" + || ident == "AnyToDeviceEvent" + || ident == "AnyEphemeralRoomEvent" + || ident == "AnyBasicEvent"; - let event_deserialize_impl = quote! { - impl<'de> ::serde::de::Deserialize<'de> for #ident { - fn deserialize(deserializer: D) -> Result - where - D: ::serde::de::Deserializer<'de>, - { - use ::serde::de::Error as _; + let needs_event_stub = ident == "AnyStateEvent" || ident == "AnyMessageEvent"; - let json = Box::<::serde_json::value::RawValue>::deserialize(deserializer)?; - let ::ruma_events::EventDeHelper { ev_type } = ::ruma_events::from_raw_json_value(&json)?; - match ev_type.as_str() { - #( - #event_type_str => { - let event = ::serde_json::from_str::<#content>(json.get()).map_err(D::Error::custom)?; - Ok(#ident::#variants(event)) - }, - )* - event => { - let event = - ::serde_json::from_str::<::ruma_events::#event_struct<::ruma_events::custom::CustomEventContent>>(json.get()) - .map_err(D::Error::custom)?; + let needs_stripped_event = ident == "AnyStateEvent"; - Ok(Self::Custom(event)) - }, - } - } - } - }; + let event_stub_enum = + if needs_event_stub { expand_stub_enum(&input)? } else { TokenStream::new() }; - let event_content_enum = expand_content_enum(input)?; + let event_stripped_enum = + if needs_stripped_event { expand_stripped_enum(&input)? } else { TokenStream::new() }; + + let event_content_enum = + if needs_event_content { expand_content_enum(&input)? } else { TokenStream::new() }; Ok(quote! { #event_enum - #event_deserialize_impl + #event_stub_enum + + #event_stripped_enum #event_content_enum }) } +/// Create a "stub" enum from `EventEnumInput`. +pub fn expand_stub_enum(input: &EventEnumInput) -> syn::Result { + let ident = Ident::new(&format!("{}Stub", input.name.to_string()), input.name.span()); + + expand_any_enum_with_deserialize(input, &ident) +} + +/// Create a "stripped" enum from `EventEnumInput`. +pub fn expand_stripped_enum(input: &EventEnumInput) -> syn::Result { + let ident = Ident::new("AnyStrippedStateEventStub", input.name.span()); + + expand_any_enum_with_deserialize(input, &ident) +} + /// Create a content enum from `EventEnumInput`. -pub fn expand_content_enum(input: EventEnumInput) -> syn::Result { +pub fn expand_content_enum(input: &EventEnumInput) -> syn::Result { let attrs = &input.attrs; let ident = Ident::new(&format!("{}Content", input.name.to_string()), input.name.span()); let event_type_str = &input.events; @@ -122,30 +107,80 @@ pub fn expand_content_enum(input: EventEnumInput) -> syn::Result { } }; - let any_event_variant_impl = quote! { - impl #ident { - fn is_compatible(event_type: &str) -> bool { - match event_type { - #( #event_type_str => true, )* - _ => false, - } - } - } - }; - let marker_trait_impls = marker_traits(&ident); Ok(quote! { #content_enum - #any_event_variant_impl - #event_content_impl #marker_trait_impls }) } +fn expand_any_enum_with_deserialize( + input: &EventEnumInput, + ident: &Ident, +) -> syn::Result { + let attrs = &input.attrs; + let event_type_str = &input.events; + let event_struct = Ident::new(&ident.to_string().trim_start_matches("Any"), ident.span()); + + let variants = input.events.iter().map(to_camel_case).collect::>>()?; + let content = + input.events.iter().map(|event| to_event_path(event, &event_struct)).collect::>(); + + let any_enum = quote! { + #( #attrs )* + #[derive(Clone, Debug, ::serde::Serialize)] + #[serde(untagged)] + #[allow(clippy::large_enum_variant)] + pub enum #ident { + #( + #[doc = #event_type_str] + #variants(#content), + )* + /// An event not defined by the Matrix specification + Custom(::ruma_events::#event_struct<::ruma_events::custom::CustomEventContent>), + } + }; + + let event_deserialize_impl = quote! { + impl<'de> ::serde::de::Deserialize<'de> for #ident { + fn deserialize(deserializer: D) -> Result + where + D: ::serde::de::Deserializer<'de>, + { + use ::serde::de::Error as _; + + let json = Box::<::serde_json::value::RawValue>::deserialize(deserializer)?; + let ::ruma_events::EventDeHelper { ev_type, .. } = ::ruma_events::from_raw_json_value(&json)?; + match ev_type.as_str() { + #( + #event_type_str => { + let event = ::serde_json::from_str::<#content>(json.get()).map_err(D::Error::custom)?; + Ok(#ident::#variants(event)) + }, + )* + event => { + let event = + ::serde_json::from_str::<::ruma_events::#event_struct<::ruma_events::custom::CustomEventContent>>(json.get()) + .map_err(D::Error::custom)?; + + Ok(Self::Custom(event)) + }, + } + } + } + }; + + Ok(quote! { + #any_enum + + #event_deserialize_impl + }) +} + fn marker_traits(ident: &Ident) -> TokenStream { match ident.to_string().as_str() { "AnyStateEventContent" => quote! { @@ -166,7 +201,7 @@ fn marker_traits(ident: &Ident) -> TokenStream { } } -fn to_event_path(name: &LitStr) -> TokenStream { +fn to_event_path(name: &LitStr, struct_name: &Ident) -> TokenStream { let span = name.span(); let name = name.value(); @@ -180,10 +215,25 @@ fn to_event_path(name: &LitStr) -> TokenStream { .map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..]) .collect::(); - let content_str = Ident::new(&format!("{}Event", event), span); let path = path.iter().map(|s| Ident::new(s, span)); - quote! { - ::ruma_events::#( #path )::*::#content_str + + match struct_name.to_string().as_str() { + "MessageEvent" | "MessageEventStub" if *event_str == "m.room.redaction" => { + let redaction = if struct_name == "MessageEvent" { + quote! { RedactionEvent } + } else { + quote! { RedactionEventStub } + }; + quote! { ::ruma_events::room::redaction::#redaction } + } + "ToDeviceEvent" | "StateEventStub" | "StrippedStateEventStub" | "MessageEventStub" => { + let content = Ident::new(&format!("{}EventContent", event), span); + quote! { ::ruma_events::#struct_name<::ruma_events::#( #path )::*::#content> } + } + _ => { + let event_name = Ident::new(&format!("{}Event", event), span); + quote! { ::ruma_events::#( #path )::*::#event_name } + } } } @@ -253,18 +303,19 @@ pub struct EventEnumInput { impl Parse for EventEnumInput { fn parse(input: ParseStream<'_>) -> parse::Result { let attrs = input.call(Attribute::parse_outer)?; - // name field + // "name" field input.parse::()?; input.parse::()?; + // the name of our event enum let name: Ident = input.parse()?; input.parse::()?; - // events field + // "events" field input.parse::()?; input.parse::()?; - // an array of event names `["m.room.whatever"]` + // an array of event names `["m.room.whatever", ...]` let ev_array = input.parse::()?; let events = ev_array .elems diff --git a/ruma-events/src/enums.rs b/ruma-events/src/enums.rs index 2476cbe2..1269f0f4 100644 --- a/ruma-events/src/enums.rs +++ b/ruma-events/src/enums.rs @@ -1,14 +1,8 @@ use ruma_events_macros::event_enum; -use serde::{ - de::{self, Error}, - Serialize, -}; +use serde::{de, Serialize}; use serde_json::value::RawValue as RawJsonValue; -use crate::{ - event_kinds::{MessageEventStub, StateEventStub, StrippedStateEventStub}, - from_raw_json_value, EventDeHelper, -}; +use crate::{from_raw_json_value, EventDeHelper}; event_enum! { /// Any basic event. @@ -46,7 +40,6 @@ event_enum! { "m.room.message.feedback", "m.room.redaction", "m.sticker", - ] } @@ -66,7 +59,6 @@ event_enum! { "m.room.name", "m.room.pinned_events", "m.room.power_levels", - "m.room.redaction", "m.room.server_acl", "m.room.third_party_invite", "m.room.tombstone", @@ -92,16 +84,6 @@ event_enum! { ] } -/// Any message event stub (message event without a `room_id`, as returned in `/sync` responses) -pub type AnyMessageEventStub = MessageEventStub; - -/// Any state event stub (state event without a `room_id`, as returned in `/sync` responses) -pub type AnyStateEventStub = StateEventStub; - -/// Any stripped state event stub (stripped-down state event, as returned for rooms the user has -/// been invited to in `/sync` responses) -pub type AnyStrippedStateEventStub = StrippedStateEventStub; - /// Any event. #[derive(Clone, Debug, Serialize)] #[serde(untagged)] @@ -144,22 +126,18 @@ impl<'de> de::Deserialize<'de> for AnyEvent { D: de::Deserializer<'de>, { let json = Box::::deserialize(deserializer)?; - let EventDeHelper { ev_type } = from_raw_json_value(&json)?; + let EventDeHelper { state_key, event_id, room_id, .. } = from_raw_json_value(&json)?; - match ev_type.as_str() { - ev_type if AnyBasicEventContent::is_compatible(ev_type) => { - Ok(AnyEvent::Basic(from_raw_json_value(&json)?)) - } - ev_type if AnyEphemeralRoomEventContent::is_compatible(ev_type) => { - Ok(AnyEvent::Ephemeral(from_raw_json_value(&json)?)) - } - ev_type if AnyMessageEventContent::is_compatible(ev_type) => { - Ok(AnyEvent::Message(from_raw_json_value(&json)?)) - } - ev_type if AnyStateEventContent::is_compatible(ev_type) => { - Ok(AnyEvent::State(from_raw_json_value(&json)?)) - } - _ => Err(D::Error::custom(format!("event type `{}` is not a valid event", ev_type))), + // Determine whether the event is a state, message, ephemeral, or basic event + // based on the fields present. + if state_key.is_some() { + Ok(AnyEvent::State(from_raw_json_value(&json)?)) + } else if event_id.is_some() { + Ok(AnyEvent::Message(from_raw_json_value(&json)?)) + } else if room_id.is_some() { + Ok(AnyEvent::Ephemeral(from_raw_json_value(&json)?)) + } else { + Ok(AnyEvent::Basic(from_raw_json_value(&json)?)) } } } @@ -170,16 +148,12 @@ impl<'de> de::Deserialize<'de> for AnyRoomEvent { D: de::Deserializer<'de>, { let json = Box::::deserialize(deserializer)?; - let EventDeHelper { ev_type } = from_raw_json_value(&json)?; + let EventDeHelper { state_key, .. } = from_raw_json_value(&json)?; - match ev_type.as_str() { - ev_type if AnyMessageEventContent::is_compatible(ev_type) => { - Ok(AnyRoomEvent::Message(from_raw_json_value(&json)?)) - } - ev_type if AnyStateEventContent::is_compatible(ev_type) => { - Ok(AnyRoomEvent::State(from_raw_json_value(&json)?)) - } - _ => Err(D::Error::custom(format!("event type `{}` is not a valid event", ev_type))), + if state_key.is_some() { + Ok(AnyRoomEvent::State(from_raw_json_value(&json)?)) + } else { + Ok(AnyRoomEvent::Message(from_raw_json_value(&json)?)) } } } @@ -190,16 +164,12 @@ impl<'de> de::Deserialize<'de> for AnyRoomEventStub { D: de::Deserializer<'de>, { let json = Box::::deserialize(deserializer)?; - let EventDeHelper { ev_type } = from_raw_json_value(&json)?; + let EventDeHelper { state_key, .. } = from_raw_json_value(&json)?; - match ev_type.as_str() { - ev_type if AnyMessageEventContent::is_compatible(ev_type) => { - Ok(AnyRoomEventStub::Message(from_raw_json_value(&json)?)) - } - ev_type if AnyStateEventContent::is_compatible(ev_type) => { - Ok(AnyRoomEventStub::State(from_raw_json_value(&json)?)) - } - _ => Err(D::Error::custom(format!("event type `{}` is not a valid event", ev_type))), + if state_key.is_some() { + Ok(AnyRoomEventStub::State(from_raw_json_value(&json)?)) + } else { + Ok(AnyRoomEventStub::Message(from_raw_json_value(&json)?)) } } } diff --git a/ruma-events/src/lib.rs b/ruma-events/src/lib.rs index 6444b610..e0620757 100644 --- a/ruma-events/src/lib.rs +++ b/ruma-events/src/lib.rs @@ -120,7 +120,10 @@ use std::fmt::Debug; use js_int::Int; -use serde::{de, Deserialize, Serialize}; +use serde::{ + de::{self, IgnoredAny}, + Deserialize, Serialize, +}; use serde_json::value::RawValue as RawJsonValue; use self::room::redaction::RedactionEvent; @@ -234,12 +237,24 @@ pub trait MessageEventContent: RoomEventContent {} /// Marker trait for the content of a state event. pub trait StateEventContent: RoomEventContent {} -/// Helper struct to obtain the event type from a serde_json::value::RawValue. +/// Helper struct to determine the event kind from a serde_json::value::RawValue. #[doc(hidden)] #[derive(Debug, Deserialize)] pub struct EventDeHelper { + /// the Matrix event type string "m.room.whatever". #[serde(rename = "type")] pub ev_type: String, + + /// If `state_key` is present the event will be deserialized as a state event. + pub state_key: Option, + + /// If no `state_key` is found but an `event_id` is present the event + /// will be deserialized as a message event. + pub event_id: Option, + + /// If no `event_id` or `state_key` are found but a `room_id` is present + /// the event will be deserialized as a ephemeral event. + pub room_id: Option, } /// Helper function for serde_json::value::RawValue deserialization. diff --git a/ruma-events/src/room/redaction.rs b/ruma-events/src/room/redaction.rs index 7a4acd83..eaa7e581 100644 --- a/ruma-events/src/room/redaction.rs +++ b/ruma-events/src/room/redaction.rs @@ -64,6 +64,10 @@ pub struct RedactionEventContent { pub reason: Option, } +impl ruma_events::RoomEventContent for RedactionEventContent {} + +impl ruma_events::MessageEventContent for RedactionEventContent {} + #[cfg(test)] mod tests { use std::{ diff --git a/ruma-events/tests/custom.rs b/ruma-events/tests/custom.rs index ee24044e..e5d525ec 100644 --- a/ruma-events/tests/custom.rs +++ b/ruma-events/tests/custom.rs @@ -5,8 +5,9 @@ use std::{ use matches::assert_matches; use ruma_events::{ - custom::CustomEventContent, AnyMessageEvent, AnyStateEvent, AnyStateEventContent, EventJson, - MessageEvent, StateEvent, StateEventStub, UnsignedData, + custom::CustomEventContent, AnyMessageEvent, AnyMessageEventStub, AnyRoomEventStub, + AnyStateEvent, AnyStateEventContent, EventJson, MessageEvent, MessageEventStub, StateEvent, + StateEventStub, UnsignedData, }; use ruma_identifiers::{EventId, RoomId, UserId}; use serde_json::{ @@ -188,3 +189,50 @@ fn deserialize_custom_state_stub_event() { && !unsigned.is_empty() ); } + +#[test] +fn deserialize_custom_message_stub_event() { + let json_data = json!({ + "content": { + "m.relates_to": { + "event_id": "$MDitXXXXXX", + "key": "👍", + "rel_type": "m.annotation" + } + }, + "event_id": "$h29iv0s8:example.com", + "origin_server_ts": 10, + "room_id": "!room:room.com", + "sender": "@carl:example.com", + "type": "m.reaction", + "unsigned": { + "age": 85 + } + }); + + let expected_content = json!({ + "m.relates_to": { + "event_id": "$MDitXXXXXX", + "key": "👍", + "rel_type": "m.annotation" + } + }); + + assert_matches!( + from_json_value::(json_data) + .unwrap(), + AnyRoomEventStub::Message(AnyMessageEventStub::Custom(MessageEventStub { + content: CustomEventContent { + json, event_type, + }, + event_id, + origin_server_ts, + sender, + unsigned, + })) if json == expected_content && event_type == "m.reaction" + && event_id == EventId::try_from("$h29iv0s8:example.com").unwrap() + && origin_server_ts == UNIX_EPOCH + Duration::from_millis(10) + && sender == UserId::try_from("@carl:example.com").unwrap() + && !unsigned.is_empty() + ); +} diff --git a/ruma-events/tests/enums.rs b/ruma-events/tests/enums.rs index 50ce88c3..58b3f124 100644 --- a/ruma-events/tests/enums.rs +++ b/ruma-events/tests/enums.rs @@ -10,9 +10,8 @@ use ruma_events::{ message::{MessageEventContent, TextMessageEventContent}, power_levels::PowerLevelsEventContent, }, - AnyEvent, AnyMessageEvent, AnyMessageEventContent, AnyRoomEvent, AnyRoomEventStub, - AnyStateEvent, AnyStateEventContent, MessageEvent, MessageEventStub, StateEvent, - StateEventStub, + AnyEvent, AnyMessageEvent, AnyMessageEventStub, AnyRoomEvent, AnyRoomEventStub, AnyStateEvent, + AnyStateEventStub, MessageEvent, MessageEventStub, StateEvent, StateEventStub, }; fn message_event() -> JsonValue { @@ -120,12 +119,12 @@ fn power_event_stub_deserialization() { assert_matches!( from_json_value::(json_data), Ok(AnyRoomEventStub::State( - StateEventStub { - content: AnyStateEventContent::RoomPowerLevels(PowerLevelsEventContent { + AnyStateEventStub::RoomPowerLevels(StateEventStub { + content: PowerLevelsEventContent { ban, .. - }), + }, .. - } + }) )) if ban == js_int::Int::new(50).unwrap() ); @@ -138,14 +137,14 @@ fn message_event_stub_deserialization() { assert_matches!( from_json_value::(json_data), Ok(AnyRoomEventStub::Message( - MessageEventStub { - content: AnyMessageEventContent::RoomMessage(MessageEventContent::Text(TextMessageEventContent { + AnyMessageEventStub::RoomMessage(MessageEventStub { + content: MessageEventContent::Text(TextMessageEventContent { body, formatted: Some(formatted), relates_to: None, - })), + }), .. - } + }) )) if body == "baba" && formatted.body == "baba" ); @@ -158,12 +157,12 @@ fn aliases_event_stub_deserialization() { assert_matches!( from_json_value::(json_data), Ok(AnyRoomEventStub::State( - StateEventStub { - content: AnyStateEventContent::RoomAliases(AliasesEventContent { + AnyStateEventStub::RoomAliases(StateEventStub { + content: AliasesEventContent { aliases, - }), + }, .. - } + }) )) if aliases == vec![ RoomAliasId::try_from("#somewhere:localhost").unwrap() ] ); diff --git a/ruma-events/tests/redaction.rs b/ruma-events/tests/redaction.rs new file mode 100644 index 00000000..f6cd9cd7 --- /dev/null +++ b/ruma-events/tests/redaction.rs @@ -0,0 +1,73 @@ +use std::{ + convert::TryFrom, + time::{Duration, UNIX_EPOCH}, +}; + +use matches::assert_matches; +use ruma_events::{ + room::redaction::{RedactionEvent, RedactionEventContent}, + AnyMessageEvent, EventJson, UnsignedData, +}; +use ruma_identifiers::{EventId, RoomId, UserId}; +use serde_json::{ + from_value as from_json_value, json, to_value as to_json_value, Value as JsonValue, +}; + +fn redaction() -> JsonValue { + json!({ + "content": { + "reason": "being a turd" + }, + "redacts": "$nomore:example.com", + "event_id": "$h29iv0s8:example.com", + "sender": "@carl:example.com", + "origin_server_ts": 1, + "room_id": "!roomid:room.com", + "type": "m.room.redaction" + }) +} + +#[test] +fn serialize_redaction() { + let aliases_event = RedactionEvent { + content: RedactionEventContent { reason: Some("being a turd".to_string()) }, + redacts: EventId::try_from("$nomore:example.com").unwrap(), + event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(), + origin_server_ts: UNIX_EPOCH + Duration::from_millis(1), + room_id: RoomId::try_from("!roomid:room.com").unwrap(), + sender: UserId::try_from("@carl:example.com").unwrap(), + unsigned: UnsignedData::default(), + }; + + let actual = to_json_value(&aliases_event).unwrap(); + let expected = redaction(); + + assert_eq!(actual, expected); +} + +#[test] +fn deserialize_redaction() { + let json_data = redaction(); + + assert_matches!( + from_json_value::>(json_data) + .unwrap() + .deserialize() + .unwrap(), + AnyMessageEvent::RoomRedaction(RedactionEvent { + content: RedactionEventContent { reason: Some(reas) }, + redacts, + event_id, + origin_server_ts, + room_id, + sender, + unsigned, + }) if reas == "being a turd" + && event_id == EventId::try_from("$h29iv0s8:example.com").unwrap() + && redacts == EventId::try_from("$nomore:example.com").unwrap() + && origin_server_ts == UNIX_EPOCH + Duration::from_millis(1) + && room_id == RoomId::try_from("!roomid:room.com").unwrap() + && sender == UserId::try_from("@carl:example.com").unwrap() + && unsigned.is_empty() + ); +} diff --git a/ruma-events/tests/stripped.rs b/ruma-events/tests/stripped.rs index e98eb71d..5342159c 100644 --- a/ruma-events/tests/stripped.rs +++ b/ruma-events/tests/stripped.rs @@ -3,14 +3,14 @@ use std::convert::TryFrom; use js_int::uint; use ruma_events::{ room::{join_rules::JoinRule, topic::TopicEventContent}, - AnyStateEventContent, AnyStrippedStateEventStub, + AnyStateEventContent, AnyStrippedStateEventStub, StrippedStateEventStub, }; use ruma_identifiers::UserId; use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; #[test] -fn serialize_stripped_state_event() { - let event = AnyStrippedStateEventStub { +fn serialize_stripped_state_event_any_content() { + let event = StrippedStateEventStub { content: AnyStateEventContent::RoomTopic(TopicEventContent { topic: "Testing room".to_string(), }), @@ -30,6 +30,26 @@ fn serialize_stripped_state_event() { assert_eq!(to_json_value(&event).unwrap(), json_data); } +#[test] +fn serialize_stripped_state_event_any_event() { + let event = AnyStrippedStateEventStub::RoomTopic(StrippedStateEventStub { + content: TopicEventContent { topic: "Testing room".to_string() }, + state_key: "".to_string(), + sender: UserId::try_from("@example:localhost").unwrap(), + }); + + let json_data = json!({ + "content": { + "topic": "Testing room" + }, + "type": "m.room.topic", + "state_key": "", + "sender": "@example:localhost" + }); + + assert_eq!(to_json_value(&event).unwrap(), json_data); +} + #[test] fn deserialize_stripped_state_events() { let name_event = json!({ @@ -76,9 +96,9 @@ fn deserialize_stripped_state_events() { }); let event = from_json_value::(name_event).unwrap(); - match event.content { - AnyStateEventContent::RoomName(content) => { - assert_eq!(content.name(), Some("Ruma")); + match event { + AnyStrippedStateEventStub::RoomName(event) => { + assert_eq!(event.content.name(), Some("Ruma")); assert_eq!(event.state_key, ""); assert_eq!(event.sender.to_string(), "@example:localhost"); } @@ -86,9 +106,9 @@ fn deserialize_stripped_state_events() { } let event = from_json_value::(join_rules_event).unwrap(); - match event.content { - AnyStateEventContent::RoomJoinRules(content) => { - assert_eq!(content.join_rule, JoinRule::Public); + match event { + AnyStrippedStateEventStub::RoomJoinRules(event) => { + assert_eq!(event.content.join_rule, JoinRule::Public); assert_eq!(event.state_key, ""); assert_eq!(event.sender.to_string(), "@example:localhost"); } @@ -96,16 +116,16 @@ fn deserialize_stripped_state_events() { } let event = from_json_value::(avatar_event).unwrap(); - match event.content { - AnyStateEventContent::RoomAvatar(content) => { - let image_info = content.info.unwrap(); + match event { + AnyStrippedStateEventStub::RoomAvatar(event) => { + let image_info = event.content.info.unwrap(); assert_eq!(image_info.height.unwrap(), uint!(128)); assert_eq!(image_info.width.unwrap(), uint!(128)); assert_eq!(image_info.mimetype.unwrap(), "image/jpeg"); assert_eq!(image_info.size.unwrap(), uint!(1024)); assert_eq!(image_info.thumbnail_info.unwrap().size.unwrap(), uint!(32)); - assert_eq!(content.url, "https://example.com/image.jpg"); + assert_eq!(event.content.url, "https://example.com/image.jpg"); assert_eq!(event.state_key, ""); assert_eq!(event.sender.to_string(), "@example:localhost"); }