matrix_sdk_base/room/
tombstone.rs1use std::ops::Not;
16
17use ruma::{events::room::tombstone::RoomTombstoneEventContent, OwnedEventId, OwnedRoomId};
18
19use super::Room;
20
21impl Room {
22 pub fn is_tombstoned(&self) -> bool {
29 self.inner.read().base_info.tombstone.is_some()
30 }
31
32 pub fn tombstone_content(&self) -> Option<RoomTombstoneEventContent> {
40 self.inner.read().tombstone().cloned()
41 }
42
43 pub fn successor_room(&self) -> Option<SuccessorRoom> {
51 self.tombstone_content().map(|tombstone_event| SuccessorRoom {
52 room_id: tombstone_event.replacement_room,
53 reason: tombstone_event.body.is_empty().not().then_some(tombstone_event.body),
54 })
55 }
56
57 pub fn predecessor_room(&self) -> Option<PredecessorRoom> {
70 self.create_content().and_then(|content_event| content_event.predecessor).map(
71 |predecessor| PredecessorRoom {
72 room_id: predecessor.room_id,
73 last_event_id: predecessor.event_id,
74 },
75 )
76 }
77}
78
79#[derive(Debug)]
87pub struct SuccessorRoom {
88 pub room_id: OwnedRoomId,
90
91 pub reason: Option<String>,
93}
94
95#[derive(Debug)]
104pub struct PredecessorRoom {
105 pub room_id: OwnedRoomId,
107
108 pub last_event_id: OwnedEventId,
110}
111
112#[cfg(test)]
113mod tests {
114 use std::ops::Not;
115
116 use assert_matches::assert_matches;
117 use matrix_sdk_test::{
118 async_test, event_factory::EventFactory, JoinedRoomBuilder, SyncResponseBuilder,
119 };
120 use ruma::{event_id, room_id, user_id, RoomVersionId};
121
122 use crate::{test_utils::logged_in_base_client, RoomState};
123
124 #[async_test]
125 async fn test_no_successor_room() {
126 let client = logged_in_base_client(None).await;
127 let room = client.get_or_create_room(room_id!("!r0"), RoomState::Joined);
128
129 assert!(room.is_tombstoned().not());
130 assert!(room.tombstone_content().is_none());
131 assert!(room.successor_room().is_none());
132 }
133
134 #[async_test]
135 async fn test_successor_room() {
136 let client = logged_in_base_client(None).await;
137 let sender = user_id!("@mnt_io:matrix.org");
138 let room_id = room_id!("!r0");
139 let successor_room_id = room_id!("!r1");
140 let room = client.get_or_create_room(room_id, RoomState::Joined);
141
142 let mut sync_builder = SyncResponseBuilder::new();
143 let response = sync_builder
144 .add_joined_room(
145 JoinedRoomBuilder::new(room_id).add_timeline_event(
146 EventFactory::new()
147 .sender(sender)
148 .room_tombstone("traces of you", successor_room_id),
149 ),
150 )
151 .build_sync_response();
152
153 client.receive_sync_response(response).await.unwrap();
154
155 assert!(room.is_tombstoned());
156 assert!(room.tombstone_content().is_some());
157 assert_matches!(room.successor_room(), Some(successor_room) => {
158 assert_eq!(successor_room.room_id, successor_room_id);
159 assert_matches!(successor_room.reason, Some(reason) => {
160 assert_eq!(reason, "traces of you");
161 });
162 });
163 }
164
165 #[async_test]
166 async fn test_successor_room_no_reason() {
167 let client = logged_in_base_client(None).await;
168 let sender = user_id!("@mnt_io:matrix.org");
169 let room_id = room_id!("!r0");
170 let successor_room_id = room_id!("!r1");
171 let room = client.get_or_create_room(room_id, RoomState::Joined);
172
173 let mut sync_builder = SyncResponseBuilder::new();
174 let response = sync_builder
175 .add_joined_room(JoinedRoomBuilder::new(room_id).add_timeline_event(
176 EventFactory::new().sender(sender).room_tombstone(
177 "",
179 successor_room_id,
180 ),
181 ))
182 .build_sync_response();
183
184 client.receive_sync_response(response).await.unwrap();
185
186 assert!(room.is_tombstoned());
187 assert!(room.tombstone_content().is_some());
188 assert_matches!(room.successor_room(), Some(successor_room) => {
189 assert_eq!(successor_room.room_id, successor_room_id);
190 assert!(successor_room.reason.is_none());
191 });
192 }
193
194 #[async_test]
195 async fn test_no_predecessor_room() {
196 let client = logged_in_base_client(None).await;
197 let room = client.get_or_create_room(room_id!("!r0"), RoomState::Joined);
198
199 assert!(room.create_content().is_none());
200 assert!(room.predecessor_room().is_none());
201 }
202
203 #[async_test]
204 async fn test_no_predecessor_room_with_create_event() {
205 let client = logged_in_base_client(None).await;
206 let sender = user_id!("@mnt_io:matrix.org");
207 let room_id = room_id!("!r1");
208 let room = client.get_or_create_room(room_id, RoomState::Joined);
209
210 let mut sync_builder = SyncResponseBuilder::new();
211 let response = sync_builder
212 .add_joined_room(
213 JoinedRoomBuilder::new(room_id).add_timeline_event(
214 EventFactory::new()
215 .create(sender, RoomVersionId::V11)
216 .no_predecessor()
218 .into_raw_sync(),
219 ),
220 )
221 .build_sync_response();
222
223 client.receive_sync_response(response).await.unwrap();
224
225 assert!(room.create_content().is_some());
226 assert!(room.predecessor_room().is_none());
227 }
228
229 #[async_test]
230 async fn test_predecessor_room() {
231 let client = logged_in_base_client(None).await;
232 let sender = user_id!("@mnt_io:matrix.org");
233 let room_id = room_id!("!r1");
234 let predecessor_room_id = room_id!("!r0");
235 let predecessor_last_event_id = event_id!("$ev42");
236 let room = client.get_or_create_room(room_id, RoomState::Joined);
237
238 let mut sync_builder = SyncResponseBuilder::new();
239 let response = sync_builder
240 .add_joined_room(
241 JoinedRoomBuilder::new(room_id).add_timeline_event(
242 EventFactory::new()
243 .create(sender, RoomVersionId::V11)
244 .predecessor(predecessor_room_id, predecessor_last_event_id)
245 .into_raw_sync(),
246 ),
247 )
248 .build_sync_response();
249
250 client.receive_sync_response(response).await.unwrap();
251
252 assert!(room.create_content().is_some());
253 assert_matches!(room.predecessor_room(), Some(predecessor_room) => {
254 assert_eq!(predecessor_room.room_id, predecessor_room_id);
255 assert_eq!(predecessor_room.last_event_id, predecessor_last_event_id);
256 });
257 }
258}