From 0c6dd0ba327ec7fa4926b26995ed2168a3b3f51b Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Tue, 17 Mar 2020 13:10:40 +0100 Subject: [PATCH] Simplify proc_macro tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … by moving them from ruma-events-macros to ruma-events and updating the macros to work in different contexts (without items like FromRaw being available at the calling crate's root) --- ruma-events-macros/src/from_raw.rs | 6 +- ruma-events-macros/src/gen.rs | 14 +- ruma-events-macros/src/parse.rs | 4 +- src/lib.rs | 7 +- src/util.rs | 59 ++-- .../tests => tests}/ruma_events_macros.rs | 267 +----------------- 6 files changed, 47 insertions(+), 310 deletions(-) rename {ruma-events-macros/tests => tests}/ruma_events_macros.rs (52%) diff --git a/ruma-events-macros/src/from_raw.rs b/ruma-events-macros/src/from_raw.rs index b9a8eb99..f9f0d943 100644 --- a/ruma-events-macros/src/from_raw.rs +++ b/ruma-events-macros/src/from_raw.rs @@ -21,11 +21,11 @@ pub fn expand_from_raw(input: DeriveInput) -> syn::Result { if field_ident == "content" { quote_spanned! {field_span=> - content: crate::FromRaw::from_raw(raw.content), + content: ::ruma_events::FromRaw::from_raw(raw.content), } } else if field_ident == "prev_content" { quote_spanned! {field_span=> - prev_content: raw.prev_content.map(crate::FromRaw::from_raw), + prev_content: raw.prev_content.map(::ruma_events::FromRaw::from_raw), } } else { quote_spanned! {field_span=> @@ -35,7 +35,7 @@ pub fn expand_from_raw(input: DeriveInput) -> syn::Result { }); Ok(quote! { - impl crate::FromRaw for #ident { + impl ::ruma_events::FromRaw for #ident { type Raw = raw::#ident; fn from_raw(raw: raw::#ident) -> Self { diff --git a/ruma-events-macros/src/gen.rs b/ruma-events-macros/src/gen.rs index 12bb3b09..c365a034 100644 --- a/ruma-events-macros/src/gen.rs +++ b/ruma-events-macros/src/gen.rs @@ -92,7 +92,7 @@ impl ToTokens for RumaEvent { let event_type = if self.is_custom { quote! { - crate::EventType::Custom(self.event_type.clone()) + ::ruma_events::EventType::Custom(self.event_type.clone()) } } else { let event_type = &self.event_type; @@ -189,7 +189,7 @@ impl ToTokens for RumaEvent { }; let import_event_in_serialize_impl = quote! { - use crate::Event as _; + use ::ruma_events::Event as _; }; ( @@ -214,7 +214,7 @@ impl ToTokens for RumaEvent { let impl_room_event = match self.kind { EventKind::RoomEvent | EventKind::StateEvent => { quote! { - impl crate::RoomEvent for #name { + impl ::ruma_events::RoomEvent for #name { /// The unique identifier for the event. fn event_id(&self) -> &ruma_identifiers::EventId { &self.event_id @@ -251,7 +251,7 @@ impl ToTokens for RumaEvent { let impl_state_event = if self.kind == EventKind::StateEvent { quote! { - impl crate::StateEvent for #name { + impl ::ruma_events::StateEvent for #name { /// The previous content for this state key, if any. fn prev_content(&self) -> Option<&Self::Content> { self.prev_content.as_ref() @@ -284,7 +284,7 @@ impl ToTokens for RumaEvent { } quote! { - impl crate::FromRaw for #content_name { + impl ::ruma_events::FromRaw for #content_name { type Raw = raw::#content_name; fn from_raw( @@ -337,7 +337,7 @@ impl ToTokens for RumaEvent { } } - impl crate::Event for #name { + impl ::ruma_events::Event for #name { /// The type of this event's `content` field. type Content = #content_name; @@ -347,7 +347,7 @@ impl ToTokens for RumaEvent { } /// The type of the event. - fn event_type(&self) -> crate::EventType { + fn event_type(&self) -> ::ruma_events::EventType { #event_type } } diff --git a/ruma-events-macros/src/parse.rs b/ruma-events-macros/src/parse.rs index e2fb6ba5..868955bc 100644 --- a/ruma-events-macros/src/parse.rs +++ b/ruma-events-macros/src/parse.rs @@ -109,7 +109,7 @@ impl Parse for RumaEventInput { let mut punctuated = Punctuated::new(); punctuated.push(PathSegment { - ident: Ident::new("crate", Span::call_site()), + ident: Ident::new("ruma_events", Span::call_site()), arguments: PathArguments::None, }); punctuated.push(PathSegment { @@ -119,7 +119,7 @@ impl Parse for RumaEventInput { punctuated.push(variant.clone()); event_type = Some(Path { - leading_colon: None, + leading_colon: Some(Default::default()), segments: punctuated, }); } diff --git a/src/lib.rs b/src/lib.rs index f4d72d69..efc0722e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -135,7 +135,12 @@ mod macros; mod algorithm; mod event_type; mod from_raw; -mod util; +#[doc(hidden)] // only public for external tests +pub mod util; + +// Hack to allow both ruma-events itself and external crates (or tests) to use procedural macros +// that expect `ruma_events` to exist in the prelude. +extern crate self as ruma_events; pub mod call; /// Enums for heterogeneous collections of events. diff --git a/src/util.rs b/src/util.rs index f3bf3a88..5a6e8494 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,7 +1,12 @@ -use serde::de::{Deserialize, DeserializeOwned, IntoDeserializer}; +use std::fmt::Debug; + +use serde::{ + de::{Deserialize, DeserializeOwned, IntoDeserializer}, + Serialize, +}; use serde_json::Value; -use crate::TryFromRaw; +use crate::{EventResult, TryFromRaw}; pub fn try_convert_variant( variant: fn(Content) -> Enum, @@ -107,35 +112,25 @@ pub fn default_true() -> bool { } #[cfg(test)] -mod test_util { - use std::fmt::Debug; - - use serde::{de::DeserializeOwned, Serialize}; - - use crate::{EventResult, TryFromRaw}; - - pub fn serde_json_eq(de: T, se: serde_json::Value) - where - T: Clone + Debug + PartialEq + Serialize + DeserializeOwned, - { - assert_eq!(se, serde_json::to_value(de.clone()).unwrap()); - assert_eq!(de, serde_json::from_value(se).unwrap()); - } - - pub fn serde_json_eq_try_from_raw(de: T, se: serde_json::Value) - where - T: Clone + Debug + PartialEq + Serialize + TryFromRaw, - { - assert_eq!(se, serde_json::to_value(de.clone()).unwrap()); - assert_eq!( - de, - serde_json::from_value::>(se) - .unwrap() - .into_result() - .unwrap() - ); - } +pub fn serde_json_eq(de: T, se: serde_json::Value) +where + T: Clone + Debug + PartialEq + Serialize + DeserializeOwned, +{ + assert_eq!(se, serde_json::to_value(de.clone()).unwrap()); + assert_eq!(de, serde_json::from_value(se).unwrap()); } -#[cfg(test)] -pub use test_util::*; +// This would be #[cfg(test)] if it wasn't used from external tests +pub fn serde_json_eq_try_from_raw(de: T, se: serde_json::Value) +where + T: Clone + Debug + PartialEq + Serialize + TryFromRaw, +{ + assert_eq!(se, serde_json::to_value(de.clone()).unwrap()); + assert_eq!( + de, + serde_json::from_value::>(se) + .unwrap() + .into_result() + .unwrap() + ); +} diff --git a/ruma-events-macros/tests/ruma_events_macros.rs b/tests/ruma_events_macros.rs similarity index 52% rename from ruma-events-macros/tests/ruma_events_macros.rs rename to tests/ruma_events_macros.rs index bc486f3e..b5b95645 100644 --- a/ruma-events-macros/tests/ruma_events_macros.rs +++ b/tests/ruma_events_macros.rs @@ -1,274 +1,11 @@ -use std::{ - borrow::Cow, - collections::HashMap, - convert::{Infallible, TryFrom}, - fmt::{Debug, Display, Formatter, Result as FmtResult}, -}; +use std::{collections::HashMap, convert::TryFrom}; use js_int::UInt; +use ruma_events::util::serde_json_eq_try_from_raw; use ruma_events_macros::ruma_event; use ruma_identifiers::{EventId, RoomAliasId, RoomId, UserId}; -use serde::{de::DeserializeOwned, Deserialize, Deserializer, Serialize}; use serde_json::{json, Value}; -/// The type of an event. -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -// Cow because deserialization sometimes needs to copy to unescape things -#[serde(from = "Cow<'_, str>", into = "String")] -pub enum EventType { - /// m.direct - Direct, - - /// m.room.aliases - RoomAliases, - - /// m.room.redaction - RoomRedaction, - - /// Any event that is not part of the specification. - Custom(String), -} - -impl Display for EventType { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - let event_type_str = match *self { - EventType::Direct => "m.direct", - EventType::RoomAliases => "m.room.aliases", - EventType::RoomRedaction => "m.room.redaction", - EventType::Custom(ref event_type) => event_type, - }; - - write!(f, "{}", event_type_str) - } -} - -impl<'a> From> for EventType { - fn from(s: Cow<'a, str>) -> EventType { - match &s as &str { - "m.direct" => EventType::Direct, - "m.room.aliases" => EventType::RoomAliases, - "m.room.redaction" => EventType::RoomRedaction, - _ => EventType::Custom(s.into_owned()), - } - } -} - -impl From<&str> for EventType { - fn from(s: &str) -> EventType { - EventType::from(Cow::Borrowed(s)) - } -} - -impl From for String { - fn from(event_type: EventType) -> String { - event_type.to_string() - } -} - -/// The result of deserializing an event, which may or may not be valid. -#[derive(Debug)] -pub enum EventResult { - /// `T` deserialized and validated successfully. - Ok(T), - - /// `T` deserialized but was invalid. - /// - /// `InvalidEvent` contains the original input. - Err(InvalidEvent), -} - -impl EventResult { - /// Convert `EventResult` into the equivalent `std::result::Result`. - pub fn into_result(self) -> Result { - match self { - EventResult::Ok(t) => Ok(t), - EventResult::Err(invalid_event) => Err(invalid_event), - } - } -} - -/// Marks types that can be deserialized as EventResult (and don't need fallible conversion -/// from their raw type) -pub trait FromRaw: Sized { - /// The raw form of this event that deserialization falls back to if deserializing `Self` fails. - type Raw: DeserializeOwned; - - fn from_raw(_: Self::Raw) -> Self; -} - -pub trait TryFromRaw: Sized { - /// The raw form of this event that deserialization falls back to if deserializing `Self` fails. - type Raw: DeserializeOwned; - type Err: Display; - - fn try_from_raw(_: Self::Raw) -> Result; -} - -impl FromRaw for serde_json::Value { - type Raw = Self; - - fn from_raw(raw: Self) -> Self { - raw - } -} - -impl FromRaw for HashMap -where - Self: DeserializeOwned, -{ - type Raw = Self; - - fn from_raw(raw: Self) -> Self { - raw - } -} - -impl TryFromRaw for T { - type Raw = ::Raw; - type Err = Infallible; - - fn try_from_raw(raw: Self::Raw) -> Result { - Ok(Self::from_raw(raw)) - } -} - -impl<'de, T> Deserialize<'de> for EventResult -where - T: TryFromRaw, -{ - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let json = serde_json::Value::deserialize(deserializer)?; - - let raw_data: T::Raw = match serde_json::from_value(json.clone()) { - Ok(raw) => raw, - Err(error) => { - return Ok(EventResult::Err(InvalidEvent { - json, - message: error.to_string(), - kind: InvalidEventKind::Deserialization, - })); - } - }; - - match T::try_from_raw(raw_data) { - Ok(value) => Ok(EventResult::Ok(value)), - Err(err) => Ok(EventResult::Err(InvalidEvent { - message: err.to_string(), - json, - kind: InvalidEventKind::Validation, - })), - } - } -} - -/// A basic event. -pub trait Event: Debug + Serialize + TryFromRaw { - /// The type of this event's `content` field. - type Content: Debug + Serialize; - - /// The event's content. - fn content(&self) -> &Self::Content; - - /// The type of the event. - fn event_type(&self) -> EventType; -} - -/// An event within the context of a room. -pub trait RoomEvent: Event { - /// The unique identifier for the event. - fn event_id(&self) -> &ruma_identifiers::EventId; - - /// Timestamp (milliseconds since the UNIX epoch) on originating homeserver when this event was - /// sent. - fn origin_server_ts(&self) -> js_int::UInt; - - /// The unique identifier for the room associated with this event. - /// - /// This can be `None` if the event came from a context where there is - /// no ambiguity which room it belongs to, like a `/sync` response for example. - fn room_id(&self) -> Option<&ruma_identifiers::RoomId>; - - /// The unique identifier for the user who sent this event. - fn sender(&self) -> &ruma_identifiers::UserId; - - /// Additional key-value pairs not signed by the homeserver. - fn unsigned(&self) -> Option<&serde_json::Value>; -} - -/// An event that describes persistent state about a room. -pub trait StateEvent: RoomEvent { - /// The previous content for this state key, if any. - fn prev_content(&self) -> Option<&Self::Content>; - - /// A key that determines which piece of room state the event represents. - fn state_key(&self) -> &str; -} - -/// An event that is malformed or otherwise invalid. -/// -/// When attempting to deserialize an `EventResult`, an error in the input data may cause -/// deserialization to fail, or the JSON structure may be correct, but additional constraints -/// defined in the matrix specification are not upheld. This type provides an error message and a -/// `serde_json::Value` representation of the invalid event, as well as a flag for which type of -/// error was encountered. -#[derive(Clone, Debug)] -pub struct InvalidEvent { - message: String, - json: Value, - kind: InvalidEventKind, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -enum InvalidEventKind { - Deserialization, - Validation, -} - -impl InvalidEvent { - /// A message describing why the event is invalid. - pub fn message(&self) -> String { - self.message.clone() - } - - /// The `serde_json::Value` representation of the invalid event. - pub fn json(&self) -> &Value { - &self.json - } - - /// Returns whether this is a deserialization error. - pub fn is_deserialization(&self) -> bool { - self.kind == InvalidEventKind::Deserialization - } - - /// Returns whether this is a validation error. - pub fn is_validation(&self) -> bool { - self.kind == InvalidEventKind::Validation - } -} - -impl Display for InvalidEvent { - fn fmt(&self, f: &mut Formatter) -> FmtResult { - write!(f, "{}", self.message()) - } -} - -pub fn serde_json_eq_try_from_raw(de: T, se: serde_json::Value) -where - T: Clone + Debug + PartialEq + Serialize + TryFromRaw, -{ - assert_eq!(se, serde_json::to_value(de.clone()).unwrap()); - assert_eq!( - de, - serde_json::from_value::>(se) - .unwrap() - .into_result() - .unwrap() - ); -} - // See note about wrapping macro expansion in a module from `src/lib.rs` mod common_case { use super::*;