matrix_sdk_base/room/
tombstone.rs1use std::ops::Not;
16
17use ruma::{OwnedRoomId, events::room::tombstone::RoomTombstoneEventContent};
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()
71 .and_then(|content_event| content_event.predecessor)
72 .map(|predecessor| PredecessorRoom { room_id: predecessor.room_id })
73 }
74}
75
76#[derive(Debug)]
84pub struct SuccessorRoom {
85 pub room_id: OwnedRoomId,
87
88 pub reason: Option<String>,
90}
91
92#[derive(Debug)]
101pub struct PredecessorRoom {
102 pub room_id: OwnedRoomId,
104}
105
106#[cfg(test)]
107mod tests {
108 use std::ops::Not;
109
110 use assert_matches::assert_matches;
111 use matrix_sdk_test::{
112 JoinedRoomBuilder, SyncResponseBuilder, async_test, event_factory::EventFactory,
113 };
114 use ruma::{RoomVersionId, room_id, user_id};
115
116 use crate::{RoomState, test_utils::logged_in_base_client};
117
118 #[async_test]
119 async fn test_no_successor_room() {
120 let client = logged_in_base_client(None).await;
121 let room = client.get_or_create_room(room_id!("!r0"), RoomState::Joined);
122
123 assert!(room.is_tombstoned().not());
124 assert!(room.tombstone_content().is_none());
125 assert!(room.successor_room().is_none());
126 }
127
128 #[async_test]
129 async fn test_successor_room() {
130 let client = logged_in_base_client(None).await;
131 let sender = user_id!("@mnt_io:matrix.org");
132 let room_id = room_id!("!r0");
133 let successor_room_id = room_id!("!r1");
134 let room = client.get_or_create_room(room_id, RoomState::Joined);
135
136 let mut sync_builder = SyncResponseBuilder::new();
137 let response = sync_builder
138 .add_joined_room(
139 JoinedRoomBuilder::new(room_id).add_timeline_event(
140 EventFactory::new()
141 .sender(sender)
142 .room_tombstone("traces of you", successor_room_id),
143 ),
144 )
145 .build_sync_response();
146
147 client.receive_sync_response(response).await.unwrap();
148
149 assert!(room.is_tombstoned());
150 assert!(room.tombstone_content().is_some());
151 assert_matches!(room.successor_room(), Some(successor_room) => {
152 assert_eq!(successor_room.room_id, successor_room_id);
153 assert_matches!(successor_room.reason, Some(reason) => {
154 assert_eq!(reason, "traces of you");
155 });
156 });
157 }
158
159 #[async_test]
160 async fn test_successor_room_no_reason() {
161 let client = logged_in_base_client(None).await;
162 let sender = user_id!("@mnt_io:matrix.org");
163 let room_id = room_id!("!r0");
164 let successor_room_id = room_id!("!r1");
165 let room = client.get_or_create_room(room_id, RoomState::Joined);
166
167 let mut sync_builder = SyncResponseBuilder::new();
168 let response = sync_builder
169 .add_joined_room(JoinedRoomBuilder::new(room_id).add_timeline_event(
170 EventFactory::new().sender(sender).room_tombstone(
171 "",
173 successor_room_id,
174 ),
175 ))
176 .build_sync_response();
177
178 client.receive_sync_response(response).await.unwrap();
179
180 assert!(room.is_tombstoned());
181 assert!(room.tombstone_content().is_some());
182 assert_matches!(room.successor_room(), Some(successor_room) => {
183 assert_eq!(successor_room.room_id, successor_room_id);
184 assert!(successor_room.reason.is_none());
185 });
186 }
187
188 #[async_test]
189 async fn test_no_predecessor_room() {
190 let client = logged_in_base_client(None).await;
191 let room = client.get_or_create_room(room_id!("!r0"), RoomState::Joined);
192
193 assert!(room.create_content().is_none());
194 assert!(room.predecessor_room().is_none());
195 }
196
197 #[async_test]
198 async fn test_no_predecessor_room_with_create_event() {
199 let client = logged_in_base_client(None).await;
200 let sender = user_id!("@mnt_io:matrix.org");
201 let room_id = room_id!("!r1");
202 let room = client.get_or_create_room(room_id, RoomState::Joined);
203
204 let mut sync_builder = SyncResponseBuilder::new();
205 let response = sync_builder
206 .add_joined_room(
207 JoinedRoomBuilder::new(room_id).add_timeline_event(
208 EventFactory::new()
209 .create(sender, RoomVersionId::V11)
210 .no_predecessor()
212 .into_raw_sync(),
213 ),
214 )
215 .build_sync_response();
216
217 client.receive_sync_response(response).await.unwrap();
218
219 assert!(room.create_content().is_some());
220 assert!(room.predecessor_room().is_none());
221 }
222
223 #[async_test]
224 async fn test_predecessor_room() {
225 let client = logged_in_base_client(None).await;
226 let sender = user_id!("@mnt_io:matrix.org");
227 let room_id = room_id!("!r1");
228 let predecessor_room_id = room_id!("!r0");
229 let room = client.get_or_create_room(room_id, RoomState::Joined);
230
231 let mut sync_builder = SyncResponseBuilder::new();
232 let response = sync_builder
233 .add_joined_room(
234 JoinedRoomBuilder::new(room_id).add_timeline_event(
235 EventFactory::new()
236 .create(sender, RoomVersionId::V11)
237 .predecessor(predecessor_room_id)
238 .into_raw_sync(),
239 ),
240 )
241 .build_sync_response();
242
243 client.receive_sync_response(response).await.unwrap();
244
245 assert!(room.create_content().is_some());
246 assert_matches!(room.predecessor_room(), Some(predecessor_room) => {
247 assert_eq!(predecessor_room.room_id, predecessor_room_id);
248 });
249 }
250}