From c8a4bc799bec673802408bd23285f491b5385f22 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 21 Sep 2023 11:43:54 +0200 Subject: [PATCH] testing: Add sync_timeline_event macro for more type safety in tests --- .../matrix-sdk-ui/src/timeline/tests/basic.rs | 24 ++++---- .../matrix-sdk-ui/src/timeline/tests/echo.rs | 9 ++- .../matrix-sdk-ui/src/timeline/tests/edit.rs | 8 +-- .../src/timeline/tests/event_filter.rs | 7 +-- .../src/timeline/tests/invalid.rs | 9 ++- .../matrix-sdk-ui/src/timeline/tests/mod.rs | 55 ++++++++----------- .../matrix-sdk-ui/src/timeline/tests/polls.rs | 4 +- .../src/timeline/tests/reactions.rs | 10 ++-- .../src/timeline/tests/redaction.rs | 12 ++-- testing/matrix-sdk-test/src/lib.rs | 12 ++++ 10 files changed, 75 insertions(+), 75 deletions(-) diff --git a/crates/matrix-sdk-ui/src/timeline/tests/basic.rs b/crates/matrix-sdk-ui/src/timeline/tests/basic.rs index d352dedb1..ad9a92bc2 100644 --- a/crates/matrix-sdk-ui/src/timeline/tests/basic.rs +++ b/crates/matrix-sdk-ui/src/timeline/tests/basic.rs @@ -15,7 +15,8 @@ use assert_matches::assert_matches; use eyeball_im::VectorDiff; use imbl::vector; -use matrix_sdk_test::async_test; +use matrix_sdk_base::deserialized_responses::SyncTimelineEvent; +use matrix_sdk_test::{async_test, sync_timeline_event}; use ruma::{ assign, events::{ @@ -29,10 +30,9 @@ use ruma::{ FullStateEventContent, }, }; -use serde_json::json; use stream_assert::assert_next_matches; -use super::{sync_timeline_event, TestTimeline, ALICE, BOB}; +use super::{TestTimeline, ALICE, BOB}; use crate::timeline::{ event_item::AnyOtherFullStateEventContent, tests::CAROL, MembershipChange, TimelineDetails, TimelineItemContent, TimelineItemKind, VirtualTimelineItem, @@ -46,10 +46,10 @@ async fn initial_events() { timeline .inner .add_initial_events(vector![ - sync_timeline_event( + SyncTimelineEvent::new( timeline.make_message_event(*ALICE, RoomMessageEventContent::text_plain("A")), ), - sync_timeline_event( + SyncTimelineEvent::new( timeline.make_message_event(*BOB, RoomMessageEventContent::text_plain("B")), ), ]) @@ -69,7 +69,7 @@ async fn sticker() { let mut stream = timeline.subscribe_events().await; timeline - .handle_live_custom_event(json!({ + .handle_live_custom_event(sync_timeline_event!({ "content": { "body": "Happy sticker", "info": { @@ -195,7 +195,11 @@ async fn dedup_pagination() { let event = timeline.make_message_event(*ALICE, RoomMessageEventContent::text_plain("o/")); timeline.handle_live_custom_event(event.clone()).await; - timeline.handle_back_paginated_custom_event(event).await; + // This cast is not actually correct, sync events aren't valid + // back-paginated events, as they are missing `room_id`. However, the + // timeline doesn't care about that `room_id` and casts back to + // `Raw` before attempting to deserialize. + timeline.handle_back_paginated_custom_event(event.cast()).await; let timeline_items = timeline.inner.items().await; assert_eq!(timeline_items.len(), 2); @@ -210,13 +214,13 @@ async fn dedup_pagination() { async fn dedup_initial() { let mut timeline = TestTimeline::new(); - let event_a = sync_timeline_event( + let event_a = SyncTimelineEvent::new( timeline.make_message_event(*ALICE, RoomMessageEventContent::text_plain("A")), ); - let event_b = sync_timeline_event( + let event_b = SyncTimelineEvent::new( timeline.make_message_event(*BOB, RoomMessageEventContent::text_plain("B")), ); - let event_c = sync_timeline_event( + let event_c = SyncTimelineEvent::new( timeline.make_message_event(*CAROL, RoomMessageEventContent::text_plain("C")), ); diff --git a/crates/matrix-sdk-ui/src/timeline/tests/echo.rs b/crates/matrix-sdk-ui/src/timeline/tests/echo.rs index c089cff4b..0b5c3a6db 100644 --- a/crates/matrix-sdk-ui/src/timeline/tests/echo.rs +++ b/crates/matrix-sdk-ui/src/timeline/tests/echo.rs @@ -17,12 +17,11 @@ use std::{io, sync::Arc}; use assert_matches::assert_matches; use eyeball_im::VectorDiff; use matrix_sdk::Error; -use matrix_sdk_test::async_test; +use matrix_sdk_test::{async_test, sync_timeline_event}; use ruma::{ event_id, events::{room::message::RoomMessageEventContent, AnyMessageLikeEventContent}, }; -use serde_json::json; use stream_assert::assert_next_matches; use super::{TestTimeline, ALICE, BOB}; @@ -94,7 +93,7 @@ async fn remote_echo_full_trip() { // Now, a sync has been run against the server, and an event with the same ID // comes in. timeline - .handle_live_custom_event(json!({ + .handle_live_custom_event(sync_timeline_event!({ "content": { "body": "echo", "msgtype": "m.text", @@ -140,7 +139,7 @@ async fn remote_echo_new_position() { // When the remote echo comes in… timeline - .handle_live_custom_event(json!({ + .handle_live_custom_event(sync_timeline_event!({ "content": { "body": "echo", "msgtype": "m.text", @@ -190,7 +189,7 @@ async fn day_divider_duplication() { // … when the second remote event is re-received (day still the same) let event_id = items[2].as_event().unwrap().event_id().unwrap(); timeline - .handle_live_custom_event(json!({ + .handle_live_custom_event(sync_timeline_event!({ "content": { "body": "B", "msgtype": "m.text", diff --git a/crates/matrix-sdk-ui/src/timeline/tests/edit.rs b/crates/matrix-sdk-ui/src/timeline/tests/edit.rs index b506ca12f..ac475c3be 100644 --- a/crates/matrix-sdk-ui/src/timeline/tests/edit.rs +++ b/crates/matrix-sdk-ui/src/timeline/tests/edit.rs @@ -14,7 +14,7 @@ use assert_matches::assert_matches; use eyeball_im::VectorDiff; -use matrix_sdk_test::async_test; +use matrix_sdk_test::{async_test, sync_timeline_event}; use ruma::{ assign, events::{ @@ -23,10 +23,8 @@ use ruma::{ self, MessageType, RedactedRoomMessageEventContent, RoomMessageEventContent, }, }, - serde::Raw, server_name, EventId, }; -use serde_json::json; use stream_assert::assert_next_matches; use super::{TestTimeline, ALICE}; @@ -112,7 +110,7 @@ async fn aggregated_sanitized() { let mut stream = timeline.subscribe().await; let original_event_id = EventId::new(server_name!("dummy.server")); - let ev = json!({ + let ev = sync_timeline_event!({ "content": { "formatted_body": "original message", "format": "org.matrix.custom.html", @@ -150,7 +148,7 @@ async fn aggregated_sanitized() { } } }); - timeline.handle_live_event(Raw::new(&ev).unwrap().cast()).await; + timeline.handle_live_event(ev).await; let _day_divider = assert_next_matches!(stream, VectorDiff::PushBack { value } => value); let item = assert_next_matches!(stream, VectorDiff::PushBack { value } => value); diff --git a/crates/matrix-sdk-ui/src/timeline/tests/event_filter.rs b/crates/matrix-sdk-ui/src/timeline/tests/event_filter.rs index c75944f7c..f73c938ff 100644 --- a/crates/matrix-sdk-ui/src/timeline/tests/event_filter.rs +++ b/crates/matrix-sdk-ui/src/timeline/tests/event_filter.rs @@ -16,7 +16,7 @@ use std::sync::Arc; use assert_matches::assert_matches; use eyeball_im::VectorDiff; -use matrix_sdk_test::async_test; +use matrix_sdk_test::{async_test, sync_timeline_event}; use ruma::{ assign, events::{ @@ -32,7 +32,6 @@ use ruma::{ AnySyncTimelineEvent, }, }; -use serde_json::json; use stream_assert::assert_next_matches; use super::{TestTimeline, ALICE, BOB}; @@ -176,7 +175,7 @@ async fn hide_failed_to_parse() { // m.room.message events must have a msgtype and body in content, so this // event with an empty content object should fail to deserialize. timeline - .handle_live_custom_event(json!({ + .handle_live_custom_event(sync_timeline_event!({ "content": {}, "event_id": "$eeG0HA0FAZ37wP8kXlNkxx3I", "origin_server_ts": 10, @@ -188,7 +187,7 @@ async fn hide_failed_to_parse() { // Similar to above, the m.room.member state event must also not have an // empty content object. timeline - .handle_live_custom_event(json!({ + .handle_live_custom_event(sync_timeline_event!({ "content": {}, "event_id": "$d5G0HA0FAZ37wP8kXlNkxx3I", "origin_server_ts": 2179, diff --git a/crates/matrix-sdk-ui/src/timeline/tests/invalid.rs b/crates/matrix-sdk-ui/src/timeline/tests/invalid.rs index 5751d5bbe..6f61f447f 100644 --- a/crates/matrix-sdk-ui/src/timeline/tests/invalid.rs +++ b/crates/matrix-sdk-ui/src/timeline/tests/invalid.rs @@ -14,7 +14,7 @@ use assert_matches::assert_matches; use eyeball_im::VectorDiff; -use matrix_sdk_test::async_test; +use matrix_sdk_test::{async_test, sync_timeline_event}; use ruma::{ assign, events::{ @@ -24,7 +24,6 @@ use ruma::{ }, uint, MilliSecondsSinceUnixEpoch, }; -use serde_json::json; use stream_assert::assert_next_matches; use super::{TestTimeline, ALICE, BOB}; @@ -64,7 +63,7 @@ async fn invalid_event_content() { // m.room.message events must have a msgtype and body in content, so this // event with an empty content object should fail to deserialize. timeline - .handle_live_custom_event(json!({ + .handle_live_custom_event(sync_timeline_event!({ "content": {}, "event_id": "$eeG0HA0FAZ37wP8kXlNkxx3I", "origin_server_ts": 10, @@ -86,7 +85,7 @@ async fn invalid_event_content() { // Similar to above, the m.room.member state event must also not have an // empty content object. timeline - .handle_live_custom_event(json!({ + .handle_live_custom_event(sync_timeline_event!({ "content": {}, "event_id": "$d5G0HA0FAZ37wP8kXlNkxx3I", "origin_server_ts": 2179, @@ -119,7 +118,7 @@ async fn invalid_event() { // This event is missing the sender field which the homeserver must add to // all timeline events. Because the event is malformed, it will be ignored. timeline - .handle_live_custom_event(json!({ + .handle_live_custom_event(sync_timeline_event!({ "content": { "body": "hello world", "msgtype": "m.text" diff --git a/crates/matrix-sdk-ui/src/timeline/tests/mod.rs b/crates/matrix-sdk-ui/src/timeline/tests/mod.rs index 93efdaee1..a27f6c115 100644 --- a/crates/matrix-sdk-ui/src/timeline/tests/mod.rs +++ b/crates/matrix-sdk-ui/src/timeline/tests/mod.rs @@ -29,15 +29,16 @@ use futures_core::Stream; use futures_util::{FutureExt, StreamExt}; use indexmap::IndexMap; use matrix_sdk::deserialized_responses::{SyncTimelineEvent, TimelineEvent}; +use matrix_sdk_test::sync_timeline_event; use once_cell::sync::Lazy; use ruma::{ events::{ receipt::{Receipt, ReceiptEventContent, ReceiptThread, ReceiptType}, relation::Annotation, room::redaction::RoomRedactionEventContent, - AnyMessageLikeEventContent, AnySyncTimelineEvent, EmptyStateKey, MessageLikeEventContent, - RedactedMessageLikeEventContent, RedactedStateEventContent, StateEventContent, - StaticStateEventContent, + AnyMessageLikeEventContent, AnySyncTimelineEvent, AnyTimelineEvent, EmptyStateKey, + MessageLikeEventContent, RedactedMessageLikeEventContent, RedactedStateEventContent, + StateEventContent, StaticStateEventContent, }, int, power_levels::NotificationPowerLevels, @@ -75,11 +76,6 @@ static ALICE: Lazy<&UserId> = Lazy::new(|| user_id!("@alice:server.name")); static BOB: Lazy<&UserId> = Lazy::new(|| user_id!("@bob:other.server")); static CAROL: Lazy<&UserId> = Lazy::new(|| user_id!("@carol:other.server")); -fn sync_timeline_event(event: JsonValue) -> SyncTimelineEvent { - let event = serde_json::from_value(event).unwrap(); - SyncTimelineEvent { event, encryption_info: None, push_actions: Vec::default() } -} - struct TestTimeline { inner: TimelineInner, next_ts: AtomicU64, @@ -133,7 +129,7 @@ impl TestTimeline { C: StaticStateEventContent, { let ev = self.make_state_event(sender, "", content, prev_content); - self.handle_live_event(Raw::new(&ev).unwrap().cast()).await; + self.handle_live_event(ev).await; } async fn handle_live_state_event_with_state_key( @@ -169,13 +165,12 @@ impl TestTimeline { self.handle_live_event(Raw::new(&ev).unwrap().cast()).await; } - async fn handle_live_custom_event(&self, event: JsonValue) { - let raw = Raw::new(&event).unwrap().cast(); - self.handle_live_event(raw).await; + async fn handle_live_custom_event(&self, event: Raw) { + self.handle_live_event(event).await; } async fn handle_live_redaction(&self, sender: &UserId, redacts: &EventId) { - let ev = json!({ + let ev = sync_timeline_event!({ "type": "m.room.redaction", "content": {}, "redacts": redacts, @@ -183,13 +178,12 @@ impl TestTimeline { "sender": sender, "origin_server_ts": self.next_server_ts(), }); - let raw = Raw::new(&ev).unwrap().cast(); - self.handle_live_event(raw).await; + self.handle_live_event(ev).await; } async fn handle_live_reaction(&self, sender: &UserId, annotation: &Annotation) -> OwnedEventId { let event_id = EventId::new(server_name!("dummy.server")); - let ev = json!({ + let ev = sync_timeline_event!({ "type": "m.reaction", "content": { "m.relates_to": { @@ -202,8 +196,7 @@ impl TestTimeline { "sender": sender, "origin_server_ts": self.next_server_ts(), }); - let raw = Raw::new(&ev).unwrap().cast(); - self.handle_live_event(raw).await; + self.handle_live_event(ev).await; event_id } @@ -228,8 +221,8 @@ impl TestTimeline { txn_id } - async fn handle_back_paginated_custom_event(&self, event: JsonValue) { - let timeline_event = TimelineEvent::new(Raw::new(&event).unwrap().cast()); + async fn handle_back_paginated_custom_event(&self, event: Raw) { + let timeline_event = TimelineEvent::new(event.cast()); self.inner.handle_back_paginated_events(vec![timeline_event]).await; } @@ -267,7 +260,7 @@ impl TestTimeline { &self, sender: &UserId, content: C, - ) -> JsonValue { + ) -> Raw { self.make_message_event_with_id(sender, content, EventId::new(server_name!("dummy.server"))) } @@ -276,8 +269,8 @@ impl TestTimeline { sender: &UserId, content: C, event_id: OwnedEventId, - ) -> JsonValue { - json!({ + ) -> Raw { + sync_timeline_event!({ "type": content.event_type(), "content": content, "event_id": event_id, @@ -290,8 +283,8 @@ impl TestTimeline { &self, sender: &UserId, content: C, - ) -> JsonValue { - json!({ + ) -> Raw { + sync_timeline_event!({ "type": content.event_type(), "content": content, "event_id": EventId::new(server_name!("dummy.server")), @@ -307,14 +300,14 @@ impl TestTimeline { state_key: &str, content: C, prev_content: Option, - ) -> JsonValue { + ) -> Raw { let unsigned = if let Some(prev_content) = prev_content { json!({ "prev_content": prev_content }) } else { json!({}) }; - json!({ + sync_timeline_event!({ "type": content.event_type(), "state_key": state_key, "content": content, @@ -330,8 +323,8 @@ impl TestTimeline { sender: &UserId, state_key: &str, content: C, - ) -> JsonValue { - json!({ + ) -> Raw { + sync_timeline_event!({ "type": content.event_type(), "state_key": state_key, "content": content, @@ -359,8 +352,8 @@ impl TestTimeline { sender: &UserId, annotation: &Annotation, timestamp: MilliSecondsSinceUnixEpoch, - ) -> JsonValue { - json!({ + ) -> Raw { + sync_timeline_event!({ "event_id": EventId::new(server_name!("dummy.server")), "content": { "m.relates_to": { diff --git a/crates/matrix-sdk-ui/src/timeline/tests/polls.rs b/crates/matrix-sdk-ui/src/timeline/tests/polls.rs index 031147e97..0eb68d452 100644 --- a/crates/matrix-sdk-ui/src/timeline/tests/polls.rs +++ b/crates/matrix-sdk-ui/src/timeline/tests/polls.rs @@ -11,7 +11,6 @@ use ruma::{ }, AnyMessageLikeEventContent, }, - serde::Raw, server_name, EventId, OwnedEventId, UserId, }; @@ -217,8 +216,7 @@ impl TestTimeline { NewUnstablePollStartEventContent::new(content).into(), ); let event = self.make_message_event_with_id(sender, event_content, event_id.to_owned()); - let raw = Raw::new(&event).unwrap().cast(); - self.handle_live_event(raw).await; + self.handle_live_event(event).await; } async fn send_poll_response(&self, sender: &UserId, answers: Vec<&str>, poll_id: &EventId) { diff --git a/crates/matrix-sdk-ui/src/timeline/tests/reactions.rs b/crates/matrix-sdk-ui/src/timeline/tests/reactions.rs index f9efb1c39..f1b6d50fb 100644 --- a/crates/matrix-sdk-ui/src/timeline/tests/reactions.rs +++ b/crates/matrix-sdk-ui/src/timeline/tests/reactions.rs @@ -18,6 +18,7 @@ use assert_matches::assert_matches; use eyeball_im::VectorDiff; use futures_core::Stream; use imbl::vector; +use matrix_sdk_base::deserialized_responses::SyncTimelineEvent; use matrix_sdk_test::async_test; use ruma::{ events::{relation::Annotation, room::message::RoomMessageEventContent}, @@ -29,10 +30,7 @@ use crate::timeline::{ event_item::EventItemIdentifier, inner::ReactionAction, reactions::ReactionToggleResult, - tests::{ - assert_event_is_updated, assert_no_more_updates, sync_timeline_event, TestTimeline, ALICE, - BOB, - }, + tests::{assert_event_is_updated, assert_no_more_updates, TestTimeline, ALICE, BOB}, TimelineItem, }; @@ -249,12 +247,12 @@ async fn initial_reaction_timestamp_is_stored() { timeline .inner .add_initial_events(vector![ - sync_timeline_event(timeline.make_reaction( + SyncTimelineEvent::new(timeline.make_reaction( *ALICE, &Annotation::new(message_event_id.clone(), REACTION_KEY.to_owned()), reaction_timestamp )), - sync_timeline_event(timeline.make_message_event_with_id( + SyncTimelineEvent::new(timeline.make_message_event_with_id( *ALICE, RoomMessageEventContent::text_plain("A"), message_event_id diff --git a/crates/matrix-sdk-ui/src/timeline/tests/redaction.rs b/crates/matrix-sdk-ui/src/timeline/tests/redaction.rs index 66624789d..48b7b1509 100644 --- a/crates/matrix-sdk-ui/src/timeline/tests/redaction.rs +++ b/crates/matrix-sdk-ui/src/timeline/tests/redaction.rs @@ -15,7 +15,8 @@ use assert_matches::assert_matches; use eyeball_im::VectorDiff; use imbl::vector; -use matrix_sdk_test::async_test; +use matrix_sdk_base::deserialized_responses::SyncTimelineEvent; +use matrix_sdk_test::{async_test, sync_timeline_event}; use ruma::{ events::{ reaction::{ReactionEventContent, RedactedReactionEventContent}, @@ -31,10 +32,9 @@ use ruma::{ }, owned_room_id, }; -use serde_json::json; use stream_assert::assert_next_matches; -use super::{sync_timeline_event, TestTimeline, ALICE, BOB}; +use super::{TestTimeline, ALICE, BOB}; use crate::timeline::{AnyOtherFullStateEventContent, TimelineDetails, TimelineItemContent}; #[async_test] @@ -146,7 +146,7 @@ async fn reaction_redaction_timeline_filter() { // Initialise a timeline with a redacted reaction. timeline .inner - .add_initial_events(vector![sync_timeline_event( + .add_initial_events(vector![SyncTimelineEvent::new( timeline.make_redacted_message_event(*ALICE, RedactedReactionEventContent::new()) )]) .await; @@ -209,7 +209,7 @@ async fn receive_unredacted() { // send new events with the same event ID as the previous ones timeline - .handle_live_custom_event(json!({ + .handle_live_custom_event(sync_timeline_event!({ "content": { "body": "unredacted #1", "msgtype": "m.text", @@ -221,7 +221,7 @@ async fn receive_unredacted() { })) .await; timeline - .handle_live_custom_event(json!({ + .handle_live_custom_event(sync_timeline_event!({ "content": { "body": "unredacted #2", "msgtype": "m.text", diff --git a/testing/matrix-sdk-test/src/lib.rs b/testing/matrix-sdk-test/src/lib.rs index 95febe074..bd8ba4cc6 100644 --- a/testing/matrix-sdk-test/src/lib.rs +++ b/testing/matrix-sdk-test/src/lib.rs @@ -3,6 +3,18 @@ pub use matrix_sdk_test_macros::async_test; use ruma::api::{client::sync::sync_events::v3::Response as SyncResponse, IncomingResponse}; use serde_json::Value as JsonValue; +/// Create a `Raw` from arbitrary JSON. +/// +/// Forwards all arguments to [`serde_json::json`]. +#[macro_export] +macro_rules! sync_timeline_event { + ($( $tt:tt )*) => { + ::ruma::serde::Raw::new(&::serde_json::json!( $($tt)* )) + .unwrap() + .cast::<::ruma::events::AnySyncTimelineEvent>() + } +} + pub mod notification_settings; mod sync_builder; pub mod test_json;