1
0
Fork 0
ruma/crates/ruma-events/tests/it/relations.rs
Kévin Commaille 31bd360db8 events: Prevent hidden _Custom variant types to be deserialized
To prevent users from constructing them.

We also change some methods to access the custom data to work with all
variants, otherwise they might break when new variants are added.
2026-04-25 15:26:46 +02:00

402 lines
13 KiB
Rust

use assert_matches2::{assert_let, assert_matches};
use assign::assign;
#[cfg(feature = "unstable-msc3381")]
use ruma_common::event_id;
use ruma_common::{canonical_json::assert_to_canonical_json_eq, owned_event_id, serde::Raw};
#[cfg(feature = "unstable-msc3381")]
use ruma_events::poll::{
start::{PollAnswer, PollContentBlock, PollStartEventContent},
unstable_start::{
NewUnstablePollStartEventContent, UnstablePollAnswer, UnstablePollStartContentBlock,
UnstablePollStartEventContent,
},
};
#[cfg(feature = "unstable-msc3381")]
use ruma_events::{
AnyMessageLikeEventContent,
message::TextContentBlock,
room::{encrypted, message::RelationWithoutReplacement},
};
use ruma_events::{
relation::{Replacement, Reply, Thread},
room::message::{MessageType, Relation, RoomMessageEventContent},
};
use serde_json::{Value as JsonValue, from_value as from_json_value, json};
#[test]
fn reply_deserialize() {
let json = json!({
"msgtype": "m.text",
"body": "<text msg>",
"m.relates_to": {
"m.in_reply_to": {
"event_id": "$1598361704261elfgc:localhost",
},
},
});
assert_matches!(
from_json_value::<RoomMessageEventContent>(json),
Ok(RoomMessageEventContent {
msgtype: MessageType::Text(_),
relates_to: Some(Relation::Reply(reply)),
..
})
);
assert_eq!(reply.in_reply_to.event_id, "$1598361704261elfgc:localhost");
}
#[test]
fn reply_serialize() {
let content = assign!(RoomMessageEventContent::text_plain("This is a reply"), {
relates_to: Some(Relation::Reply(Reply::with_event_id(owned_event_id!("$1598361704261elfgc")) )),
});
assert_to_canonical_json_eq!(
content,
json!({
"msgtype": "m.text",
"body": "This is a reply",
"m.relates_to": {
"m.in_reply_to": {
"event_id": "$1598361704261elfgc",
},
},
})
);
}
#[test]
fn reply_serialization_roundtrip() {
let body = "This is a reply";
let mut content = RoomMessageEventContent::text_plain(body);
let event_id = owned_event_id!("$1598361704261elfgc");
content.relates_to = Some(Relation::Reply(Reply::with_event_id(event_id.clone())));
let json_content = Raw::new(&content).unwrap();
let deser_content = json_content.deserialize().unwrap();
assert_matches!(deser_content.msgtype, MessageType::Text(deser_msg));
assert_eq!(deser_msg.body, body);
assert_matches!(content.relates_to.unwrap(), Relation::Reply(reply));
assert_eq!(reply.in_reply_to.event_id, event_id);
}
#[test]
fn replacement_serialize() {
let content = assign!(
RoomMessageEventContent::text_plain("<text msg>"),
{
relates_to: Some(Relation::Replacement(
Replacement::new(
owned_event_id!("$1598361704261elfgc"),
RoomMessageEventContent::text_plain("This is the new content.").into(),
)
))
}
);
assert_to_canonical_json_eq!(
content,
json!({
"msgtype": "m.text",
"body": "<text msg>",
"m.new_content": {
"body": "This is the new content.",
"msgtype": "m.text",
},
"m.relates_to": {
"rel_type": "m.replace",
"event_id": "$1598361704261elfgc",
},
})
);
}
#[test]
fn replacement_deserialize() {
let json = json!({
"msgtype": "m.text",
"body": "<text msg>",
"m.new_content": {
"body": "Hello! My name is bar",
"msgtype": "m.text",
},
"m.relates_to": {
"rel_type": "m.replace",
"event_id": "$1598361704261elfgc",
},
});
assert_matches!(
from_json_value::<RoomMessageEventContent>(json),
Ok(RoomMessageEventContent {
msgtype: MessageType::Text(_),
relates_to: Some(Relation::Replacement(replacement)),
..
})
);
assert_eq!(replacement.event_id, "$1598361704261elfgc");
assert_matches!(replacement.new_content.msgtype, MessageType::Text(text));
assert_eq!(text.body, "Hello! My name is bar");
}
#[test]
fn replacement_serialization_roundtrip() {
let body = "<text msg>";
let mut content = RoomMessageEventContent::text_plain(body);
let new_body = "This is the new content.";
let replacement = Replacement::new(
owned_event_id!("$1598361704261elfgc"),
RoomMessageEventContent::text_plain(new_body).into(),
);
content.relates_to = Some(Relation::Replacement(replacement.clone()));
let json_content = Raw::new(&content).unwrap();
let deser_content = json_content.deserialize().unwrap();
assert_matches!(deser_content.msgtype, MessageType::Text(deser_msg));
assert_eq!(deser_msg.body, body);
assert_matches!(content.relates_to.unwrap(), Relation::Replacement(deser_replacement));
assert_eq!(deser_replacement.event_id, replacement.event_id);
assert_matches!(deser_replacement.new_content.msgtype, MessageType::Text(deser_new_msg));
assert_eq!(deser_new_msg.body, new_body);
}
#[test]
fn thread_plain_serialize() {
let content = assign!(
RoomMessageEventContent::text_plain("<text msg>"),
{
relates_to: Some(Relation::Thread(
Thread::plain(
owned_event_id!("$1598361704261elfgc"),
owned_event_id!("$latesteventid"),
),
)),
}
);
assert_to_canonical_json_eq!(
content,
json!({
"msgtype": "m.text",
"body": "<text msg>",
"m.relates_to": {
"rel_type": "m.thread",
"event_id": "$1598361704261elfgc",
"m.in_reply_to": {
"event_id": "$latesteventid",
},
"is_falling_back": true,
},
})
);
}
#[test]
fn thread_reply_serialize() {
let content = assign!(
RoomMessageEventContent::text_plain("<text msg>"),
{
relates_to: Some(Relation::Thread(
Thread::reply(
owned_event_id!("$1598361704261elfgc"),
owned_event_id!("$repliedtoeventid"),
),
)),
}
);
assert_to_canonical_json_eq!(
content,
json!({
"msgtype": "m.text",
"body": "<text msg>",
"m.relates_to": {
"rel_type": "m.thread",
"event_id": "$1598361704261elfgc",
"m.in_reply_to": {
"event_id": "$repliedtoeventid",
},
},
})
);
}
#[test]
fn thread_stable_deserialize() {
let json = json!({
"msgtype": "m.text",
"body": "<text msg>",
"m.relates_to": {
"rel_type": "m.thread",
"event_id": "$1598361704261elfgc",
},
});
assert_matches!(
from_json_value::<RoomMessageEventContent>(json),
Ok(RoomMessageEventContent {
msgtype: MessageType::Text(_),
relates_to: Some(Relation::Thread(thread)),
..
})
);
assert_eq!(thread.event_id, "$1598361704261elfgc");
assert_matches!(thread.in_reply_to, None);
assert!(!thread.is_falling_back);
}
#[test]
fn thread_stable_reply_deserialize() {
let json = json!({
"msgtype": "m.text",
"body": "<text msg>",
"m.relates_to": {
"rel_type": "m.thread",
"event_id": "$1598361704261elfgc",
"m.in_reply_to": {
"event_id": "$latesteventid",
},
},
});
assert_matches!(
from_json_value::<RoomMessageEventContent>(json),
Ok(RoomMessageEventContent {
msgtype: MessageType::Text(_),
relates_to: Some(Relation::Thread(thread)),
..
})
);
assert_eq!(thread.event_id, "$1598361704261elfgc");
assert_eq!(thread.in_reply_to.unwrap().event_id, "$latesteventid");
assert!(!thread.is_falling_back);
}
#[test]
fn thread_unstable_deserialize() {
let json = json!({
"msgtype": "m.text",
"body": "<text msg>",
"m.relates_to": {
"rel_type": "io.element.thread",
"event_id": "$1598361704261elfgc",
"m.in_reply_to": {
"event_id": "$latesteventid",
},
},
});
assert_matches!(
from_json_value::<RoomMessageEventContent>(json),
Ok(RoomMessageEventContent {
msgtype: MessageType::Text(_),
relates_to: Some(Relation::Thread(thread)),
..
})
);
assert_eq!(thread.event_id, "$1598361704261elfgc");
assert_eq!(thread.in_reply_to.unwrap().event_id, "$latesteventid");
assert!(!thread.is_falling_back);
}
#[test]
fn thread_serialization_roundtrip() {
let body = "<text msg>";
let mut content = RoomMessageEventContent::text_plain(body);
let thread =
Thread::plain(owned_event_id!("$1598361704261elfgc"), owned_event_id!("$latesteventid"));
content.relates_to = Some(Relation::Thread(thread.clone()));
let json_content = Raw::new(&content).unwrap();
let deser_content = json_content.deserialize().unwrap();
assert_matches!(deser_content.msgtype, MessageType::Text(deser_msg));
assert_eq!(deser_msg.body, body);
assert_matches!(content.relates_to.unwrap(), Relation::Thread(deser_thread));
assert_eq!(deser_thread.event_id, thread.event_id);
assert_eq!(deser_thread.in_reply_to.unwrap().event_id, thread.in_reply_to.unwrap().event_id);
assert_eq!(deser_thread.is_falling_back, thread.is_falling_back);
}
#[test]
fn custom_serialization_roundtrip() {
let relation_json = json!({
"rel_type": "io.ruma.unknown",
"event_id": "$related_event",
"key": "value",
});
let content_json = json!({
"msgtype": "m.text",
"body": "<text msg>",
"m.relates_to": relation_json,
});
let content = from_json_value::<RoomMessageEventContent>(content_json.clone()).unwrap();
assert_let!(
RoomMessageEventContent { msgtype: MessageType::Text(_), relates_to: Some(relation), .. } =
&content
);
assert_eq!(relation.rel_type().unwrap().as_str(), "io.ruma.unknown");
assert_eq!(JsonValue::Object(relation.data().into_owned()), relation_json);
assert_to_canonical_json_eq!(content, content_json);
}
#[cfg(feature = "unstable-msc3381")]
#[test]
fn unstable_poll_start_event_return_relations() {
let event_content = AnyMessageLikeEventContent::UnstablePollStart(
UnstablePollStartEventContent::New(assign!(NewUnstablePollStartEventContent::plain_text(
"A poll",
UnstablePollStartContentBlock::new(
"A question",
vec![
UnstablePollAnswer::new("id1", "A"),
UnstablePollAnswer::new("id2", "B")
].try_into().unwrap()
)
), {
relates_to: Some(RelationWithoutReplacement::Thread(Thread::plain(
owned_event_id!("$thread_root_id"),
owned_event_id!("$prev_event_id")
))),
})),
);
assert_let!(Some(encrypted::Relation::Thread(thread)) = event_content.relation());
assert_eq!(thread.event_id, event_id!("$thread_root_id"));
assert!(thread.is_falling_back);
assert_let!(Some(in_reply_to) = thread.in_reply_to);
assert_eq!(in_reply_to.event_id, event_id!("$prev_event_id"));
}
#[cfg(feature = "unstable-msc3381")]
#[test]
fn stable_poll_start_event_return_relations() {
let event_content =
AnyMessageLikeEventContent::PollStart(assign!(PollStartEventContent::with_plain_text(
"A poll",
PollContentBlock::new(
TextContentBlock::plain("A question"),
vec![
PollAnswer::new("id1".to_owned(), TextContentBlock::plain("A")),
PollAnswer::new("id2".to_owned(), TextContentBlock::plain("B"))
].try_into().unwrap()
)
), {
relates_to: Some(Relation::Thread(Thread::plain(
owned_event_id!("$thread_root_id"),
owned_event_id!("$prev_event_id")
))),
}));
assert_let!(Some(encrypted::Relation::Thread(thread)) = event_content.relation());
assert_eq!(thread.event_id, event_id!("$thread_root_id"));
assert!(thread.is_falling_back);
assert_let!(Some(in_reply_to) = thread.in_reply_to);
assert_eq!(in_reply_to.event_id, event_id!("$prev_event_id"));
}