test: get rid of EventBuilder (#4560)
This gets rid of `EventBuilder`, and makes more usage of the `EventFactory`, which is more ergonomic to create test events. A large part of https://github.com/matrix-org/matrix-rust-sdk/issues/3716.
This commit is contained in:
@@ -1,23 +1,20 @@
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
|
||||
use matrix_sdk::{
|
||||
config::SyncSettings, test_utils::logged_in_client_with_server, utils::IntoRawStateEventContent,
|
||||
};
|
||||
use matrix_sdk::{config::SyncSettings, test_utils::logged_in_client_with_server};
|
||||
use matrix_sdk_base::{
|
||||
store::StoreConfig, BaseClient, RoomInfo, RoomState, SessionMeta, StateChanges, StateStore,
|
||||
};
|
||||
use matrix_sdk_sqlite::SqliteStateStore;
|
||||
use matrix_sdk_test::{
|
||||
event_factory::EventFactory, EventBuilder, JoinedRoomBuilder, StateTestEvent,
|
||||
SyncResponseBuilder,
|
||||
event_factory::EventFactory, JoinedRoomBuilder, StateTestEvent, SyncResponseBuilder,
|
||||
};
|
||||
use matrix_sdk_ui::{timeline::TimelineFocus, Timeline};
|
||||
use ruma::{
|
||||
api::client::membership::get_member_events,
|
||||
device_id,
|
||||
events::room::member::{RoomMemberEvent, RoomMemberEventContent},
|
||||
owned_room_id, owned_user_id,
|
||||
events::room::member::{MembershipState, RoomMemberEvent},
|
||||
mxc_uri, owned_room_id, owned_user_id,
|
||||
serde::Raw,
|
||||
user_id, EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedUserId,
|
||||
};
|
||||
@@ -35,28 +32,17 @@ pub fn receive_all_members_benchmark(c: &mut Criterion) {
|
||||
let runtime = Builder::new_multi_thread().build().expect("Can't create runtime");
|
||||
let room_id = owned_room_id!("!room:example.com");
|
||||
|
||||
let ev_builder = EventBuilder::new();
|
||||
let f = EventFactory::new().room(&room_id);
|
||||
let mut member_events: Vec<Raw<RoomMemberEvent>> = Vec::with_capacity(MEMBERS_IN_ROOM);
|
||||
let member_content_json = json!({
|
||||
"avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF",
|
||||
"displayname": "Alice Margatroid",
|
||||
"membership": "join",
|
||||
"reason": "Looking for support",
|
||||
});
|
||||
let member_content: Raw<RoomMemberEventContent> =
|
||||
member_content_json.into_raw_state_event_content().cast();
|
||||
for i in 0..MEMBERS_IN_ROOM {
|
||||
let user_id = OwnedUserId::try_from(format!("@user_{}:matrix.org", i)).unwrap();
|
||||
let state_key = user_id.to_string();
|
||||
let event: Raw<RoomMemberEvent> = ev_builder
|
||||
.make_state_event(
|
||||
&user_id,
|
||||
&room_id,
|
||||
&state_key,
|
||||
member_content.deserialize().unwrap(),
|
||||
None,
|
||||
)
|
||||
.cast();
|
||||
let event = f
|
||||
.member(&user_id)
|
||||
.membership(MembershipState::Join)
|
||||
.avatar_url(mxc_uri!("mxc://example.org/SEsfnsuifSDFSSEF"))
|
||||
.display_name("Alice Margatroid")
|
||||
.reason("Looking for support")
|
||||
.into_raw();
|
||||
member_events.push(event);
|
||||
}
|
||||
|
||||
|
||||
@@ -621,7 +621,7 @@ mod tests {
|
||||
|
||||
use eyeball_im::Vector;
|
||||
use matrix_sdk_common::{deserialized_responses::SyncTimelineEvent, ring_buffer::RingBuffer};
|
||||
use matrix_sdk_test::{sync_timeline_event, EventBuilder};
|
||||
use matrix_sdk_test::{event_factory::EventFactory, sync_timeline_event};
|
||||
use ruma::{
|
||||
event_id,
|
||||
events::receipt::{ReceiptThread, ReceiptType},
|
||||
@@ -975,12 +975,12 @@ mod tests {
|
||||
let ev1 = sync_timeline_message(other_user_id, receipt_event_id, "A");
|
||||
let ev2 = sync_timeline_message(other_user_id, "$2", "A");
|
||||
|
||||
let receipt_event = EventBuilder::new().make_receipt_event_content([(
|
||||
receipt_event_id.to_owned(),
|
||||
ReceiptType::Read,
|
||||
user_id.to_owned(),
|
||||
ReceiptThread::Unthreaded,
|
||||
)]);
|
||||
let f = EventFactory::new();
|
||||
|
||||
let receipt_event = f
|
||||
.read_receipts()
|
||||
.add(receipt_event_id, user_id, ReceiptType::Read, ReceiptThread::Unthreaded)
|
||||
.build();
|
||||
|
||||
let mut read_receipts = Default::default();
|
||||
compute_unread_counts(
|
||||
@@ -1035,30 +1035,32 @@ mod tests {
|
||||
|
||||
// Given a receipt event marking events 1-3 as read using a combination of
|
||||
// different thread and privacy types,
|
||||
let f = EventFactory::new();
|
||||
for receipt_type_1 in &[ReceiptType::Read, ReceiptType::ReadPrivate] {
|
||||
for receipt_thread_1 in &[ReceiptThread::Unthreaded, ReceiptThread::Main] {
|
||||
for receipt_type_2 in &[ReceiptType::Read, ReceiptType::ReadPrivate] {
|
||||
for receipt_thread_2 in &[ReceiptThread::Unthreaded, ReceiptThread::Main] {
|
||||
let receipt_event = EventBuilder::new().make_receipt_event_content([
|
||||
(
|
||||
owned_event_id!("$2"),
|
||||
let receipt_event = f
|
||||
.read_receipts()
|
||||
.add(
|
||||
event_id!("$2"),
|
||||
user_id,
|
||||
receipt_type_1.clone(),
|
||||
user_id.to_owned(),
|
||||
receipt_thread_1.clone(),
|
||||
),
|
||||
(
|
||||
owned_event_id!("$3"),
|
||||
)
|
||||
.add(
|
||||
event_id!("$3"),
|
||||
user_id,
|
||||
receipt_type_2.clone(),
|
||||
user_id.to_owned(),
|
||||
receipt_thread_2.clone(),
|
||||
),
|
||||
(
|
||||
owned_event_id!("$1"),
|
||||
)
|
||||
.add(
|
||||
event_id!("$1"),
|
||||
user_id,
|
||||
receipt_type_1.clone(),
|
||||
user_id.to_owned(),
|
||||
receipt_thread_2.clone(),
|
||||
),
|
||||
]);
|
||||
)
|
||||
.build();
|
||||
|
||||
// When I compute the notifications for this room (with no new events),
|
||||
let mut read_receipts = RoomReadReceipts::default();
|
||||
@@ -1118,12 +1120,11 @@ mod tests {
|
||||
|
||||
let events = make_test_events(user_id!("@bob:example.org"));
|
||||
|
||||
let receipt_event = EventBuilder::new().make_receipt_event_content([(
|
||||
owned_event_id!("$6"),
|
||||
ReceiptType::Read,
|
||||
user_id.clone(),
|
||||
ReceiptThread::Unthreaded,
|
||||
)]);
|
||||
let f = EventFactory::new();
|
||||
let receipt_event = f
|
||||
.read_receipts()
|
||||
.add(event_id!("$6"), &user_id, ReceiptType::Read, ReceiptThread::Unthreaded)
|
||||
.build();
|
||||
|
||||
let mut read_receipts = RoomReadReceipts::default();
|
||||
assert!(read_receipts.pending.is_empty());
|
||||
@@ -1154,12 +1155,11 @@ mod tests {
|
||||
|
||||
let events = make_test_events(user_id!("@bob:example.org"));
|
||||
|
||||
let receipt_event = EventBuilder::new().make_receipt_event_content([(
|
||||
owned_event_id!("$1"),
|
||||
ReceiptType::Read,
|
||||
user_id.clone(),
|
||||
ReceiptThread::Unthreaded,
|
||||
)]);
|
||||
let f = EventFactory::new();
|
||||
let receipt_event = f
|
||||
.read_receipts()
|
||||
.add(event_id!("$1"), &user_id, ReceiptType::Read, ReceiptThread::Unthreaded)
|
||||
.build();
|
||||
|
||||
// Sync with a read receipt *and* a single event that was already known: in that
|
||||
// case, only consider the new events in isolation, and compute the
|
||||
@@ -1412,21 +1412,25 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_receipt_selector_handle_new_receipt() {
|
||||
let myself = owned_user_id!("@alice:example.org");
|
||||
let myself = user_id!("@alice:example.org");
|
||||
let events = make_test_events(user_id!("@bob:example.org"));
|
||||
|
||||
let f = EventFactory::new();
|
||||
{
|
||||
// Thread receipts are ignored.
|
||||
let mut selector = ReceiptSelector::new(&events, None);
|
||||
|
||||
let receipt_event = EventBuilder::new().make_receipt_event_content([(
|
||||
owned_event_id!("$5"),
|
||||
ReceiptType::Read,
|
||||
myself.clone(),
|
||||
ReceiptThread::Thread(owned_event_id!("$2")),
|
||||
)]);
|
||||
let receipt_event = f
|
||||
.read_receipts()
|
||||
.add(
|
||||
event_id!("$5"),
|
||||
myself,
|
||||
ReceiptType::Read,
|
||||
ReceiptThread::Thread(owned_event_id!("$2")),
|
||||
)
|
||||
.build();
|
||||
|
||||
let pending = selector.handle_new_receipt(&myself, &receipt_event);
|
||||
let pending = selector.handle_new_receipt(myself, &receipt_event);
|
||||
assert!(pending.is_empty());
|
||||
|
||||
let best_receipt = selector.select();
|
||||
@@ -1440,14 +1444,12 @@ mod tests {
|
||||
// receipt.
|
||||
let mut selector = ReceiptSelector::new(&events, None);
|
||||
|
||||
let receipt_event = EventBuilder::new().make_receipt_event_content([(
|
||||
owned_event_id!("$6"),
|
||||
receipt_type.clone(),
|
||||
myself.clone(),
|
||||
receipt_thread.clone(),
|
||||
)]);
|
||||
let receipt_event = f
|
||||
.read_receipts()
|
||||
.add(event_id!("$6"), myself, receipt_type.clone(), receipt_thread.clone())
|
||||
.build();
|
||||
|
||||
let pending = selector.handle_new_receipt(&myself, &receipt_event);
|
||||
let pending = selector.handle_new_receipt(myself, &receipt_event);
|
||||
assert_eq!(pending[0], event_id!("$6"));
|
||||
assert_eq!(pending.len(), 1);
|
||||
|
||||
@@ -1460,14 +1462,12 @@ mod tests {
|
||||
// receipt.
|
||||
let mut selector = ReceiptSelector::new(&events, None);
|
||||
|
||||
let receipt_event = EventBuilder::new().make_receipt_event_content([(
|
||||
owned_event_id!("$3"),
|
||||
receipt_type.clone(),
|
||||
myself.clone(),
|
||||
receipt_thread.clone(),
|
||||
)]);
|
||||
let receipt_event = f
|
||||
.read_receipts()
|
||||
.add(event_id!("$3"), myself, receipt_type.clone(), receipt_thread.clone())
|
||||
.build();
|
||||
|
||||
let pending = selector.handle_new_receipt(&myself, &receipt_event);
|
||||
let pending = selector.handle_new_receipt(myself, &receipt_event);
|
||||
assert!(pending.is_empty());
|
||||
|
||||
let best_receipt = selector.select();
|
||||
@@ -1479,14 +1479,12 @@ mod tests {
|
||||
// better receipt.
|
||||
let mut selector = ReceiptSelector::new(&events, Some(event_id!("$4")));
|
||||
|
||||
let receipt_event = EventBuilder::new().make_receipt_event_content([(
|
||||
owned_event_id!("$3"),
|
||||
receipt_type.clone(),
|
||||
myself.clone(),
|
||||
receipt_thread.clone(),
|
||||
)]);
|
||||
let receipt_event = f
|
||||
.read_receipts()
|
||||
.add(event_id!("$3"), myself, receipt_type.clone(), receipt_thread.clone())
|
||||
.build();
|
||||
|
||||
let pending = selector.handle_new_receipt(&myself, &receipt_event);
|
||||
let pending = selector.handle_new_receipt(myself, &receipt_event);
|
||||
assert!(pending.is_empty());
|
||||
|
||||
let best_receipt = selector.select();
|
||||
@@ -1498,14 +1496,12 @@ mod tests {
|
||||
// new better receipt.
|
||||
let mut selector = ReceiptSelector::new(&events, Some(event_id!("$2")));
|
||||
|
||||
let receipt_event = EventBuilder::new().make_receipt_event_content([(
|
||||
owned_event_id!("$3"),
|
||||
receipt_type.clone(),
|
||||
myself.clone(),
|
||||
receipt_thread.clone(),
|
||||
)]);
|
||||
let receipt_event = f
|
||||
.read_receipts()
|
||||
.add(event_id!("$3"), myself, receipt_type.clone(), receipt_thread.clone())
|
||||
.build();
|
||||
|
||||
let pending = selector.handle_new_receipt(&myself, &receipt_event);
|
||||
let pending = selector.handle_new_receipt(myself, &receipt_event);
|
||||
assert!(pending.is_empty());
|
||||
|
||||
let best_receipt = selector.select();
|
||||
@@ -1519,23 +1515,14 @@ mod tests {
|
||||
// new better receipt.
|
||||
let mut selector = ReceiptSelector::new(&events, Some(event_id!("$2")));
|
||||
|
||||
let receipt_event = EventBuilder::new().make_receipt_event_content([
|
||||
(
|
||||
owned_event_id!("$4"),
|
||||
ReceiptType::ReadPrivate,
|
||||
myself.clone(),
|
||||
ReceiptThread::Unthreaded,
|
||||
),
|
||||
(
|
||||
owned_event_id!("$6"),
|
||||
ReceiptType::ReadPrivate,
|
||||
myself.clone(),
|
||||
ReceiptThread::Main,
|
||||
),
|
||||
(owned_event_id!("$3"), ReceiptType::Read, myself.clone(), ReceiptThread::Main),
|
||||
]);
|
||||
let receipt_event = f
|
||||
.read_receipts()
|
||||
.add(event_id!("$4"), myself, ReceiptType::ReadPrivate, ReceiptThread::Unthreaded)
|
||||
.add(event_id!("$6"), myself, ReceiptType::ReadPrivate, ReceiptThread::Main)
|
||||
.add(event_id!("$3"), myself, ReceiptType::Read, ReceiptThread::Main)
|
||||
.build();
|
||||
|
||||
let pending = selector.handle_new_receipt(&myself, &receipt_event);
|
||||
let pending = selector.handle_new_receipt(myself, &receipt_event);
|
||||
assert_eq!(pending.len(), 1);
|
||||
assert_eq!(pending[0], event_id!("$6"));
|
||||
|
||||
@@ -1573,7 +1560,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_compute_unread_counts_with_implicit_receipt() {
|
||||
let user_id = owned_user_id!("@alice:example.org");
|
||||
let user_id = user_id!("@alice:example.org");
|
||||
let bob = user_id!("@bob:example.org");
|
||||
let room_id = room_id!("!room:example.org");
|
||||
|
||||
@@ -1581,7 +1568,7 @@ mod tests {
|
||||
let mut events = make_test_events(bob);
|
||||
|
||||
// One by me,
|
||||
events.push_back(sync_timeline_message(&user_id, "$6", "A mulatto, an albino"));
|
||||
events.push_back(sync_timeline_message(user_id, "$6", "A mulatto, an albino"));
|
||||
|
||||
// And others by Bob,
|
||||
events.push_back(sync_timeline_message(bob, "$7", "A mosquito, my libido"));
|
||||
@@ -1590,19 +1577,18 @@ mod tests {
|
||||
let events: Vec<_> = events.into_iter().collect();
|
||||
|
||||
// I have a read receipt attached to one of Bob's event sent before my message,
|
||||
let receipt_event = EventBuilder::new().make_receipt_event_content([(
|
||||
owned_event_id!("$3"),
|
||||
ReceiptType::Read,
|
||||
user_id.clone(),
|
||||
ReceiptThread::Unthreaded,
|
||||
)]);
|
||||
let f = EventFactory::new();
|
||||
let receipt_event = f
|
||||
.read_receipts()
|
||||
.add(event_id!("$3"), user_id, ReceiptType::Read, ReceiptThread::Unthreaded)
|
||||
.build();
|
||||
|
||||
let mut read_receipts = RoomReadReceipts::default();
|
||||
|
||||
// And I compute the unread counts for all those new events (no previous events
|
||||
// in that room),
|
||||
compute_unread_counts(
|
||||
&user_id,
|
||||
user_id,
|
||||
room_id,
|
||||
Some(&receipt_event),
|
||||
Vector::new(),
|
||||
|
||||
@@ -17,19 +17,20 @@ use assert_matches2::assert_let;
|
||||
use eyeball_im::VectorDiff;
|
||||
use futures_util::StreamExt;
|
||||
use matrix_sdk::deserialized_responses::SyncTimelineEvent;
|
||||
use matrix_sdk_test::{async_test, sync_timeline_event, ALICE, BOB, CAROL};
|
||||
use matrix_sdk_test::{
|
||||
async_test, event_factory::PreviousMembership, sync_timeline_event, ALICE, BOB, CAROL,
|
||||
};
|
||||
use ruma::{
|
||||
events::{
|
||||
receipt::{Receipt, ReceiptThread, ReceiptType},
|
||||
room::{
|
||||
member::{MembershipState, RedactedRoomMemberEventContent, RoomMemberEventContent},
|
||||
member::{MembershipState, RedactedRoomMemberEventContent},
|
||||
message::MessageType,
|
||||
name::RoomNameEventContent,
|
||||
topic::RedactedRoomTopicEventContent,
|
||||
},
|
||||
FullStateEventContent,
|
||||
},
|
||||
owned_event_id, owned_mxc_uri, MilliSecondsSinceUnixEpoch,
|
||||
mxc_uri, owned_event_id, MilliSecondsSinceUnixEpoch,
|
||||
};
|
||||
use stream_assert::assert_next_matches;
|
||||
|
||||
@@ -148,16 +149,9 @@ async fn test_room_member() {
|
||||
let timeline = TestTimeline::new();
|
||||
let mut stream = timeline.subscribe_events().await;
|
||||
|
||||
let mut first_room_member_content = RoomMemberEventContent::new(MembershipState::Invite);
|
||||
first_room_member_content.displayname = Some("Alice".to_owned());
|
||||
timeline
|
||||
.handle_live_state_event_with_state_key(
|
||||
&BOB,
|
||||
ALICE.to_owned(),
|
||||
first_room_member_content.clone(),
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
// Bob invites Alice.
|
||||
let f = &timeline.factory;
|
||||
timeline.handle_live_event(f.member(&BOB).invited(&ALICE).display_name("Alice")).await;
|
||||
|
||||
let item = assert_next_matches!(stream, VectorDiff::PushBack { value } => value);
|
||||
assert!(item.can_be_replied_to());
|
||||
@@ -165,14 +159,12 @@ async fn test_room_member() {
|
||||
assert_matches!(membership.content(), FullStateEventContent::Original { .. });
|
||||
assert_matches!(membership.change(), Some(MembershipChange::Invited));
|
||||
|
||||
let mut second_room_member_content = RoomMemberEventContent::new(MembershipState::Join);
|
||||
second_room_member_content.displayname = Some("Alice".to_owned());
|
||||
timeline
|
||||
.handle_live_state_event_with_state_key(
|
||||
&ALICE,
|
||||
ALICE.to_owned(),
|
||||
second_room_member_content.clone(),
|
||||
Some(first_room_member_content),
|
||||
.handle_live_event(
|
||||
f.member(&ALICE)
|
||||
.membership(MembershipState::Join)
|
||||
.display_name("Alice")
|
||||
.previous(PreviousMembership::new(MembershipState::Invite).display_name("Alice")),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -181,14 +173,12 @@ async fn test_room_member() {
|
||||
assert_matches!(membership.content(), FullStateEventContent::Original { .. });
|
||||
assert_matches!(membership.change(), Some(MembershipChange::InvitationAccepted));
|
||||
|
||||
let mut third_room_member_content = RoomMemberEventContent::new(MembershipState::Join);
|
||||
third_room_member_content.displayname = Some("Alice In Wonderland".to_owned());
|
||||
timeline
|
||||
.handle_live_state_event_with_state_key(
|
||||
&ALICE,
|
||||
ALICE.to_owned(),
|
||||
third_room_member_content.clone(),
|
||||
Some(second_room_member_content),
|
||||
.handle_live_event(
|
||||
f.member(&ALICE)
|
||||
.membership(MembershipState::Join)
|
||||
.display_name("Alice In Wonderland")
|
||||
.previous(PreviousMembership::new(MembershipState::Join).display_name("Alice")),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -197,15 +187,16 @@ async fn test_room_member() {
|
||||
assert_matches!(profile.displayname_change(), Some(_));
|
||||
assert_matches!(profile.avatar_url_change(), None);
|
||||
|
||||
let mut fourth_room_member_content = RoomMemberEventContent::new(MembershipState::Join);
|
||||
fourth_room_member_content.displayname = Some("Alice In Wonderland".to_owned());
|
||||
fourth_room_member_content.avatar_url = Some(owned_mxc_uri!("mxc://lolcathost.io/abc"));
|
||||
timeline
|
||||
.handle_live_state_event_with_state_key(
|
||||
&ALICE,
|
||||
ALICE.to_owned(),
|
||||
fourth_room_member_content.clone(),
|
||||
Some(third_room_member_content),
|
||||
.handle_live_event(
|
||||
f.member(&ALICE)
|
||||
.membership(MembershipState::Join)
|
||||
.display_name("Alice In Wonderland")
|
||||
.avatar_url(mxc_uri!("mxc://lolcathost.io/abc"))
|
||||
.previous(
|
||||
PreviousMembership::new(MembershipState::Join)
|
||||
.display_name("Alice In Wonderland"),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -217,14 +208,13 @@ async fn test_room_member() {
|
||||
{
|
||||
// No avatar or display name in the new room member event content, but it's
|
||||
// possible to get the previous one using the getters.
|
||||
let room_member_content = RoomMemberEventContent::new(MembershipState::Leave);
|
||||
|
||||
timeline
|
||||
.handle_live_state_event_with_state_key(
|
||||
&ALICE,
|
||||
ALICE.to_owned(),
|
||||
room_member_content,
|
||||
Some(fourth_room_member_content),
|
||||
.handle_live_event(
|
||||
f.member(&ALICE).membership(MembershipState::Leave).previous(
|
||||
PreviousMembership::new(MembershipState::Join)
|
||||
.display_name("Alice In Wonderland")
|
||||
.avatar_url(mxc_uri!("mxc://lolcathost.io/abc")),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -240,11 +230,11 @@ async fn test_room_member() {
|
||||
}
|
||||
|
||||
timeline
|
||||
.handle_live_redacted_state_event_with_state_key(
|
||||
.handle_live_event(f.redacted_state(
|
||||
&ALICE,
|
||||
ALICE.to_owned(),
|
||||
ALICE.as_str(),
|
||||
RedactedRoomMemberEventContent::new(MembershipState::Join),
|
||||
)
|
||||
))
|
||||
.await;
|
||||
|
||||
let item = assert_next_matches!(stream, VectorDiff::PushBack { value } => value);
|
||||
@@ -258,9 +248,8 @@ async fn test_other_state() {
|
||||
let timeline = TestTimeline::new();
|
||||
let mut stream = timeline.subscribe().await;
|
||||
|
||||
timeline
|
||||
.handle_live_state_event(&ALICE, RoomNameEventContent::new("Alice's room".to_owned()), None)
|
||||
.await;
|
||||
let f = &timeline.factory;
|
||||
timeline.handle_live_event(f.room_name("Alice's room").sender(&ALICE)).await;
|
||||
|
||||
let item = assert_next_matches!(stream, VectorDiff::PushBack { value } => value);
|
||||
assert_let!(TimelineItemContent::OtherState(ev) = item.as_event().unwrap().content());
|
||||
@@ -272,7 +261,9 @@ async fn test_other_state() {
|
||||
let date_divider = assert_next_matches!(stream, VectorDiff::PushFront { value } => value);
|
||||
assert!(date_divider.is_date_divider());
|
||||
|
||||
timeline.handle_live_redacted_state_event(&ALICE, RedactedRoomTopicEventContent::new()).await;
|
||||
timeline
|
||||
.handle_live_event(f.redacted_state(&ALICE, "", RedactedRoomTopicEventContent::new()))
|
||||
.await;
|
||||
|
||||
let item = assert_next_matches!(stream, VectorDiff::PushBack { value } => value);
|
||||
assert_let!(TimelineItemContent::OtherState(ev) = item.as_event().unwrap().content());
|
||||
|
||||
@@ -41,9 +41,7 @@ async fn test_live_redacted() {
|
||||
|
||||
let f = &timeline.factory;
|
||||
|
||||
timeline
|
||||
.handle_live_redacted_message_event(*ALICE, RedactedRoomMessageEventContent::new())
|
||||
.await;
|
||||
timeline.handle_live_event(f.redacted(*ALICE, RedactedRoomMessageEventContent::new())).await;
|
||||
let item = assert_next_matches!(stream, VectorDiff::PushBack { value } => value);
|
||||
|
||||
let redacted_event_id = item.as_event().unwrap().event_id().unwrap();
|
||||
|
||||
@@ -21,10 +21,8 @@ use matrix_sdk::deserialized_responses::SyncTimelineEvent;
|
||||
use matrix_sdk_test::{async_test, sync_timeline_event, ALICE, BOB};
|
||||
use ruma::events::{
|
||||
room::{
|
||||
member::{MembershipState, RoomMemberEventContent},
|
||||
member::MembershipState,
|
||||
message::{MessageType, RedactedRoomMessageEventContent},
|
||||
name::RoomNameEventContent,
|
||||
topic::RoomTopicEventContent,
|
||||
},
|
||||
AnySyncTimelineEvent, TimelineEventType,
|
||||
};
|
||||
@@ -82,7 +80,7 @@ async fn test_default_filter() {
|
||||
let item = assert_next_matches!(stream, VectorDiff::PushBack { value } => value);
|
||||
let third_event_id = item.as_event().unwrap().event_id().unwrap();
|
||||
|
||||
timeline.handle_live_event(f.reaction(third_event_id, "+1".to_owned()).sender(&BOB)).await;
|
||||
timeline.handle_live_event(f.reaction(third_event_id, "+1").sender(&BOB)).await;
|
||||
timeline.handle_live_event(f.redaction(second_event_id).sender(&BOB)).await;
|
||||
let item = assert_next_matches!(stream, VectorDiff::Set { index: 3, value } => value);
|
||||
assert_eq!(item.as_event().unwrap().reactions().len(), 1);
|
||||
@@ -102,22 +100,11 @@ async fn test_filter_always_false() {
|
||||
let f = &timeline.factory;
|
||||
timeline.handle_live_event(f.text_msg("The first message").sender(&ALICE)).await;
|
||||
|
||||
timeline
|
||||
.handle_live_redacted_message_event(&ALICE, RedactedRoomMessageEventContent::new())
|
||||
.await;
|
||||
timeline.handle_live_event(f.redacted(&ALICE, RedactedRoomMessageEventContent::new())).await;
|
||||
|
||||
timeline
|
||||
.handle_live_state_event_with_state_key(
|
||||
&ALICE,
|
||||
ALICE.to_owned(),
|
||||
RoomMemberEventContent::new(MembershipState::Join),
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
timeline.handle_live_event(f.member(&ALICE).membership(MembershipState::Join)).await;
|
||||
|
||||
timeline
|
||||
.handle_live_state_event(&ALICE, RoomNameEventContent::new("Alice's room".to_owned()), None)
|
||||
.await;
|
||||
timeline.handle_live_event(f.room_name("Alice's room").sender(&ALICE)).await;
|
||||
|
||||
assert_eq!(timeline.controller.items().await.len(), 0);
|
||||
}
|
||||
@@ -136,23 +123,12 @@ async fn test_custom_filter() {
|
||||
let _item = assert_next_matches!(stream, VectorDiff::PushBack { value } => value);
|
||||
let _date_divider = assert_next_matches!(stream, VectorDiff::PushFront { value } => value);
|
||||
|
||||
timeline
|
||||
.handle_live_redacted_message_event(&ALICE, RedactedRoomMessageEventContent::new())
|
||||
.await;
|
||||
timeline.handle_live_event(f.redacted(&ALICE, RedactedRoomMessageEventContent::new())).await;
|
||||
let _item = assert_next_matches!(stream, VectorDiff::PushBack { value } => value);
|
||||
|
||||
timeline
|
||||
.handle_live_state_event_with_state_key(
|
||||
&ALICE,
|
||||
ALICE.to_owned(),
|
||||
RoomMemberEventContent::new(MembershipState::Join),
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
timeline.handle_live_event(f.member(&ALICE).membership(MembershipState::Join)).await;
|
||||
|
||||
timeline
|
||||
.handle_live_state_event(&ALICE, RoomNameEventContent::new("Alice's room".to_owned()), None)
|
||||
.await;
|
||||
timeline.handle_live_event(f.room_name("Alice's room").sender(&ALICE)).await;
|
||||
|
||||
assert_eq!(timeline.controller.items().await.len(), 3);
|
||||
}
|
||||
@@ -204,28 +180,10 @@ async fn test_event_type_filter_include_only_room_names() {
|
||||
// Add a non-encrypted message event
|
||||
timeline.handle_live_event(f.text_msg("The first message").sender(&ALICE)).await;
|
||||
// Add a couple of room name events
|
||||
timeline
|
||||
.handle_live_state_event(
|
||||
&ALICE,
|
||||
RoomNameEventContent::new("A new room name".to_owned()),
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
timeline
|
||||
.handle_live_state_event(
|
||||
&ALICE,
|
||||
RoomNameEventContent::new("A new room name (again)".to_owned()),
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
timeline.handle_live_event(f.room_name("A new room name").sender(&ALICE)).await;
|
||||
timeline.handle_live_event(f.room_name("A new room name (again)").sender(&ALICE)).await;
|
||||
// And a different state event
|
||||
timeline
|
||||
.handle_live_state_event(
|
||||
&ALICE,
|
||||
RoomTopicEventContent::new("A new room topic".to_owned()),
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
timeline.handle_live_event(f.room_topic("A new room topic").sender(&ALICE)).await;
|
||||
|
||||
// The timeline should contain only the room name events
|
||||
let event_items: Vec<Arc<TimelineItem>> = timeline.get_event_items().await;
|
||||
@@ -252,28 +210,10 @@ async fn test_event_type_filter_exclude_messages() {
|
||||
// Add a message event
|
||||
timeline.handle_live_event(f.text_msg("The first message").sender(&ALICE)).await;
|
||||
// Add a couple of room name state events
|
||||
timeline
|
||||
.handle_live_state_event(
|
||||
&ALICE,
|
||||
RoomNameEventContent::new("A new room name".to_owned()),
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
timeline
|
||||
.handle_live_state_event(
|
||||
&ALICE,
|
||||
RoomNameEventContent::new("A new room name (again)".to_owned()),
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
timeline.handle_live_event(f.room_name("A new room name").sender(&ALICE)).await;
|
||||
timeline.handle_live_event(f.room_name("A new room name (again)").sender(&ALICE)).await;
|
||||
// And a different state event
|
||||
timeline
|
||||
.handle_live_state_event(
|
||||
&ALICE,
|
||||
RoomTopicEventContent::new("A new room topic".to_owned()),
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
timeline.handle_live_event(f.room_topic("A new room topic").sender(&ALICE)).await;
|
||||
|
||||
// The timeline should contain everything except for the message event.
|
||||
let event_items: Vec<Arc<TimelineItem>> = timeline.get_event_items().await;
|
||||
|
||||
@@ -36,17 +36,14 @@ use matrix_sdk::{
|
||||
use matrix_sdk_base::{
|
||||
crypto::types::events::CryptoContextInfo, latest_event::LatestEvent, RoomInfo, RoomState,
|
||||
};
|
||||
use matrix_sdk_test::{
|
||||
event_factory::EventFactory, EventBuilder, ALICE, BOB, DEFAULT_TEST_ROOM_ID,
|
||||
};
|
||||
use matrix_sdk_test::{event_factory::EventFactory, ALICE, BOB, DEFAULT_TEST_ROOM_ID};
|
||||
use ruma::{
|
||||
event_id,
|
||||
events::{
|
||||
reaction::ReactionEventContent,
|
||||
receipt::{Receipt, ReceiptThread, ReceiptType},
|
||||
relation::{Annotation, RelationType},
|
||||
AnyMessageLikeEventContent, AnyTimelineEvent, EmptyStateKey,
|
||||
RedactedMessageLikeEventContent, RedactedStateEventContent, StaticStateEventContent,
|
||||
AnyMessageLikeEventContent, AnyTimelineEvent,
|
||||
},
|
||||
int,
|
||||
power_levels::NotificationPowerLevels,
|
||||
@@ -86,7 +83,6 @@ mod virt;
|
||||
|
||||
struct TestTimeline {
|
||||
controller: TimelineController<TestRoomDataProvider>,
|
||||
event_builder: EventBuilder,
|
||||
/// An [`EventFactory`] that can be used for creating events in this
|
||||
/// timeline.
|
||||
pub factory: EventFactory,
|
||||
@@ -111,7 +107,6 @@ impl TestTimeline {
|
||||
None,
|
||||
Some(false),
|
||||
),
|
||||
event_builder: EventBuilder::new(),
|
||||
factory: EventFactory::new(),
|
||||
}
|
||||
}
|
||||
@@ -125,7 +120,6 @@ impl TestTimeline {
|
||||
None,
|
||||
Some(false),
|
||||
),
|
||||
event_builder: EventBuilder::new(),
|
||||
factory: EventFactory::new(),
|
||||
}
|
||||
}
|
||||
@@ -139,7 +133,6 @@ impl TestTimeline {
|
||||
Some(hook),
|
||||
Some(true),
|
||||
),
|
||||
event_builder: EventBuilder::new(),
|
||||
factory: EventFactory::new(),
|
||||
}
|
||||
}
|
||||
@@ -154,7 +147,6 @@ impl TestTimeline {
|
||||
None,
|
||||
Some(encrypted),
|
||||
),
|
||||
event_builder: EventBuilder::new(),
|
||||
factory: EventFactory::new(),
|
||||
}
|
||||
}
|
||||
@@ -181,61 +173,6 @@ impl TestTimeline {
|
||||
self.controller.items().await.len()
|
||||
}
|
||||
|
||||
async fn handle_live_redacted_message_event<C>(&self, sender: &UserId, content: C)
|
||||
where
|
||||
C: RedactedMessageLikeEventContent,
|
||||
{
|
||||
let ev = self.event_builder.make_sync_redacted_message_event(sender, content);
|
||||
self.handle_live_event(SyncTimelineEvent::new(ev)).await;
|
||||
}
|
||||
|
||||
async fn handle_live_state_event<C>(&self, sender: &UserId, content: C, prev_content: Option<C>)
|
||||
where
|
||||
C: StaticStateEventContent<StateKey = EmptyStateKey>,
|
||||
{
|
||||
let ev = self.event_builder.make_sync_state_event(sender, "", content, prev_content);
|
||||
self.handle_live_event(SyncTimelineEvent::new(ev)).await;
|
||||
}
|
||||
|
||||
async fn handle_live_state_event_with_state_key<C>(
|
||||
&self,
|
||||
sender: &UserId,
|
||||
state_key: C::StateKey,
|
||||
content: C,
|
||||
prev_content: Option<C>,
|
||||
) where
|
||||
C: StaticStateEventContent,
|
||||
{
|
||||
let ev = self.event_builder.make_sync_state_event(
|
||||
sender,
|
||||
state_key.as_ref(),
|
||||
content,
|
||||
prev_content,
|
||||
);
|
||||
self.handle_live_event(SyncTimelineEvent::new(ev)).await;
|
||||
}
|
||||
|
||||
async fn handle_live_redacted_state_event<C>(&self, sender: &UserId, content: C)
|
||||
where
|
||||
C: RedactedStateEventContent<StateKey = EmptyStateKey>,
|
||||
{
|
||||
let ev = self.event_builder.make_sync_redacted_state_event(sender, "", content);
|
||||
self.handle_live_event(SyncTimelineEvent::new(ev)).await;
|
||||
}
|
||||
|
||||
async fn handle_live_redacted_state_event_with_state_key<C>(
|
||||
&self,
|
||||
sender: &UserId,
|
||||
state_key: C::StateKey,
|
||||
content: C,
|
||||
) where
|
||||
C: RedactedStateEventContent,
|
||||
{
|
||||
let ev =
|
||||
self.event_builder.make_sync_redacted_state_event(sender, state_key.as_ref(), content);
|
||||
self.handle_live_event(SyncTimelineEvent::new(ev)).await;
|
||||
}
|
||||
|
||||
async fn handle_live_event(&self, event: impl Into<SyncTimelineEvent>) {
|
||||
let event = event.into();
|
||||
self.controller
|
||||
@@ -272,7 +209,11 @@ impl TestTimeline {
|
||||
&self,
|
||||
receipts: impl IntoIterator<Item = (OwnedEventId, ReceiptType, OwnedUserId, ReceiptThread)>,
|
||||
) {
|
||||
let ev_content = self.event_builder.make_receipt_event_content(receipts);
|
||||
let mut read_receipt = self.factory.read_receipts();
|
||||
for (event_id, tyype, user_id, thread) in receipts {
|
||||
read_receipt = read_receipt.add(&event_id, &user_id, tyype, thread);
|
||||
}
|
||||
let ev_content = read_receipt.build();
|
||||
self.controller.handle_read_receipts(ev_content).await;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use matrix_sdk_base::deserialized_responses::SyncTimelineEvent;
|
||||
use fakes::poll_a2;
|
||||
use matrix_sdk_test::{async_test, ALICE, BOB};
|
||||
use ruma::{
|
||||
events::{
|
||||
@@ -164,26 +164,27 @@ async fn test_events_received_before_start_are_not_lost() {
|
||||
let poll_id: OwnedEventId = EventId::new(server_name!("dummy.server"));
|
||||
|
||||
// Alice votes
|
||||
timeline.send_poll_response(&ALICE, vec!["id_up"], &poll_id).await;
|
||||
timeline.send_poll_response(&ALICE, vec!["0"], &poll_id).await;
|
||||
|
||||
// Now Bob also votes
|
||||
timeline.send_poll_response(&BOB, vec!["id_up"], &poll_id).await;
|
||||
timeline.send_poll_response(&BOB, vec!["0"], &poll_id).await;
|
||||
|
||||
// Alice changes her mind and votes again
|
||||
timeline.send_poll_response(&ALICE, vec!["id_down"], &poll_id).await;
|
||||
timeline.send_poll_response(&ALICE, vec!["1"], &poll_id).await;
|
||||
|
||||
// Poll finishes
|
||||
timeline.send_poll_end(&ALICE, "ENDED", &poll_id).await;
|
||||
|
||||
// Now the start event arrives
|
||||
timeline.send_poll_start_with_id(&ALICE, &poll_id, fakes::poll_a()).await;
|
||||
let start_ev = poll_a2(&timeline.factory).sender(&ALICE).event_id(&poll_id);
|
||||
timeline.handle_live_event(start_ev).await;
|
||||
|
||||
// Now Bob votes again but his vote won't count
|
||||
timeline.send_poll_response(&BOB, vec!["id_down"], &poll_id).await;
|
||||
timeline.send_poll_response(&BOB, vec!["1"], &poll_id).await;
|
||||
|
||||
let results = timeline.poll_state().await.results();
|
||||
assert_eq!(results.votes["id_up"], vec![BOB.to_string()]);
|
||||
assert_eq!(results.votes["id_down"], vec![ALICE.to_string()]);
|
||||
assert_eq!(results.votes["0"], vec![BOB.to_string()]);
|
||||
assert_eq!(results.votes["1"], vec![ALICE.to_string()]);
|
||||
}
|
||||
|
||||
impl TestTimeline {
|
||||
@@ -206,20 +207,6 @@ impl TestTimeline {
|
||||
self.handle_live_event(self.factory.event(event_content).sender(sender)).await;
|
||||
}
|
||||
|
||||
async fn send_poll_start_with_id(
|
||||
&self,
|
||||
sender: &UserId,
|
||||
event_id: &EventId,
|
||||
content: UnstablePollStartContentBlock,
|
||||
) {
|
||||
let event_content = AnyMessageLikeEventContent::UnstablePollStart(
|
||||
NewUnstablePollStartEventContent::new(content).into(),
|
||||
);
|
||||
let event =
|
||||
self.event_builder.make_sync_message_event_with_id(sender, event_id, event_content);
|
||||
self.handle_live_event(SyncTimelineEvent::new(event)).await;
|
||||
}
|
||||
|
||||
async fn send_poll_response(&self, sender: &UserId, answers: Vec<&str>, poll_id: &EventId) {
|
||||
let event_content = AnyMessageLikeEventContent::UnstablePollResponse(
|
||||
UnstablePollResponseEventContent::new(
|
||||
@@ -263,11 +250,19 @@ fn assert_poll_start_eq(a: &UnstablePollStartContentBlock, b: &UnstablePollStart
|
||||
}
|
||||
|
||||
mod fakes {
|
||||
use matrix_sdk_test::event_factory::{EventBuilder, EventFactory};
|
||||
use ruma::events::poll::{
|
||||
start::PollKind,
|
||||
unstable_start::{UnstablePollAnswer, UnstablePollAnswers, UnstablePollStartContentBlock},
|
||||
unstable_start::{
|
||||
UnstablePollAnswer, UnstablePollAnswers, UnstablePollStartContentBlock,
|
||||
UnstablePollStartEventContent,
|
||||
},
|
||||
};
|
||||
|
||||
pub fn poll_a2(f: &EventFactory) -> EventBuilder<UnstablePollStartEventContent> {
|
||||
f.poll_start("Up or down?", "Up or down?", vec!["Up", "Down"])
|
||||
}
|
||||
|
||||
pub fn poll_a() -> UnstablePollStartContentBlock {
|
||||
let mut content = UnstablePollStartContentBlock::new(
|
||||
"Up or down?",
|
||||
|
||||
@@ -113,7 +113,7 @@ async fn test_add_reaction_success() {
|
||||
|
||||
// When the remote echo is received from sync,
|
||||
let f = EventFactory::new();
|
||||
timeline.handle_live_event(f.reaction(&event_id, REACTION_KEY.to_owned()).sender(*ALICE)).await;
|
||||
timeline.handle_live_event(f.reaction(&event_id, REACTION_KEY).sender(*ALICE)).await;
|
||||
|
||||
// The reaction is still present on the item, as a remote echo.
|
||||
assert_reaction_is_updated!(stream, &event_id, item_pos, true);
|
||||
@@ -132,9 +132,7 @@ async fn test_redact_reaction_success() {
|
||||
// A reaction is added by sync.
|
||||
let reaction_id = event_id!("$reaction_id");
|
||||
timeline
|
||||
.handle_live_event(
|
||||
f.reaction(&event_id, REACTION_KEY.to_owned()).sender(&ALICE).event_id(reaction_id),
|
||||
)
|
||||
.handle_live_event(f.reaction(&event_id, REACTION_KEY).sender(&ALICE).event_id(reaction_id))
|
||||
.await;
|
||||
assert_reaction_is_updated!(stream, &event_id, item_pos, true);
|
||||
|
||||
@@ -198,7 +196,7 @@ async fn test_initial_reaction_timestamp_is_stored() {
|
||||
.add_events_at(
|
||||
[
|
||||
// Reaction comes first.
|
||||
f.reaction(&message_event_id, REACTION_KEY.to_owned())
|
||||
f.reaction(&message_event_id, REACTION_KEY)
|
||||
.server_ts(reaction_timestamp)
|
||||
.into_sync(),
|
||||
// Event comes next.
|
||||
|
||||
@@ -15,11 +15,9 @@
|
||||
use assert_matches::assert_matches;
|
||||
use assert_matches2::assert_let;
|
||||
use eyeball_im::VectorDiff;
|
||||
use matrix_sdk_base::deserialized_responses::SyncTimelineEvent;
|
||||
use matrix_sdk_test::{async_test, ALICE, BOB};
|
||||
use ruma::events::{
|
||||
reaction::RedactedReactionEventContent,
|
||||
room::{message::OriginalSyncRoomMessageEvent, name::RoomNameEventContent},
|
||||
reaction::RedactedReactionEventContent, room::message::OriginalSyncRoomMessageEvent,
|
||||
FullStateEventContent,
|
||||
};
|
||||
use stream_assert::assert_next_matches;
|
||||
@@ -37,13 +35,7 @@ async fn test_redact_state_event() {
|
||||
|
||||
let f = &timeline.factory;
|
||||
|
||||
timeline
|
||||
.handle_live_state_event(
|
||||
&ALICE,
|
||||
RoomNameEventContent::new("Fancy room name".to_owned()),
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
timeline.handle_live_event(f.room_name("Fancy room name").sender(&ALICE)).await;
|
||||
|
||||
let item = assert_next_matches!(stream, VectorDiff::PushBack { value } => value);
|
||||
assert_let!(TimelineItemContent::OtherState(state) = item.content());
|
||||
@@ -114,7 +106,7 @@ async fn test_reaction_redaction() {
|
||||
|
||||
let msg_event_id = item.event_id().unwrap();
|
||||
|
||||
timeline.handle_live_event(f.reaction(msg_event_id, "+1".to_owned()).sender(&BOB)).await;
|
||||
timeline.handle_live_event(f.reaction(msg_event_id, "+1").sender(&BOB)).await;
|
||||
let item = assert_next_matches!(stream, VectorDiff::Set { index: 0, value } => value);
|
||||
assert_eq!(item.reactions().len(), 1);
|
||||
|
||||
@@ -138,12 +130,7 @@ async fn test_reaction_redaction_timeline_filter() {
|
||||
timeline
|
||||
.controller
|
||||
.add_events_at(
|
||||
[SyncTimelineEvent::new(
|
||||
timeline
|
||||
.event_builder
|
||||
.make_sync_redacted_message_event(*ALICE, RedactedReactionEventContent::new()),
|
||||
)]
|
||||
.into_iter(),
|
||||
[f.redacted(*ALICE, RedactedReactionEventContent::new())].into_iter(),
|
||||
TimelineNewItemPosition::End { origin: RemoteEventOrigin::Sync },
|
||||
)
|
||||
.await;
|
||||
@@ -151,7 +138,7 @@ async fn test_reaction_redaction_timeline_filter() {
|
||||
assert_eq!(timeline.controller.items().await.len(), 0);
|
||||
|
||||
// Adding a live redacted reaction does nothing.
|
||||
timeline.handle_live_redacted_message_event(&ALICE, RedactedReactionEventContent::new()).await;
|
||||
timeline.handle_live_event(f.redacted(&ALICE, RedactedReactionEventContent::new())).await;
|
||||
assert_eq!(timeline.controller.items().await.len(), 0);
|
||||
|
||||
// Adding a room message
|
||||
@@ -161,9 +148,7 @@ async fn test_reaction_redaction_timeline_filter() {
|
||||
assert_eq!(timeline.controller.items().await.len(), 2);
|
||||
|
||||
// Reaction is attached to the message and doesn't add a timeline item.
|
||||
timeline
|
||||
.handle_live_event(f.reaction(item.event_id().unwrap(), "+1".to_owned()).sender(&BOB))
|
||||
.await;
|
||||
timeline.handle_live_event(f.reaction(item.event_id().unwrap(), "+1").sender(&BOB)).await;
|
||||
let item = assert_next_matches!(stream, VectorDiff::Set { index: 0, value } => value);
|
||||
let reaction_event_id = item.event_id().unwrap();
|
||||
assert_eq!(timeline.controller.items().await.len(), 2);
|
||||
|
||||
@@ -242,7 +242,7 @@ async fn test_focused_timeline_reacts() {
|
||||
// This event must be ignored.
|
||||
f.text_msg("this is a sync event").sender(*ALICE).into(),
|
||||
// This event must not be ignored.
|
||||
f.reaction(target_event, "👍".to_owned()).sender(*BOB).into(),
|
||||
f.reaction(target_event, "👍").sender(*BOB).into(),
|
||||
]));
|
||||
|
||||
// Sync the room.
|
||||
|
||||
@@ -22,18 +22,15 @@ use futures_util::{
|
||||
};
|
||||
use matrix_sdk::{config::SyncSettings, test_utils::logged_in_client_with_server};
|
||||
use matrix_sdk_test::{
|
||||
async_test, mocks::mock_encryption_state, EventBuilder, JoinedRoomBuilder, StateTestEvent,
|
||||
SyncResponseBuilder, ALICE, BOB,
|
||||
async_test, event_factory::EventFactory, mocks::mock_encryption_state, JoinedRoomBuilder,
|
||||
StateTestEvent, SyncResponseBuilder, ALICE, BOB,
|
||||
};
|
||||
use matrix_sdk_ui::timeline::{
|
||||
AnyOtherFullStateEventContent, LiveBackPaginationStatus, RoomExt, TimelineItemContent,
|
||||
};
|
||||
use once_cell::sync::Lazy;
|
||||
use ruma::{
|
||||
events::{
|
||||
room::message::{MessageType, RoomMessageEventContent},
|
||||
FullStateEventContent,
|
||||
},
|
||||
events::{room::message::MessageType, FullStateEventContent},
|
||||
room_id,
|
||||
};
|
||||
use serde_json::{json, Value as JsonValue};
|
||||
@@ -257,7 +254,7 @@ async fn test_wait_for_token() {
|
||||
let (client, server) = logged_in_client_with_server().await;
|
||||
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
||||
|
||||
let event_builder = EventBuilder::new();
|
||||
let f = EventFactory::new();
|
||||
let mut sync_builder = SyncResponseBuilder::new();
|
||||
sync_builder.add_joined_room(JoinedRoomBuilder::new(room_id));
|
||||
|
||||
@@ -285,10 +282,7 @@ async fn test_wait_for_token() {
|
||||
|
||||
sync_builder.add_joined_room(
|
||||
JoinedRoomBuilder::new(room_id)
|
||||
.add_timeline_event(event_builder.make_sync_message_event(
|
||||
&ALICE,
|
||||
RoomMessageEventContent::text_plain("live event!"),
|
||||
))
|
||||
.add_timeline_event(f.text_msg("live event!").sender(&ALICE))
|
||||
.set_timeline_prev_batch(from.to_owned())
|
||||
.set_timeline_limited(),
|
||||
);
|
||||
@@ -321,7 +315,7 @@ async fn test_dedup_pagination() {
|
||||
let (client, server) = logged_in_client_with_server().await;
|
||||
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
||||
|
||||
let event_builder = EventBuilder::new();
|
||||
let f = EventFactory::new();
|
||||
let mut sync_builder = SyncResponseBuilder::new();
|
||||
sync_builder.add_joined_room(JoinedRoomBuilder::new(room_id));
|
||||
|
||||
@@ -353,10 +347,7 @@ async fn test_dedup_pagination() {
|
||||
|
||||
sync_builder.add_joined_room(
|
||||
JoinedRoomBuilder::new(room_id)
|
||||
.add_timeline_event(event_builder.make_sync_message_event(
|
||||
&ALICE,
|
||||
RoomMessageEventContent::text_plain("live event!"),
|
||||
))
|
||||
.add_timeline_event(f.text_msg("live event!").sender(&ALICE))
|
||||
.set_timeline_prev_batch(from.to_owned()),
|
||||
);
|
||||
mock_sync(&server, sync_builder.build_json_sync_response(), None).await;
|
||||
@@ -383,7 +374,7 @@ async fn test_timeline_reset_while_paginating() {
|
||||
let (client, server) = logged_in_client_with_server().await;
|
||||
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
||||
|
||||
let event_builder = EventBuilder::new();
|
||||
let f = EventFactory::new();
|
||||
let mut sync_builder = SyncResponseBuilder::new();
|
||||
|
||||
sync_builder.add_joined_room(JoinedRoomBuilder::new(room_id));
|
||||
@@ -398,10 +389,7 @@ async fn test_timeline_reset_while_paginating() {
|
||||
|
||||
sync_builder.add_joined_room(
|
||||
JoinedRoomBuilder::new(room_id)
|
||||
.add_timeline_event(event_builder.make_sync_message_event(
|
||||
&ALICE,
|
||||
RoomMessageEventContent::text_plain("live event!"),
|
||||
))
|
||||
.add_timeline_event(f.text_msg("live event!").sender(&ALICE))
|
||||
.set_timeline_prev_batch("pagination_1".to_owned())
|
||||
.set_timeline_limited(),
|
||||
);
|
||||
@@ -413,10 +401,7 @@ async fn test_timeline_reset_while_paginating() {
|
||||
// response, resetting the timeline
|
||||
sync_builder.add_joined_room(
|
||||
JoinedRoomBuilder::new(room_id)
|
||||
.add_timeline_event(event_builder.make_sync_message_event(
|
||||
&BOB,
|
||||
RoomMessageEventContent::text_plain("new live event."),
|
||||
))
|
||||
.add_timeline_event(f.text_msg("new live event.").sender(&BOB))
|
||||
.set_timeline_prev_batch("pagination_2".to_owned())
|
||||
.set_timeline_limited(),
|
||||
);
|
||||
|
||||
@@ -17,14 +17,11 @@ use std::{sync::Arc, time::Duration};
|
||||
use assert_matches::assert_matches;
|
||||
use matrix_sdk::{config::SyncSettings, test_utils::logged_in_client_with_server};
|
||||
use matrix_sdk_test::{
|
||||
async_test, mocks::mock_encryption_state, EventBuilder, JoinedRoomBuilder, SyncResponseBuilder,
|
||||
ALICE, BOB, CAROL, DEFAULT_TEST_ROOM_ID,
|
||||
async_test, event_factory::EventFactory, mocks::mock_encryption_state, JoinedRoomBuilder,
|
||||
SyncResponseBuilder, ALICE, BOB, CAROL, DEFAULT_TEST_ROOM_ID,
|
||||
};
|
||||
use matrix_sdk_ui::timeline::{RoomExt, TimelineDetails};
|
||||
use ruma::events::room::{
|
||||
member::{MembershipState, RoomMemberEventContent},
|
||||
message::RoomMessageEventContent,
|
||||
};
|
||||
use ruma::events::room::member::MembershipState;
|
||||
use serde_json::json;
|
||||
use wiremock::{
|
||||
matchers::{method, path_regex},
|
||||
@@ -38,7 +35,7 @@ async fn test_update_sender_profiles() {
|
||||
let (client, server) = logged_in_client_with_server().await;
|
||||
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
||||
|
||||
let event_builder = EventBuilder::new();
|
||||
let f = EventFactory::new();
|
||||
let mut sync_builder = SyncResponseBuilder::new();
|
||||
sync_builder.add_joined_room(JoinedRoomBuilder::new(&DEFAULT_TEST_ROOM_ID));
|
||||
|
||||
@@ -54,24 +51,15 @@ async fn test_update_sender_profiles() {
|
||||
sync_builder.add_joined_room(
|
||||
JoinedRoomBuilder::new(&DEFAULT_TEST_ROOM_ID)
|
||||
// Alice accepts an invite into the room
|
||||
.add_timeline_event(event_builder.make_sync_state_event(
|
||||
&ALICE,
|
||||
ALICE.as_str(),
|
||||
RoomMemberEventContent::new(MembershipState::Join),
|
||||
Some(RoomMemberEventContent::new(MembershipState::Invite)),
|
||||
))
|
||||
.add_timeline_event(
|
||||
f.member(&ALICE)
|
||||
.membership(MembershipState::Join)
|
||||
.previous(MembershipState::Invite),
|
||||
)
|
||||
// Bob sends a text message
|
||||
.add_timeline_event(event_builder.make_sync_message_event(
|
||||
&BOB,
|
||||
RoomMessageEventContent::text_plain("text message event"),
|
||||
))
|
||||
.add_timeline_event(f.text_msg("text message event").sender(&BOB))
|
||||
// Carol kicks bob
|
||||
.add_timeline_event(event_builder.make_sync_state_event(
|
||||
&CAROL,
|
||||
BOB.as_str(),
|
||||
RoomMemberEventContent::new(MembershipState::Leave),
|
||||
Some(RoomMemberEventContent::new(MembershipState::Join)),
|
||||
)),
|
||||
.add_timeline_event(f.member(&CAROL).kicked(&BOB).previous(MembershipState::Join)),
|
||||
);
|
||||
|
||||
mock_sync(&server, sync_builder.build_json_sync_response(), None).await;
|
||||
@@ -118,36 +106,20 @@ async fn test_update_sender_profiles() {
|
||||
TimelineDetails::Error(_)
|
||||
);
|
||||
|
||||
let f = f.room(&DEFAULT_TEST_ROOM_ID);
|
||||
|
||||
// Try again, this time we mock the endpoint to get a useful response.
|
||||
Mock::given(method("GET"))
|
||||
.and(path_regex(r"/_matrix/client/r0/rooms/.*/members"))
|
||||
.respond_with(ResponseTemplate::new(200).set_body_json(json!({
|
||||
"chunk": [
|
||||
// This event wasn't previously observed by the client
|
||||
event_builder.make_state_event(
|
||||
&CAROL,
|
||||
&DEFAULT_TEST_ROOM_ID,
|
||||
CAROL.as_str(),
|
||||
RoomMemberEventContent::new(MembershipState::Join),
|
||||
None,
|
||||
),
|
||||
f.member(&CAROL).membership(MembershipState::Join).into_raw_timeline(),
|
||||
|
||||
// Same as above
|
||||
event_builder.make_state_event(
|
||||
&ALICE,
|
||||
&DEFAULT_TEST_ROOM_ID,
|
||||
ALICE.as_str(),
|
||||
RoomMemberEventContent::new(MembershipState::Join),
|
||||
Some(RoomMemberEventContent::new(MembershipState::Invite)),
|
||||
),
|
||||
f.member(&ALICE).membership(MembershipState::Join).previous(MembershipState::Invite).into_raw_timeline(),
|
||||
|
||||
event_builder.make_state_event(
|
||||
&CAROL,
|
||||
&DEFAULT_TEST_ROOM_ID,
|
||||
BOB.as_str(),
|
||||
RoomMemberEventContent::new(MembershipState::Leave),
|
||||
Some(RoomMemberEventContent::new(MembershipState::Join)),
|
||||
),
|
||||
f.member(&CAROL).kicked(&BOB).previous(MembershipState::Join).into_raw_timeline(),
|
||||
]
|
||||
})))
|
||||
.mount(&server)
|
||||
|
||||
@@ -21,8 +21,8 @@ use futures_util::StreamExt;
|
||||
use matrix_sdk::{config::SyncSettings, test_utils::logged_in_client_with_server, Error};
|
||||
use matrix_sdk_base::store::QueueWedgeError;
|
||||
use matrix_sdk_test::{
|
||||
async_test, mocks::mock_encryption_state, EventBuilder, JoinedRoomBuilder, SyncResponseBuilder,
|
||||
ALICE,
|
||||
async_test, event_factory::EventFactory, mocks::mock_encryption_state, JoinedRoomBuilder,
|
||||
SyncResponseBuilder, ALICE,
|
||||
};
|
||||
use matrix_sdk_ui::timeline::{EventItemOrigin, EventSendState, RoomExt};
|
||||
use ruma::{
|
||||
@@ -314,7 +314,7 @@ async fn test_clear_with_echoes() {
|
||||
let (client, server) = logged_in_client_with_server().await;
|
||||
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
||||
|
||||
let event_builder = EventBuilder::new();
|
||||
let f = EventFactory::new();
|
||||
let mut sync_builder = SyncResponseBuilder::new();
|
||||
sync_builder.add_joined_room(JoinedRoomBuilder::new(room_id));
|
||||
|
||||
@@ -355,12 +355,10 @@ async fn test_clear_with_echoes() {
|
||||
timeline.send(RoomMessageEventContent::text_plain("Pending").into()).await.unwrap();
|
||||
|
||||
// Another message comes in.
|
||||
sync_builder.add_joined_room(JoinedRoomBuilder::new(room_id).add_timeline_event(
|
||||
event_builder.make_sync_message_event(
|
||||
&ALICE,
|
||||
RoomMessageEventContent::text_plain("another message"),
|
||||
),
|
||||
));
|
||||
sync_builder.add_joined_room(
|
||||
JoinedRoomBuilder::new(room_id)
|
||||
.add_timeline_event(f.text_msg("another message").sender(&ALICE)),
|
||||
);
|
||||
mock_sync(&server, sync_builder.build_json_sync_response(), None).await;
|
||||
client.sync_once(sync_settings.clone()).await.unwrap();
|
||||
|
||||
@@ -475,23 +473,23 @@ async fn test_no_duplicate_date_divider() {
|
||||
assert_pending!(timeline_stream);
|
||||
|
||||
// Now have the sync return both events with more data.
|
||||
let ev_builder = EventBuilder::new();
|
||||
let f = EventFactory::new();
|
||||
|
||||
let now = MilliSecondsSinceUnixEpoch::now();
|
||||
ev_builder.set_next_ts(now.0.into());
|
||||
f.set_next_ts(now.0.into());
|
||||
|
||||
sync_response_builder.add_joined_room(
|
||||
JoinedRoomBuilder::new(room_id)
|
||||
.add_timeline_event(ev_builder.make_sync_message_event_with_id(
|
||||
client.user_id().unwrap(),
|
||||
event_id!("$PyHxV5mYzjetBUT3qZq7V95GOzxb02EP"),
|
||||
RoomMessageEventContent::text_plain("First!"),
|
||||
))
|
||||
.add_timeline_event(ev_builder.make_sync_message_event_with_id(
|
||||
client.user_id().unwrap(),
|
||||
event_id!("$5E2kLK/Sg342bgBU9ceEIEPYpbFaqJpZ"),
|
||||
RoomMessageEventContent::text_plain("Second."),
|
||||
)),
|
||||
.add_timeline_event(
|
||||
f.text_msg("First!")
|
||||
.sender(client.user_id().unwrap())
|
||||
.event_id(event_id!("$PyHxV5mYzjetBUT3qZq7V95GOzxb02EP")),
|
||||
)
|
||||
.add_timeline_event(
|
||||
f.text_msg("Second.")
|
||||
.sender(client.user_id().unwrap())
|
||||
.event_id(event_id!("$5E2kLK/Sg342bgBU9ceEIEPYpbFaqJpZ")),
|
||||
),
|
||||
);
|
||||
|
||||
mock_sync(&server, sync_response_builder.build_json_sync_response(), None).await;
|
||||
|
||||
@@ -199,7 +199,7 @@ async fn test_redact_failed() {
|
||||
sync_builder.add_joined_room(
|
||||
JoinedRoomBuilder::new(room_id)
|
||||
.add_timeline_event(f.text_msg("hello").sender(&ALICE).event_id(event_id))
|
||||
.add_timeline_event(f.reaction(event_id, "😆".to_owned()).sender(user_id)),
|
||||
.add_timeline_event(f.reaction(event_id, "😆").sender(user_id)),
|
||||
);
|
||||
|
||||
mock_sync(&server, sync_builder.build_json_sync_response(), None).await;
|
||||
|
||||
@@ -7,8 +7,8 @@ use futures_util::StreamExt;
|
||||
use matrix_sdk::{config::SyncSettings, test_utils::logged_in_client_with_server};
|
||||
use matrix_sdk_base::timeout::timeout;
|
||||
use matrix_sdk_test::{
|
||||
async_test, event_factory::EventFactory, mocks::mock_encryption_state, EventBuilder,
|
||||
JoinedRoomBuilder, SyncResponseBuilder, ALICE, BOB, CAROL,
|
||||
async_test, event_factory::EventFactory, mocks::mock_encryption_state, JoinedRoomBuilder,
|
||||
SyncResponseBuilder, ALICE, BOB, CAROL,
|
||||
};
|
||||
use matrix_sdk_ui::timeline::{
|
||||
Error as TimelineError, EventSendState, RoomExt, TimelineDetails, TimelineItemContent,
|
||||
@@ -18,13 +18,10 @@ use ruma::{
|
||||
events::{
|
||||
reaction::RedactedReactionEventContent,
|
||||
relation::InReplyTo,
|
||||
room::message::{
|
||||
AddMentions, ForwardThread, OriginalRoomMessageEvent, Relation, ReplyWithinThread,
|
||||
RoomMessageEventContent, RoomMessageEventContentWithoutRelation,
|
||||
},
|
||||
Mentions, MessageLikeUnsigned,
|
||||
room::message::{ForwardThread, Relation, RoomMessageEventContentWithoutRelation},
|
||||
Mentions,
|
||||
},
|
||||
owned_event_id, owned_room_id, owned_user_id, room_id, uint, MilliSecondsSinceUnixEpoch,
|
||||
owned_event_id, room_id,
|
||||
};
|
||||
use serde_json::json;
|
||||
use stream_assert::assert_next_matches;
|
||||
@@ -251,7 +248,6 @@ async fn test_transfer_in_reply_to_details_to_re_received_item() {
|
||||
async fn test_send_reply() {
|
||||
let room_id = room_id!("!a98sd12bjh:example.org");
|
||||
let (client, server) = logged_in_client_with_server().await;
|
||||
let event_builder = EventBuilder::new();
|
||||
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
||||
|
||||
let mut sync_builder = SyncResponseBuilder::new();
|
||||
@@ -269,13 +265,12 @@ async fn test_send_reply() {
|
||||
timeline.subscribe_filter_map(|item| item.as_event().cloned()).await;
|
||||
|
||||
let event_id_from_bob = event_id!("$event_from_bob");
|
||||
sync_builder.add_joined_room(JoinedRoomBuilder::new(room_id).add_timeline_event(
|
||||
event_builder.make_sync_message_event_with_id(
|
||||
&BOB,
|
||||
event_id_from_bob,
|
||||
RoomMessageEventContent::text_plain("Hello from Bob"),
|
||||
let f = EventFactory::new();
|
||||
sync_builder.add_joined_room(
|
||||
JoinedRoomBuilder::new(room_id).add_timeline_event(
|
||||
f.text_msg("Hello from Bob").sender(&BOB).event_id(event_id_from_bob),
|
||||
),
|
||||
));
|
||||
);
|
||||
|
||||
mock_sync(&server, sync_builder.build_json_sync_response(), None).await;
|
||||
let _response = client.sync_once(sync_settings.clone()).await.unwrap();
|
||||
@@ -364,7 +359,6 @@ async fn test_send_reply() {
|
||||
async fn test_send_reply_to_self() {
|
||||
let room_id = room_id!("!a98sd12bjh:example.org");
|
||||
let (client, server) = logged_in_client_with_server().await;
|
||||
let event_builder = EventBuilder::new();
|
||||
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
||||
|
||||
let mut sync_builder = SyncResponseBuilder::new();
|
||||
@@ -382,13 +376,14 @@ async fn test_send_reply_to_self() {
|
||||
timeline.subscribe_filter_map(|item| item.as_event().cloned()).await;
|
||||
|
||||
let event_id_from_self = event_id!("$event_from_self");
|
||||
sync_builder.add_joined_room(JoinedRoomBuilder::new(room_id).add_timeline_event(
|
||||
event_builder.make_sync_message_event_with_id(
|
||||
client.user_id().expect("Client must have a user ID"),
|
||||
event_id_from_self,
|
||||
RoomMessageEventContent::text_plain("Hello from self"),
|
||||
let f = EventFactory::new();
|
||||
sync_builder.add_joined_room(
|
||||
JoinedRoomBuilder::new(room_id).add_timeline_event(
|
||||
f.text_msg("Hello from self")
|
||||
.sender(client.user_id().expect("Client must have a user ID"))
|
||||
.event_id(event_id_from_self),
|
||||
),
|
||||
));
|
||||
);
|
||||
|
||||
mock_sync(&server, sync_builder.build_json_sync_response(), None).await;
|
||||
let _response = client.sync_once(sync_settings.clone()).await.unwrap();
|
||||
@@ -462,7 +457,6 @@ async fn test_send_reply_to_self() {
|
||||
async fn test_send_reply_to_threaded() {
|
||||
let room_id = room_id!("!a98sd12bjh:example.org");
|
||||
let (client, server) = logged_in_client_with_server().await;
|
||||
let event_builder = EventBuilder::new();
|
||||
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
||||
|
||||
let mut sync_builder = SyncResponseBuilder::new();
|
||||
@@ -479,27 +473,18 @@ async fn test_send_reply_to_threaded() {
|
||||
let (_, mut timeline_stream) =
|
||||
timeline.subscribe_filter_map(|item| item.as_event().cloned()).await;
|
||||
|
||||
let thread_root = OriginalRoomMessageEvent {
|
||||
content: RoomMessageEventContent::text_plain("Thread root"),
|
||||
event_id: owned_event_id!("$thread_root"),
|
||||
origin_server_ts: MilliSecondsSinceUnixEpoch(uint!(10_000)),
|
||||
room_id: owned_room_id!("!testroomid:example.org"),
|
||||
sender: owned_user_id!("@user:example.org"),
|
||||
unsigned: MessageLikeUnsigned::default(),
|
||||
};
|
||||
let thread_root = owned_event_id!("$thread_root");
|
||||
|
||||
let event_id_1 = event_id!("$event1");
|
||||
sync_builder.add_joined_room(JoinedRoomBuilder::new(room_id).add_timeline_event(
|
||||
event_builder.make_sync_message_event_with_id(
|
||||
&BOB,
|
||||
event_id_1,
|
||||
RoomMessageEventContent::text_plain("Hello, World!").make_for_thread(
|
||||
&thread_root,
|
||||
ReplyWithinThread::No,
|
||||
AddMentions::No,
|
||||
),
|
||||
let f = EventFactory::new();
|
||||
sync_builder.add_joined_room(
|
||||
JoinedRoomBuilder::new(room_id).add_timeline_event(
|
||||
f.text_msg("Hello, World!")
|
||||
.sender(&BOB)
|
||||
.event_id(event_id_1)
|
||||
.in_thread(&thread_root, &thread_root),
|
||||
),
|
||||
));
|
||||
);
|
||||
|
||||
mock_sync(&server, sync_builder.build_json_sync_response(), None).await;
|
||||
let _response = client.sync_once(sync_settings.clone()).await.unwrap();
|
||||
@@ -570,7 +555,6 @@ async fn test_send_reply_to_threaded() {
|
||||
async fn test_send_reply_with_event_id() {
|
||||
let room_id = room_id!("!a98sd12bjh:example.org");
|
||||
let (client, server) = logged_in_client_with_server().await;
|
||||
let event_builder = EventBuilder::new();
|
||||
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
||||
|
||||
let mut sync_builder = SyncResponseBuilder::new();
|
||||
@@ -588,11 +572,9 @@ async fn test_send_reply_with_event_id() {
|
||||
timeline.subscribe_filter_map(|item| item.as_event().cloned()).await;
|
||||
|
||||
let event_id_from_bob = event_id!("$event_from_bob");
|
||||
let raw_event_from_bob = event_builder.make_sync_message_event_with_id(
|
||||
&BOB,
|
||||
event_id_from_bob,
|
||||
RoomMessageEventContent::text_plain("Hello from Bob"),
|
||||
);
|
||||
let f = EventFactory::new();
|
||||
let raw_event_from_bob =
|
||||
f.text_msg("Hello from Bob").sender(&BOB).event_id(event_id_from_bob).into_raw_sync();
|
||||
sync_builder.add_joined_room(
|
||||
JoinedRoomBuilder::new(room_id).add_timeline_event(raw_event_from_bob.clone()),
|
||||
);
|
||||
@@ -689,7 +671,6 @@ async fn test_send_reply_with_event_id_that_is_redacted() {
|
||||
// the reply.
|
||||
let room_id = room_id!("!a98sd12bjh:example.org");
|
||||
let (client, server) = logged_in_client_with_server().await;
|
||||
let event_builder = EventBuilder::new();
|
||||
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
||||
|
||||
let mut sync_builder = SyncResponseBuilder::new();
|
||||
@@ -707,11 +688,11 @@ async fn test_send_reply_with_event_id_that_is_redacted() {
|
||||
timeline.subscribe_filter_map(|item| item.as_event().cloned()).await;
|
||||
|
||||
let redacted_event_id_from_bob = event_id!("$event_from_bob");
|
||||
let raw_redacted_event_from_bob = event_builder.make_sync_redacted_message_event_with_id(
|
||||
&BOB,
|
||||
redacted_event_id_from_bob,
|
||||
RedactedReactionEventContent::new(),
|
||||
);
|
||||
let f = EventFactory::new();
|
||||
let raw_redacted_event_from_bob = f
|
||||
.redacted(&BOB, RedactedReactionEventContent::new())
|
||||
.event_id(redacted_event_id_from_bob)
|
||||
.into_raw_sync();
|
||||
sync_builder.add_joined_room(
|
||||
JoinedRoomBuilder::new(room_id).add_timeline_event(raw_redacted_event_from_bob.clone()),
|
||||
);
|
||||
|
||||
@@ -21,15 +21,12 @@ use futures_util::{pin_mut, StreamExt};
|
||||
use matrix_sdk::{config::SyncSettings, test_utils::logged_in_client_with_server};
|
||||
use matrix_sdk_test::{
|
||||
async_test, event_factory::EventFactory, mocks::mock_encryption_state, sync_timeline_event,
|
||||
EventBuilder, GlobalAccountDataTestEvent, JoinedRoomBuilder, SyncResponseBuilder, ALICE, BOB,
|
||||
GlobalAccountDataTestEvent, JoinedRoomBuilder, SyncResponseBuilder, ALICE, BOB,
|
||||
};
|
||||
use matrix_sdk_ui::timeline::{RoomExt, TimelineDetails, TimelineItemContent};
|
||||
use ruma::{
|
||||
event_id,
|
||||
events::room::{
|
||||
member::{MembershipState, RoomMemberEventContent},
|
||||
message::{MessageType, RoomMessageEventContent},
|
||||
},
|
||||
events::room::{member::MembershipState, message::MessageType},
|
||||
room_id, user_id,
|
||||
};
|
||||
use serde_json::json;
|
||||
@@ -43,7 +40,7 @@ async fn test_batched() {
|
||||
let (client, server) = logged_in_client_with_server().await;
|
||||
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
||||
|
||||
let event_builder = EventBuilder::new();
|
||||
let f = EventFactory::new();
|
||||
let mut sync_builder = SyncResponseBuilder::new();
|
||||
sync_builder.add_joined_room(JoinedRoomBuilder::new(room_id));
|
||||
|
||||
@@ -66,20 +63,11 @@ async fn test_batched() {
|
||||
|
||||
sync_builder.add_joined_room(
|
||||
JoinedRoomBuilder::new(room_id)
|
||||
.add_timeline_event(event_builder.make_sync_message_event(
|
||||
&ALICE,
|
||||
RoomMessageEventContent::text_plain("text message event"),
|
||||
))
|
||||
.add_timeline_event(event_builder.make_sync_state_event(
|
||||
&BOB,
|
||||
BOB.as_str(),
|
||||
RoomMemberEventContent::new(MembershipState::Join),
|
||||
Some(RoomMemberEventContent::new(MembershipState::Invite)),
|
||||
))
|
||||
.add_timeline_event(event_builder.make_sync_message_event(
|
||||
&BOB,
|
||||
RoomMessageEventContent::notice_plain("notice message event"),
|
||||
)),
|
||||
.add_timeline_event(f.text_msg("text message event").sender(&ALICE))
|
||||
.add_timeline_event(
|
||||
f.member(&BOB).membership(MembershipState::Join).previous(MembershipState::Invite),
|
||||
)
|
||||
.add_timeline_event(f.notice("notice message event").sender(&BOB)),
|
||||
);
|
||||
|
||||
mock_sync(&server, sync_builder.build_json_sync_response(), None).await;
|
||||
|
||||
@@ -940,7 +940,7 @@ mod tests {
|
||||
assert_relations(
|
||||
room_id,
|
||||
f.text_msg("Original event").event_id(original_id).into(),
|
||||
f.reaction(original_id, ":D".to_owned()).event_id(related_id).into(),
|
||||
f.reaction(original_id, ":D").event_id(related_id).into(),
|
||||
f,
|
||||
)
|
||||
.await;
|
||||
@@ -958,7 +958,7 @@ mod tests {
|
||||
f.poll_start("Poll start event", "A poll question", vec!["An answer"])
|
||||
.event_id(original_id)
|
||||
.into(),
|
||||
f.poll_response("1", original_id).event_id(related_id).into(),
|
||||
f.poll_response(vec!["1"], original_id).event_id(related_id).into(),
|
||||
f,
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -25,21 +25,11 @@ use matrix_sdk::{
|
||||
Client,
|
||||
};
|
||||
use matrix_sdk_common::{executor::spawn, timeout::timeout};
|
||||
use matrix_sdk_test::{
|
||||
async_test, event_factory::EventFactory, EventBuilder, JoinedRoomBuilder, ALICE, BOB,
|
||||
};
|
||||
use matrix_sdk_test::{async_test, event_factory::EventFactory, JoinedRoomBuilder, ALICE, BOB};
|
||||
use once_cell::sync::Lazy;
|
||||
use ruma::{
|
||||
event_id,
|
||||
events::{
|
||||
room::{
|
||||
member::{MembershipState, RoomMemberEventContent},
|
||||
message::RoomMessageEventContent,
|
||||
name::RoomNameEventContent,
|
||||
topic::RoomTopicEventContent,
|
||||
},
|
||||
MessageLikeEventType, StateEventType,
|
||||
},
|
||||
events::{room::member::MembershipState, MessageLikeEventType, StateEventType},
|
||||
owned_room_id,
|
||||
serde::JsonObject,
|
||||
user_id, OwnedRoomId,
|
||||
@@ -308,7 +298,7 @@ async fn test_read_messages_with_msgtype_capabilities() {
|
||||
let chunk2 = vec![
|
||||
f.notice("custom content").event_id(event_id!("$msda7m0df9E9op3")).into_raw_timeline(),
|
||||
f.text_msg("hello").event_id(event_id!("$msda7m0df9E9op5")).into_raw_timeline(),
|
||||
f.reaction(event_id!("$event_id"), "annotation".to_owned()).into_raw_timeline(),
|
||||
f.reaction(event_id!("$event_id"), "annotation").into_raw_timeline(),
|
||||
];
|
||||
mock_server
|
||||
.mock_room_messages()
|
||||
@@ -398,51 +388,34 @@ async fn test_receive_live_events() {
|
||||
// No messages from the driver yet
|
||||
assert_matches!(recv_message(&driver_handle).now_or_never(), None);
|
||||
|
||||
let f = EventFactory::new();
|
||||
|
||||
mock_server
|
||||
.mock_sync()
|
||||
.ok_and_run(&client, |sync_builder| {
|
||||
let event_builder = EventBuilder::new();
|
||||
sync_builder.add_joined_room(
|
||||
JoinedRoomBuilder::new(&ROOM_ID)
|
||||
// text message from alice - matches filter #2
|
||||
.add_timeline_event(event_builder.make_sync_message_event(
|
||||
&ALICE,
|
||||
RoomMessageEventContent::text_plain("simple text message"),
|
||||
))
|
||||
.add_timeline_event(f.text_msg("simple text message").sender(&ALICE))
|
||||
// emote from alice - doesn't match
|
||||
.add_timeline_event(event_builder.make_sync_message_event(
|
||||
&ALICE,
|
||||
RoomMessageEventContent::emote_plain("emote message"),
|
||||
))
|
||||
.add_timeline_event(f.emote("emote message").sender(&ALICE))
|
||||
// pointless member event - matches filter #4
|
||||
.add_timeline_event(event_builder.make_sync_state_event(
|
||||
user_id!("@example:localhost"),
|
||||
"@example:localhost",
|
||||
RoomMemberEventContent::new(MembershipState::Join),
|
||||
Some(RoomMemberEventContent::new(MembershipState::Join)),
|
||||
))
|
||||
.add_timeline_event(
|
||||
f.member(user_id!("@example:localhost"))
|
||||
.membership(MembershipState::Join)
|
||||
.previous(MembershipState::Join),
|
||||
)
|
||||
// kick alice - doesn't match because the `#@example:localhost` bit
|
||||
// is about the state_key, not the sender
|
||||
.add_timeline_event(event_builder.make_sync_state_event(
|
||||
user_id!("@example:localhost"),
|
||||
ALICE.as_str(),
|
||||
RoomMemberEventContent::new(MembershipState::Ban),
|
||||
Some(RoomMemberEventContent::new(MembershipState::Join)),
|
||||
))
|
||||
// set room tpoic - doesn't match
|
||||
.add_timeline_event(event_builder.make_sync_state_event(
|
||||
&BOB,
|
||||
"",
|
||||
RoomTopicEventContent::new("new room topic".to_owned()),
|
||||
None,
|
||||
))
|
||||
.add_timeline_event(
|
||||
f.member(user_id!("@example:localhost"))
|
||||
.banned(&ALICE)
|
||||
.previous(MembershipState::Join),
|
||||
)
|
||||
// set room topic - doesn't match
|
||||
.add_timeline_event(f.room_topic("new room topic").sender(&BOB))
|
||||
// set room name - matches filter #3
|
||||
.add_timeline_event(event_builder.make_sync_state_event(
|
||||
&BOB,
|
||||
"",
|
||||
RoomNameEventContent::new("New Room Name".to_owned()),
|
||||
None,
|
||||
)),
|
||||
.add_timeline_event(f.room_name("New Room Name").sender(&BOB)),
|
||||
);
|
||||
})
|
||||
.await;
|
||||
|
||||
@@ -1,210 +0,0 @@
|
||||
// Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Unit tests (based on private methods) for the timeline API.
|
||||
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
sync::atomic::{AtomicU64, Ordering::SeqCst},
|
||||
};
|
||||
|
||||
use ruma::{
|
||||
events::{
|
||||
receipt::{Receipt, ReceiptEventContent, ReceiptThread, ReceiptType},
|
||||
AnySyncTimelineEvent, AnyTimelineEvent, MessageLikeEventContent,
|
||||
RedactedMessageLikeEventContent, RedactedStateEventContent, StateEventContent,
|
||||
},
|
||||
serde::Raw,
|
||||
server_name, EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedUserId, RoomId, UserId,
|
||||
};
|
||||
use serde_json::{json, Value as JsonValue};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct EventBuilder {
|
||||
next_ts: AtomicU64,
|
||||
}
|
||||
|
||||
impl EventBuilder {
|
||||
pub fn new() -> EventBuilder {
|
||||
Self { next_ts: AtomicU64::new(0) }
|
||||
}
|
||||
|
||||
pub fn next_server_ts(&self) -> MilliSecondsSinceUnixEpoch {
|
||||
MilliSecondsSinceUnixEpoch(
|
||||
self.next_ts
|
||||
.fetch_add(1, SeqCst)
|
||||
.try_into()
|
||||
.expect("server timestamp should fit in js_int::UInt"),
|
||||
)
|
||||
}
|
||||
|
||||
/// Set the next server timestamp.
|
||||
///
|
||||
/// Timestamps will continue to increase by 1 (millisecond) from that value.
|
||||
pub fn set_next_ts(&self, value: u64) {
|
||||
self.next_ts.store(value, SeqCst);
|
||||
}
|
||||
|
||||
pub fn make_state_event<C: StateEventContent>(
|
||||
&self,
|
||||
sender: &UserId,
|
||||
room_id: &RoomId,
|
||||
state_key: &str,
|
||||
content: C,
|
||||
prev_content: Option<C>,
|
||||
) -> Raw<AnyTimelineEvent> {
|
||||
let unsigned = if let Some(prev_content) = prev_content {
|
||||
json!({ "prev_content": prev_content })
|
||||
} else {
|
||||
json!({})
|
||||
};
|
||||
|
||||
timeline_event!({
|
||||
"type": content.event_type(),
|
||||
"state_key": state_key,
|
||||
"content": content,
|
||||
"event_id": EventId::new(server_name!("dummy.server")),
|
||||
"sender": sender,
|
||||
"room_id": room_id,
|
||||
"origin_server_ts": self.next_server_ts(),
|
||||
"unsigned": unsigned,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn make_sync_message_event<C: MessageLikeEventContent>(
|
||||
&self,
|
||||
sender: &UserId,
|
||||
content: C,
|
||||
) -> Raw<AnySyncTimelineEvent> {
|
||||
let event_id = EventId::new(server_name!("dummy.server"));
|
||||
self.make_sync_message_event_with_id(sender, &event_id, content)
|
||||
}
|
||||
|
||||
pub fn make_sync_message_event_with_id<C: MessageLikeEventContent>(
|
||||
&self,
|
||||
sender: &UserId,
|
||||
event_id: &EventId,
|
||||
content: C,
|
||||
) -> Raw<AnySyncTimelineEvent> {
|
||||
sync_timeline_event!({
|
||||
"type": content.event_type(),
|
||||
"content": content,
|
||||
"event_id": event_id,
|
||||
"sender": sender,
|
||||
"origin_server_ts": self.next_server_ts(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn make_sync_redacted_message_event<C: RedactedMessageLikeEventContent>(
|
||||
&self,
|
||||
sender: &UserId,
|
||||
content: C,
|
||||
) -> Raw<AnySyncTimelineEvent> {
|
||||
sync_timeline_event!({
|
||||
"type": content.event_type(),
|
||||
"content": content,
|
||||
"event_id": EventId::new(server_name!("dummy.server")),
|
||||
"sender": sender,
|
||||
"origin_server_ts": self.next_server_ts(),
|
||||
"unsigned": self.make_redacted_unsigned(sender),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn make_sync_redacted_message_event_with_id<C: RedactedMessageLikeEventContent>(
|
||||
&self,
|
||||
sender: &UserId,
|
||||
event_id: &EventId,
|
||||
content: C,
|
||||
) -> Raw<AnySyncTimelineEvent> {
|
||||
sync_timeline_event!({
|
||||
"type": content.event_type(),
|
||||
"content": content,
|
||||
"event_id": event_id,
|
||||
"sender": sender,
|
||||
"origin_server_ts": self.next_server_ts(),
|
||||
"unsigned": self.make_redacted_unsigned(sender),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn make_sync_state_event<C: StateEventContent>(
|
||||
&self,
|
||||
sender: &UserId,
|
||||
state_key: &str,
|
||||
content: C,
|
||||
prev_content: Option<C>,
|
||||
) -> Raw<AnySyncTimelineEvent> {
|
||||
let unsigned = if let Some(prev_content) = prev_content {
|
||||
json!({ "prev_content": prev_content })
|
||||
} else {
|
||||
json!({})
|
||||
};
|
||||
|
||||
sync_timeline_event!({
|
||||
"type": content.event_type(),
|
||||
"state_key": state_key,
|
||||
"content": content,
|
||||
"event_id": EventId::new(server_name!("dummy.server")),
|
||||
"sender": sender,
|
||||
"origin_server_ts": self.next_server_ts(),
|
||||
"unsigned": unsigned,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn make_sync_redacted_state_event<C: RedactedStateEventContent>(
|
||||
&self,
|
||||
sender: &UserId,
|
||||
state_key: &str,
|
||||
content: C,
|
||||
) -> Raw<AnySyncTimelineEvent> {
|
||||
sync_timeline_event!({
|
||||
"type": content.event_type(),
|
||||
"state_key": state_key,
|
||||
"content": content,
|
||||
"event_id": EventId::new(server_name!("dummy.server")),
|
||||
"sender": sender,
|
||||
"origin_server_ts": self.next_server_ts(),
|
||||
"unsigned": self.make_redacted_unsigned(sender),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn make_receipt_event_content(
|
||||
&self,
|
||||
receipts: impl IntoIterator<Item = (OwnedEventId, ReceiptType, OwnedUserId, ReceiptThread)>,
|
||||
) -> ReceiptEventContent {
|
||||
let mut ev_content = ReceiptEventContent(BTreeMap::new());
|
||||
for (event_id, receipt_type, user_id, thread) in receipts {
|
||||
let event_map = ev_content.entry(event_id).or_default();
|
||||
let receipt_map = event_map.entry(receipt_type).or_default();
|
||||
|
||||
let mut receipt = Receipt::new(self.next_server_ts());
|
||||
receipt.thread = thread;
|
||||
|
||||
receipt_map.insert(user_id, receipt);
|
||||
}
|
||||
|
||||
ev_content
|
||||
}
|
||||
|
||||
fn make_redacted_unsigned(&self, sender: &UserId) -> JsonValue {
|
||||
json!({
|
||||
"redacted_because": {
|
||||
"content": {},
|
||||
"event_id": EventId::new(server_name!("dummy.server")),
|
||||
"sender": sender,
|
||||
"origin_server_ts": self.next_server_ts(),
|
||||
"type": "m.room.redaction",
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -26,16 +26,16 @@ use matrix_sdk_common::deserialized_responses::{
|
||||
use ruma::{
|
||||
events::{
|
||||
member_hints::MemberHintsEventContent,
|
||||
message::TextContentBlock,
|
||||
poll::{
|
||||
end::PollEndEventContent,
|
||||
response::{PollResponseEventContent, SelectionsContentBlock},
|
||||
unstable_end::UnstablePollEndEventContent,
|
||||
unstable_response::UnstablePollResponseEventContent,
|
||||
unstable_start::{
|
||||
NewUnstablePollStartEventContent, ReplacementUnstablePollStartEventContent,
|
||||
UnstablePollAnswer, UnstablePollStartContentBlock, UnstablePollStartEventContent,
|
||||
},
|
||||
},
|
||||
reaction::ReactionEventContent,
|
||||
receipt::{Receipt, ReceiptEventContent, ReceiptThread, ReceiptType},
|
||||
relation::{Annotation, InReplyTo, Replacement, Thread},
|
||||
room::{
|
||||
encrypted::{EncryptedEventScheme, RoomEncryptedEventContent},
|
||||
@@ -44,13 +44,16 @@ use ruma::{
|
||||
FormattedBody, ImageMessageEventContent, MessageType, Relation,
|
||||
RoomMessageEventContent, RoomMessageEventContentWithoutRelation,
|
||||
},
|
||||
name::RoomNameEventContent,
|
||||
redaction::RoomRedactionEventContent,
|
||||
topic::RoomTopicEventContent,
|
||||
},
|
||||
AnySyncTimelineEvent, AnyTimelineEvent, BundledMessageLikeRelations, EventContent,
|
||||
RedactedMessageLikeEventContent, RedactedStateEventContent,
|
||||
},
|
||||
serde::Raw,
|
||||
server_name, EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedMxcUri, OwnedRoomId,
|
||||
OwnedTransactionId, OwnedUserId, RoomId, TransactionId, UInt, UserId,
|
||||
server_name, EventId, MilliSecondsSinceUnixEpoch, MxcUri, OwnedEventId, OwnedMxcUri,
|
||||
OwnedRoomId, OwnedTransactionId, OwnedUserId, RoomId, TransactionId, UInt, UserId,
|
||||
};
|
||||
use serde::Serialize;
|
||||
use serde_json::json;
|
||||
@@ -71,12 +74,43 @@ impl TimestampArg for u64 {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize)]
|
||||
struct Unsigned {
|
||||
/// A thin copy of [`ruma::events::UnsignedRoomRedactionEvent`].
|
||||
#[derive(Debug, Serialize)]
|
||||
struct RedactedBecause {
|
||||
/// Data specific to the event type.
|
||||
content: RoomRedactionEventContent,
|
||||
|
||||
/// The globally unique event identifier for the user who sent the event.
|
||||
event_id: OwnedEventId,
|
||||
|
||||
/// The fully-qualified ID of the user who sent this event.
|
||||
sender: OwnedUserId,
|
||||
|
||||
/// Timestamp in milliseconds on originating homeserver when this event was
|
||||
/// sent.
|
||||
origin_server_ts: MilliSecondsSinceUnixEpoch,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct Unsigned<C: EventContent> {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
prev_content: Option<C>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
transaction_id: Option<OwnedTransactionId>,
|
||||
|
||||
#[serde(rename = "m.relations", skip_serializing_if = "Option::is_none")]
|
||||
relations: Option<BundledMessageLikeRelations<Raw<AnySyncTimelineEvent>>>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
redacted_because: Option<RedactedBecause>,
|
||||
}
|
||||
|
||||
// rustc can't derive Default because C isn't marked as `Default` 🤔 oh well.
|
||||
impl<C: EventContent> Default for Unsigned<C> {
|
||||
fn default() -> Self {
|
||||
Self { prev_content: None, transaction_id: None, relations: None, redacted_because: None }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -87,7 +121,7 @@ pub struct EventBuilder<C: EventContent> {
|
||||
redacts: Option<OwnedEventId>,
|
||||
content: C,
|
||||
server_ts: MilliSecondsSinceUnixEpoch,
|
||||
unsigned: Option<Unsigned>,
|
||||
unsigned: Option<Unsigned<C>>,
|
||||
state_key: Option<String>,
|
||||
}
|
||||
|
||||
@@ -142,7 +176,7 @@ where
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn construct_json<T>(self, requires_room: bool) -> Raw<T> {
|
||||
fn construct_json(self, requires_room: bool) -> serde_json::Value {
|
||||
let event_id = self
|
||||
.event_id
|
||||
.or_else(|| {
|
||||
@@ -150,11 +184,18 @@ where
|
||||
})
|
||||
.unwrap_or_else(|| EventId::new(server_name!("dummy.org")));
|
||||
|
||||
// Use the `sender` preferably, or resort to the `redacted_because` sender if
|
||||
// none has been set.
|
||||
let sender = self
|
||||
.sender
|
||||
.or_else(|| Some(self.unsigned.as_ref()?.redacted_because.as_ref()?.sender.clone()))
|
||||
.expect("we should have a sender user id at this point");
|
||||
|
||||
let mut json = json!({
|
||||
"type": self.content.event_type(),
|
||||
"content": self.content,
|
||||
"event_id": event_id,
|
||||
"sender": self.sender.expect("we should have a sender user id at this point"),
|
||||
"sender": sender,
|
||||
"origin_server_ts": self.server_ts,
|
||||
});
|
||||
|
||||
@@ -177,7 +218,7 @@ where
|
||||
map.insert("state_key".to_owned(), json!(state_key));
|
||||
}
|
||||
|
||||
Raw::new(map).unwrap().cast()
|
||||
json
|
||||
}
|
||||
|
||||
/// Build an event from the [`EventBuilder`] and convert it into a
|
||||
@@ -186,11 +227,11 @@ where
|
||||
/// The generic argument `T` allows you to automatically cast the [`Raw`]
|
||||
/// event into any desired type.
|
||||
pub fn into_raw<T>(self) -> Raw<T> {
|
||||
self.construct_json(true)
|
||||
Raw::new(&self.construct_json(true)).unwrap().cast()
|
||||
}
|
||||
|
||||
pub fn into_raw_timeline(self) -> Raw<AnyTimelineEvent> {
|
||||
self.construct_json(true)
|
||||
Raw::new(&self.construct_json(true)).unwrap().cast()
|
||||
}
|
||||
|
||||
pub fn into_timeline(self) -> TimelineEvent {
|
||||
@@ -198,7 +239,7 @@ where
|
||||
}
|
||||
|
||||
pub fn into_raw_sync(self) -> Raw<AnySyncTimelineEvent> {
|
||||
self.construct_json(false)
|
||||
Raw::new(&self.construct_json(false)).unwrap().cast()
|
||||
}
|
||||
|
||||
pub fn into_sync(self) -> SyncTimelineEvent {
|
||||
@@ -360,6 +401,11 @@ impl EventFactory {
|
||||
self.event(RoomMessageEventContent::text_plain(content.into()))
|
||||
}
|
||||
|
||||
/// Create a new plain emote `m.room.message`.
|
||||
pub fn emote(&self, content: impl Into<String>) -> EventBuilder<RoomMessageEventContent> {
|
||||
self.event(RoomMessageEventContent::emote_plain(content.into()))
|
||||
}
|
||||
|
||||
/// Create a new `m.room.member` event for the given member.
|
||||
///
|
||||
/// The given member will be used as the `sender` as well as the `state_key`
|
||||
@@ -403,6 +449,22 @@ impl EventFactory {
|
||||
event
|
||||
}
|
||||
|
||||
/// Create a state event for the topic.
|
||||
pub fn room_topic(&self, topic: impl Into<String>) -> EventBuilder<RoomTopicEventContent> {
|
||||
let mut event = self.event(RoomTopicEventContent::new(topic.into()));
|
||||
// The state key is empty for a room topic state event.
|
||||
event.state_key = Some("".to_owned());
|
||||
event
|
||||
}
|
||||
|
||||
/// Create a state event for the room name.
|
||||
pub fn room_name(&self, name: impl Into<String>) -> EventBuilder<RoomNameEventContent> {
|
||||
let mut event = self.event(RoomNameEventContent::new(name.into()));
|
||||
// The state key is empty for a room name state event.
|
||||
event.state_key = Some("".to_owned());
|
||||
event
|
||||
}
|
||||
|
||||
/// Create a new `m.member_hints` event with the given service members.
|
||||
///
|
||||
/// ```
|
||||
@@ -449,18 +511,68 @@ impl EventFactory {
|
||||
pub fn reaction(
|
||||
&self,
|
||||
event_id: &EventId,
|
||||
annotation: String,
|
||||
annotation: impl Into<String>,
|
||||
) -> EventBuilder<ReactionEventContent> {
|
||||
self.event(ReactionEventContent::new(Annotation::new(event_id.to_owned(), annotation)))
|
||||
self.event(ReactionEventContent::new(Annotation::new(
|
||||
event_id.to_owned(),
|
||||
annotation.into(),
|
||||
)))
|
||||
}
|
||||
|
||||
/// Create a redaction for the given event id.
|
||||
/// Create a live redaction for the given event id.
|
||||
///
|
||||
/// Note: this is not a redacted event, but a redaction event, that will
|
||||
/// cause another event to be redacted.
|
||||
pub fn redaction(&self, event_id: &EventId) -> EventBuilder<RoomRedactionEventContent> {
|
||||
let mut builder = self.event(RoomRedactionEventContent::new_v11(event_id.to_owned()));
|
||||
builder.redacts = Some(event_id.to_owned());
|
||||
builder
|
||||
}
|
||||
|
||||
/// Create a redacted event, with extra information in the unsigned section
|
||||
/// about the redaction itself.
|
||||
pub fn redacted<T: RedactedMessageLikeEventContent>(
|
||||
&self,
|
||||
redacter: &UserId,
|
||||
content: T,
|
||||
) -> EventBuilder<T> {
|
||||
let mut builder = self.event(content);
|
||||
|
||||
let redacted_because = RedactedBecause {
|
||||
content: RoomRedactionEventContent::default(),
|
||||
event_id: EventId::new(server_name!("dummy.server")),
|
||||
sender: redacter.to_owned(),
|
||||
origin_server_ts: self.next_server_ts(),
|
||||
};
|
||||
builder.unsigned.get_or_insert_with(Default::default).redacted_because =
|
||||
Some(redacted_because);
|
||||
|
||||
builder
|
||||
}
|
||||
|
||||
/// Create a redacted state event, with extra information in the unsigned
|
||||
/// section about the redaction itself.
|
||||
pub fn redacted_state<T: RedactedStateEventContent>(
|
||||
&self,
|
||||
redacter: &UserId,
|
||||
state_key: impl Into<String>,
|
||||
content: T,
|
||||
) -> EventBuilder<T> {
|
||||
let mut builder = self.event(content);
|
||||
|
||||
let redacted_because = RedactedBecause {
|
||||
content: RoomRedactionEventContent::default(),
|
||||
event_id: EventId::new(server_name!("dummy.server")),
|
||||
sender: redacter.to_owned(),
|
||||
origin_server_ts: self.next_server_ts(),
|
||||
};
|
||||
builder.unsigned.get_or_insert_with(Default::default).redacted_because =
|
||||
Some(redacted_because);
|
||||
builder.state_key = Some(state_key.into());
|
||||
|
||||
builder
|
||||
}
|
||||
|
||||
/// Create a poll start event given a text, the question and the possible
|
||||
/// answers.
|
||||
pub fn poll_start(
|
||||
@@ -510,13 +622,13 @@ impl EventFactory {
|
||||
/// start event id.
|
||||
pub fn poll_response(
|
||||
&self,
|
||||
answer_id: impl Into<String>,
|
||||
answers: Vec<impl Into<String>>,
|
||||
poll_start_id: &EventId,
|
||||
) -> EventBuilder<PollResponseEventContent> {
|
||||
let selection_content: SelectionsContentBlock = vec![answer_id.into()].into();
|
||||
let poll_response_content =
|
||||
PollResponseEventContent::new(selection_content, poll_start_id.to_owned());
|
||||
self.event(poll_response_content)
|
||||
) -> EventBuilder<UnstablePollResponseEventContent> {
|
||||
self.event(UnstablePollResponseEventContent::new(
|
||||
answers.into_iter().map(Into::into).collect(),
|
||||
poll_start_id.to_owned(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Create a poll response with the given text and the associated poll start
|
||||
@@ -525,12 +637,8 @@ impl EventFactory {
|
||||
&self,
|
||||
content: impl Into<String>,
|
||||
poll_start_id: &EventId,
|
||||
) -> EventBuilder<PollEndEventContent> {
|
||||
let poll_end_content = PollEndEventContent::new(
|
||||
TextContentBlock::plain(content.into()),
|
||||
poll_start_id.to_owned(),
|
||||
);
|
||||
self.event(poll_end_content)
|
||||
) -> EventBuilder<UnstablePollEndEventContent> {
|
||||
self.event(UnstablePollEndEventContent::new(content.into(), poll_start_id.to_owned()))
|
||||
}
|
||||
|
||||
/// Creates a plain (unencrypted) image event content referencing the given
|
||||
@@ -544,6 +652,11 @@ impl EventFactory {
|
||||
self.event(RoomMessageEventContent::new(MessageType::Image(image_event_content)))
|
||||
}
|
||||
|
||||
/// Create a read receipt event.
|
||||
pub fn read_receipts(&self) -> ReadReceiptBuilder<'_> {
|
||||
ReadReceiptBuilder { factory: self, content: ReceiptEventContent(Default::default()) }
|
||||
}
|
||||
|
||||
/// Set the next server timestamp.
|
||||
///
|
||||
/// Timestamps will continue to increase by 1 (millisecond) from that value.
|
||||
@@ -562,9 +675,134 @@ impl EventBuilder<RoomMemberEventContent> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Set that the sender of this event invited the user passed as a parameter
|
||||
/// here.
|
||||
pub fn invited(mut self, invited_user: &UserId) -> Self {
|
||||
assert_ne!(
|
||||
self.sender.as_deref().unwrap(),
|
||||
invited_user,
|
||||
"invited user and sender can't be the same person"
|
||||
);
|
||||
self.content.membership = MembershipState::Invite;
|
||||
self.state_key = Some(invited_user.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set that the sender of this event kicked the user passed as a parameter
|
||||
/// here.
|
||||
pub fn kicked(mut self, kicked_user: &UserId) -> Self {
|
||||
assert_ne!(
|
||||
self.sender.as_deref().unwrap(),
|
||||
kicked_user,
|
||||
"kicked user and sender can't be the same person, otherwise it's just a Leave"
|
||||
);
|
||||
self.content.membership = MembershipState::Leave;
|
||||
self.state_key = Some(kicked_user.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set that the sender of this event banned the user passed as a parameter
|
||||
/// here.
|
||||
pub fn banned(mut self, banned_user: &UserId) -> Self {
|
||||
assert_ne!(
|
||||
self.sender.as_deref().unwrap(),
|
||||
banned_user,
|
||||
"a user can't ban itself" // hopefully
|
||||
);
|
||||
self.content.membership = MembershipState::Ban;
|
||||
self.state_key = Some(banned_user.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the display name of the `m.room.member` event.
|
||||
pub fn display_name(mut self, display_name: impl Into<String>) -> Self {
|
||||
self.content.displayname = Some(display_name.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the avatar URL of the `m.room.member` event.
|
||||
pub fn avatar_url(mut self, url: &MxcUri) -> Self {
|
||||
self.content.avatar_url = Some(url.to_owned());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the reason field of the `m.room.member` event.
|
||||
pub fn reason(mut self, reason: impl Into<String>) -> Self {
|
||||
self.content.reason = Some(reason.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the previous membership state (in the unsigned section).
|
||||
pub fn previous(mut self, previous: impl Into<PreviousMembership>) -> Self {
|
||||
let previous = previous.into();
|
||||
|
||||
let mut prev_content = RoomMemberEventContent::new(previous.state);
|
||||
if let Some(avatar_url) = previous.avatar_url {
|
||||
prev_content.avatar_url = Some(avatar_url);
|
||||
}
|
||||
if let Some(display_name) = previous.display_name {
|
||||
prev_content.displayname = Some(display_name);
|
||||
}
|
||||
|
||||
self.unsigned.get_or_insert_with(Default::default).prev_content = Some(prev_content);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ReadReceiptBuilder<'a> {
|
||||
factory: &'a EventFactory,
|
||||
content: ReceiptEventContent,
|
||||
}
|
||||
|
||||
impl ReadReceiptBuilder<'_> {
|
||||
/// Add a single read receipt to the event.
|
||||
pub fn add(
|
||||
mut self,
|
||||
event_id: &EventId,
|
||||
user_id: &UserId,
|
||||
tyype: ReceiptType,
|
||||
thread: ReceiptThread,
|
||||
) -> Self {
|
||||
let by_event = self.content.0.entry(event_id.to_owned()).or_default();
|
||||
let by_type = by_event.entry(tyype).or_default();
|
||||
|
||||
let mut receipt = Receipt::new(self.factory.next_server_ts());
|
||||
receipt.thread = thread;
|
||||
|
||||
by_type.insert(user_id.to_owned(), receipt);
|
||||
self
|
||||
}
|
||||
|
||||
/// Finalize the builder into the receipt event content.
|
||||
pub fn build(self) -> ReceiptEventContent {
|
||||
self.content
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PreviousMembership {
|
||||
state: MembershipState,
|
||||
avatar_url: Option<OwnedMxcUri>,
|
||||
display_name: Option<String>,
|
||||
}
|
||||
|
||||
impl PreviousMembership {
|
||||
pub fn new(state: MembershipState) -> Self {
|
||||
Self { state, avatar_url: None, display_name: None }
|
||||
}
|
||||
|
||||
pub fn avatar_url(mut self, url: &MxcUri) -> Self {
|
||||
self.avatar_url = Some(url.to_owned());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn display_name(mut self, name: impl Into<String>) -> Self {
|
||||
self.display_name = Some(name.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MembershipState> for PreviousMembership {
|
||||
fn from(state: MembershipState) -> Self {
|
||||
Self::new(state)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,8 +111,6 @@ pub mod __macro_support {
|
||||
pub use tracing_subscriber;
|
||||
}
|
||||
|
||||
mod event_builder;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub mod mocks;
|
||||
|
||||
@@ -121,13 +119,10 @@ pub mod notification_settings;
|
||||
mod sync_builder;
|
||||
pub mod test_json;
|
||||
|
||||
pub use self::{
|
||||
event_builder::EventBuilder,
|
||||
sync_builder::{
|
||||
bulk_room_members, EphemeralTestEvent, GlobalAccountDataTestEvent, InvitedRoomBuilder,
|
||||
JoinedRoomBuilder, KnockedRoomBuilder, LeftRoomBuilder, PresenceTestEvent,
|
||||
RoomAccountDataTestEvent, StateTestEvent, StrippedStateTestEvent, SyncResponseBuilder,
|
||||
},
|
||||
pub use self::sync_builder::{
|
||||
bulk_room_members, EphemeralTestEvent, GlobalAccountDataTestEvent, InvitedRoomBuilder,
|
||||
JoinedRoomBuilder, KnockedRoomBuilder, LeftRoomBuilder, PresenceTestEvent,
|
||||
RoomAccountDataTestEvent, StateTestEvent, StrippedStateTestEvent, SyncResponseBuilder,
|
||||
};
|
||||
|
||||
pub static ALICE: Lazy<&UserId> = Lazy::new(|| user_id!("@alice:server.name"));
|
||||
|
||||
Reference in New Issue
Block a user