|
|
|
@ -5,16 +5,113 @@ use log::{error, info, warn}; |
|
|
|
use solstice_proto::{server, User};
|
|
|
|
use thiserror::Error;
|
|
|
|
|
|
|
|
use crate::room::{Membership, Room, Visibility};
|
|
|
|
use crate::room::{RoomMembership, RoomMessage, RoomState, RoomVisibility};
|
|
|
|
|
|
|
|
/// The error returned by RoomMap functions.
|
|
|
|
#[derive(Debug, Error)]
|
|
|
|
pub enum RoomError {
|
|
|
|
#[error("room {0} not found")]
|
|
|
|
RoomNotFound(String),
|
|
|
|
#[error(transparent)]
|
|
|
|
RoomNotFound(#[from] RoomNotFoundError),
|
|
|
|
|
|
|
|
#[error("cannot change membership from {0:?} to {1:?}")]
|
|
|
|
MembershipChangeInvalid(Membership, Membership),
|
|
|
|
#[error(transparent)]
|
|
|
|
MembershipChangeInvalid(#[from] RoomMembershipChangeError),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Error)]
|
|
|
|
#[error("cannot change membership from {0:?} to {1:?}")]
|
|
|
|
pub struct RoomMembershipChangeError(RoomMembership, RoomMembership);
|
|
|
|
|
|
|
|
#[derive(Debug, Error)]
|
|
|
|
#[error("room {0} not found")]
|
|
|
|
pub struct RoomNotFoundError(String);
|
|
|
|
|
|
|
|
/// An entry in the chat room map.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct RoomEntry {
|
|
|
|
name: String,
|
|
|
|
state: RoomState,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RoomEntry {
|
|
|
|
/// Creates a new entry with the given state.
|
|
|
|
pub fn new(name: String, state: RoomState) -> Self {
|
|
|
|
Self { name, state }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a copy of the room state contained in this entry.
|
|
|
|
pub fn clone_state(&self) -> RoomState {
|
|
|
|
self.state.clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the state contained in this entry.
|
|
|
|
#[cfg(test)]
|
|
|
|
pub fn into_state(self) -> RoomState {
|
|
|
|
self.state
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Inserts the given message in this chat room's history.
|
|
|
|
pub fn insert_message(&mut self, message: RoomMessage) {
|
|
|
|
self.state.messages.insert(message)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Records that we are now trying to join this room.
|
|
|
|
/// Returns an error if its membership is not `NonMember`,
|
|
|
|
pub fn start_joining(&mut self) -> Result<(), RoomMembershipChangeError> {
|
|
|
|
match self.state.membership {
|
|
|
|
RoomMembership::NonMember => {
|
|
|
|
self.state.membership = RoomMembership::Joining;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
membership => Err(RoomMembershipChangeError(
|
|
|
|
membership,
|
|
|
|
RoomMembership::Joining,
|
|
|
|
)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Records that we are now a member of this room and updates its state.
|
|
|
|
pub fn join(
|
|
|
|
&mut self,
|
|
|
|
owner: Option<String>,
|
|
|
|
mut operators: Vec<String>,
|
|
|
|
members: &[User],
|
|
|
|
) {
|
|
|
|
// Log what's happening.
|
|
|
|
if let RoomMembership::Joining = self.state.membership {
|
|
|
|
info!("Joined room {:?}", self.name);
|
|
|
|
} else {
|
|
|
|
warn!(
|
|
|
|
"Joined room {:?} but membership was already {:?}",
|
|
|
|
self.name, self.state.membership
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the room state.
|
|
|
|
self.state.membership = RoomMembership::Member;
|
|
|
|
self.state.user_count = members.len();
|
|
|
|
self.state.owner = owner;
|
|
|
|
self.state.operators = operators.drain(..).collect();
|
|
|
|
self.state.members = members.iter().map(|user| user.name.clone()).collect();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Records that we are now trying to leave the given room.
|
|
|
|
/// If the room is not found, or if its membership status is not `Member`,
|
|
|
|
/// returns an error.
|
|
|
|
#[cfg(test)]
|
|
|
|
pub fn start_leaving(&mut self) -> Result<(), RoomMembershipChangeError> {
|
|
|
|
match self.state.membership {
|
|
|
|
RoomMembership::Member => {
|
|
|
|
self.state.membership = RoomMembership::Leaving;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
membership => Err(RoomMembershipChangeError(
|
|
|
|
membership,
|
|
|
|
RoomMembership::Leaving,
|
|
|
|
)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Contains the mapping from room names to room data and provides a clean
|
|
|
|
@ -22,7 +119,7 @@ pub enum RoomError { |
|
|
|
#[derive(Debug, Default)]
|
|
|
|
pub struct RoomMap {
|
|
|
|
/// The actual map from room names to room data.
|
|
|
|
map: HashMap<String, Room>,
|
|
|
|
map: HashMap<String, RoomEntry>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RoomMap {
|
|
|
|
@ -33,16 +130,23 @@ impl RoomMap { |
|
|
|
|
|
|
|
/// Inserts the given room in the map under the given name.
|
|
|
|
/// Same semantics as `std::collections::HashMap::insert()`.
|
|
|
|
pub fn insert(&mut self, name: String, room: Room) -> Option<Room> {
|
|
|
|
self.map.insert(name, room)
|
|
|
|
pub fn insert(&mut self, name: String, room: RoomState) -> Option<RoomState> {
|
|
|
|
self
|
|
|
|
.map
|
|
|
|
.insert(name.clone(), RoomEntry::new(name, room))
|
|
|
|
.map(|entry| entry.state)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Looks up the given room name in the map, returning an immutable
|
|
|
|
/// reference to the associated data if found, or an error if not found.
|
|
|
|
pub fn get_strict(&self, room_name: &str) -> Result<&Room, RoomError> {
|
|
|
|
#[cfg(test)]
|
|
|
|
pub fn get_strict(
|
|
|
|
&self,
|
|
|
|
room_name: &str,
|
|
|
|
) -> Result<&RoomEntry, RoomNotFoundError> {
|
|
|
|
match self.map.get(room_name) {
|
|
|
|
Some(room) => Ok(room),
|
|
|
|
None => Err(RoomError::RoomNotFound(room_name.to_string())),
|
|
|
|
None => Err(RoomNotFoundError(room_name.to_string())),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@ -51,10 +155,10 @@ impl RoomMap { |
|
|
|
pub fn get_mut_strict(
|
|
|
|
&mut self,
|
|
|
|
room_name: &str,
|
|
|
|
) -> Result<&mut Room, RoomError> {
|
|
|
|
) -> Result<&mut RoomEntry, RoomNotFoundError> {
|
|
|
|
match self.map.get_mut(room_name) {
|
|
|
|
Some(room) => Ok(room),
|
|
|
|
None => Err(RoomError::RoomNotFound(room_name.to_string())),
|
|
|
|
None => Err(RoomNotFoundError(room_name.to_string())),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@ -63,16 +167,16 @@ impl RoomMap { |
|
|
|
fn update_one(
|
|
|
|
&mut self,
|
|
|
|
name: String,
|
|
|
|
visibility: Visibility,
|
|
|
|
visibility: RoomVisibility,
|
|
|
|
user_count: u32,
|
|
|
|
old_map: &mut HashMap<String, Room>,
|
|
|
|
old_map: &mut HashMap<String, RoomEntry>,
|
|
|
|
) {
|
|
|
|
let room = match old_map.remove(&name) {
|
|
|
|
None => Room::new(Visibility::Public, user_count as usize),
|
|
|
|
Some(mut room) => {
|
|
|
|
room.visibility = visibility;
|
|
|
|
room.user_count = user_count as usize;
|
|
|
|
room
|
|
|
|
None => RoomState::new(RoomVisibility::Public, user_count as usize),
|
|
|
|
Some(mut entry) => {
|
|
|
|
entry.state.visibility = visibility;
|
|
|
|
entry.state.user_count = user_count as usize;
|
|
|
|
entry.state
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if let Some(_) = self.insert(name, room) {
|
|
|
|
@ -88,122 +192,53 @@ impl RoomMap { |
|
|
|
|
|
|
|
// Add all public rooms.
|
|
|
|
for (name, user_count) in response.rooms.drain(..) {
|
|
|
|
self.update_one(name, Visibility::Public, user_count, &mut old_map);
|
|
|
|
self.update_one(name, RoomVisibility::Public, user_count, &mut old_map);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add all private, owned, rooms.
|
|
|
|
for (name, user_count) in response.owned_private_rooms.drain(..) {
|
|
|
|
self.update_one(name, Visibility::PrivateOwned, user_count, &mut old_map);
|
|
|
|
self.update_one(
|
|
|
|
name,
|
|
|
|
RoomVisibility::PrivateOwned,
|
|
|
|
user_count,
|
|
|
|
&mut old_map,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add all private, unowned, rooms.
|
|
|
|
for (name, user_count) in response.other_private_rooms.drain(..) {
|
|
|
|
self.update_one(name, Visibility::PrivateOther, user_count, &mut old_map);
|
|
|
|
self.update_one(
|
|
|
|
name,
|
|
|
|
RoomVisibility::PrivateOther,
|
|
|
|
user_count,
|
|
|
|
&mut old_map,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mark all operated rooms as necessary.
|
|
|
|
for name in response.operated_private_room_names.iter() {
|
|
|
|
match self.map.get_mut(name) {
|
|
|
|
Some(room) => room.operated = true,
|
|
|
|
Some(room) => room.state.operated = true,
|
|
|
|
None => error!("Room {} is operated but does not exist", name),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the list of (room name, room data) representing all known rooms.
|
|
|
|
pub fn get_room_list(&self) -> Vec<(String, Room)> {
|
|
|
|
pub fn get_room_list(&self) -> Vec<(String, RoomState)> {
|
|
|
|
let mut rooms = Vec::new();
|
|
|
|
for (room_name, room) in self.map.iter() {
|
|
|
|
rooms.push((room_name.clone(), room.clone()));
|
|
|
|
rooms.push((room_name.clone(), room.clone_state()));
|
|
|
|
}
|
|
|
|
rooms
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Records that we are now trying to join the given room.
|
|
|
|
/// If the room is not found, or if its membership is not `NonMember`,
|
|
|
|
/// returns an error.
|
|
|
|
pub fn start_joining(&mut self, room_name: &str) -> Result<(), RoomError> {
|
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
|
|
|
|
|
match room.membership {
|
|
|
|
Membership::NonMember => {
|
|
|
|
room.membership = Membership::Joining;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
membership => Err(RoomError::MembershipChangeInvalid(
|
|
|
|
membership,
|
|
|
|
Membership::Joining,
|
|
|
|
)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Records that we are now a member of the given room and updates the room
|
|
|
|
/// information.
|
|
|
|
pub fn join(
|
|
|
|
&mut self,
|
|
|
|
room_name: &str,
|
|
|
|
owner: Option<String>,
|
|
|
|
mut operators: Vec<String>,
|
|
|
|
members: &[User],
|
|
|
|
) -> Result<&Room, RoomError> {
|
|
|
|
// First look up the room struct.
|
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
|
|
|
|
|
// Log what's happening.
|
|
|
|
if let Membership::Joining = room.membership {
|
|
|
|
info!("Joined room {:?}", room_name);
|
|
|
|
} else {
|
|
|
|
warn!(
|
|
|
|
"Joined room {:?} but membership was already {:?}",
|
|
|
|
room_name, room.membership
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the room struct.
|
|
|
|
room.membership = Membership::Member;
|
|
|
|
room.user_count = members.len();
|
|
|
|
room.owner = owner;
|
|
|
|
|
|
|
|
room.operators.clear();
|
|
|
|
for user_name in operators.drain(..) {
|
|
|
|
room.operators.insert(user_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
room.members.clear();
|
|
|
|
for user in members {
|
|
|
|
room.members.insert(user.name.clone());
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(room)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
/// Records that we are now trying to leave the given room.
|
|
|
|
/// If the room is not found, or if its membership status is not `Member`,
|
|
|
|
/// returns an error.
|
|
|
|
pub fn start_leaving(&mut self, room_name: &str) -> Result<(), RoomError> {
|
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
|
|
|
|
|
match room.membership {
|
|
|
|
Membership::Member => {
|
|
|
|
room.membership = Membership::Leaving;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
membership => Err(RoomError::MembershipChangeInvalid(
|
|
|
|
membership,
|
|
|
|
Membership::Leaving,
|
|
|
|
)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Records that we have now left the given room.
|
|
|
|
pub fn leave(&mut self, room_name: &str) -> Result<(), RoomError> {
|
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
|
|
|
|
|
match room.membership {
|
|
|
|
Membership::Leaving => info!("Left room {:?}", room_name),
|
|
|
|
match room.state.membership {
|
|
|
|
RoomMembership::Leaving => info!("Left room {:?}", room_name),
|
|
|
|
|
|
|
|
membership => warn!(
|
|
|
|
"Left room {:?} with wrong membership: {:?}",
|
|
|
|
@ -211,7 +246,7 @@ impl RoomMap { |
|
|
|
),
|
|
|
|
}
|
|
|
|
|
|
|
|
room.membership = Membership::NonMember;
|
|
|
|
room.state.membership = RoomMembership::NonMember;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
@ -223,7 +258,7 @@ impl RoomMap { |
|
|
|
user_name: String,
|
|
|
|
) -> Result<(), RoomError> {
|
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
|
room.members.insert(user_name);
|
|
|
|
room.state.members.insert(user_name);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
@ -235,7 +270,7 @@ impl RoomMap { |
|
|
|
user_name: &str,
|
|
|
|
) -> Result<(), RoomError> {
|
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
|
room.members.remove(user_name);
|
|
|
|
room.state.members.remove(user_name);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
@ -249,127 +284,121 @@ impl RoomMap { |
|
|
|
tickers: Vec<(String, String)>,
|
|
|
|
) -> Result<(), RoomError> {
|
|
|
|
let room = self.get_mut_strict(room_name)?;
|
|
|
|
room.tickers = tickers;
|
|
|
|
room.state.tickers = tickers;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use std::time::{Duration, SystemTime};
|
|
|
|
use std::collections::HashSet;
|
|
|
|
|
|
|
|
use solstice_proto::server::RoomListResponse;
|
|
|
|
|
|
|
|
use crate::room::{Membership, Message, MessageHistory, Room, Visibility};
|
|
|
|
use crate::room::{RoomMembership, RoomState, RoomVisibility};
|
|
|
|
|
|
|
|
use super::RoomMap;
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn deserialize_membership() {
|
|
|
|
assert_eq!(
|
|
|
|
serde_json::from_str::<Membership>(r#""Member""#).unwrap(),
|
|
|
|
Membership::Member
|
|
|
|
);
|
|
|
|
fn entry_start_joining_error() {
|
|
|
|
let initial_state = RoomState {
|
|
|
|
membership: RoomMembership::Member,
|
|
|
|
..RoomState::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut room = RoomEntry::new("bleep".to_string(), initial_state.clone());
|
|
|
|
|
|
|
|
room.start_joining().unwrap_err();
|
|
|
|
|
|
|
|
assert_eq!(room.into_state(), initial_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn deserialize_visibility() {
|
|
|
|
fn entry_start_joining_success() {
|
|
|
|
let mut room = RoomEntry::new("bleep".to_string(), RoomState::default());
|
|
|
|
|
|
|
|
room.start_joining().unwrap();
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
serde_json::from_str::<Visibility>(r#""Public""#).unwrap(),
|
|
|
|
Visibility::Public
|
|
|
|
room.into_state(),
|
|
|
|
RoomState {
|
|
|
|
membership: RoomMembership::Joining,
|
|
|
|
..RoomState::default()
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn deserialize_message() {
|
|
|
|
fn entry_join() {
|
|
|
|
let mut room = RoomEntry::new("bleep".to_string(), RoomState::default());
|
|
|
|
|
|
|
|
let owner = Some("owner".to_string());
|
|
|
|
let mut operators = vec!["operator1".to_string(), "operator2".to_string()];
|
|
|
|
let users = [
|
|
|
|
User {
|
|
|
|
name: "shruti".to_string(),
|
|
|
|
..User::default()
|
|
|
|
},
|
|
|
|
User {
|
|
|
|
name: "kim".to_string(),
|
|
|
|
..User::default()
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
|
|
|
room.join(owner.clone(), operators.clone(), &users);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
serde_json::from_str::<Message>(
|
|
|
|
r#"{
|
|
|
|
"received_at": { "secs_since_epoch": 42, "nanos_since_epoch": 1337 },
|
|
|
|
"user_name":"karandeep",
|
|
|
|
"message":"namaste"
|
|
|
|
}"#
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
Message {
|
|
|
|
received_at: SystemTime::UNIX_EPOCH
|
|
|
|
+ Duration::from_secs(42)
|
|
|
|
+ Duration::from_nanos(1337),
|
|
|
|
user_name: "karandeep".to_string(),
|
|
|
|
message: "namaste".to_string()
|
|
|
|
room.into_state(),
|
|
|
|
RoomState {
|
|
|
|
membership: RoomMembership::Member,
|
|
|
|
owner: owner,
|
|
|
|
operators: operators.drain(..).collect::<HashSet<String>>(),
|
|
|
|
user_count: 2,
|
|
|
|
members: users
|
|
|
|
.iter()
|
|
|
|
.map(|user| user.name.clone())
|
|
|
|
.collect::<HashSet<String>>(),
|
|
|
|
..RoomState::default()
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn deserialize_room() {
|
|
|
|
fn entry_start_leaving_error() {
|
|
|
|
let mut room = RoomEntry::new("bleep".to_string(), RoomState::default());
|
|
|
|
|
|
|
|
room.start_leaving().unwrap_err();
|
|
|
|
|
|
|
|
assert_eq!(room.into_state(), RoomState::default());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn entry_start_leaving_success() {
|
|
|
|
let initial_state = RoomState {
|
|
|
|
membership: RoomMembership::Member,
|
|
|
|
..RoomState::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut room = RoomEntry::new("bleep".to_string(), initial_state.clone());
|
|
|
|
|
|
|
|
room.start_leaving().unwrap();
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
serde_json::from_str::<Room>(
|
|
|
|
r#"{
|
|
|
|
"membership": "Joining",
|
|
|
|
"visibility": "PrivateOwned",
|
|
|
|
"operated": false,
|
|
|
|
"user_count": 3,
|
|
|
|
"owner": null,
|
|
|
|
"operators": ["op1", "op2"],
|
|
|
|
"members": ["m1", "m2"],
|
|
|
|
"messages": [
|
|
|
|
{
|
|
|
|
"received_at": { "secs_since_epoch": 43, "nanos_since_epoch": 0 },
|
|
|
|
"user_name": "u2",
|
|
|
|
"message": "msg2"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"received_at": { "secs_since_epoch": 42, "nanos_since_epoch": 0 },
|
|
|
|
"user_name": "u1",
|
|
|
|
"message": "msg1"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"tickers": [["t11", "t12"], ["t21", "t22"]]
|
|
|
|
}"#
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
Room {
|
|
|
|
membership: Membership::Joining,
|
|
|
|
visibility: Visibility::PrivateOwned,
|
|
|
|
operated: false,
|
|
|
|
user_count: 3,
|
|
|
|
owner: None,
|
|
|
|
operators: ["op1".to_string(), "op2".to_string()]
|
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.collect(),
|
|
|
|
members: ["m1".to_string(), "m2".to_string()]
|
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.collect(),
|
|
|
|
messages: MessageHistory::new(vec![
|
|
|
|
Message {
|
|
|
|
received_at: SystemTime::UNIX_EPOCH + Duration::from_secs(42),
|
|
|
|
user_name: "u1".to_string(),
|
|
|
|
message: "msg1".to_string(),
|
|
|
|
},
|
|
|
|
Message {
|
|
|
|
received_at: SystemTime::UNIX_EPOCH + Duration::from_secs(43),
|
|
|
|
user_name: "u2".to_string(),
|
|
|
|
message: "msg2".to_string(),
|
|
|
|
}
|
|
|
|
]),
|
|
|
|
tickers: vec![
|
|
|
|
("t11".to_string(), "t12".to_string()),
|
|
|
|
("t21".to_string(), "t22".to_string()),
|
|
|
|
],
|
|
|
|
room.into_state(),
|
|
|
|
RoomState {
|
|
|
|
membership: RoomMembership::Leaving,
|
|
|
|
..initial_state
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn room_map_new_is_empty() {
|
|
|
|
fn map_new_is_empty() {
|
|
|
|
assert_eq!(RoomMap::new().get_room_list(), vec![]);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn room_map_get_strict() {
|
|
|
|
fn map_get_strict() {
|
|
|
|
let mut rooms = RoomMap::new();
|
|
|
|
rooms.set_room_list(RoomListResponse {
|
|
|
|
rooms: vec![("room a".to_string(), 42), ("room b".to_string(), 1337)],
|
|
|
|
@ -379,8 +408,8 @@ mod tests { |
|
|
|
});
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
rooms.get_strict("room a").unwrap(),
|
|
|
|
&Room::new(Visibility::Public, 42)
|
|
|
|
rooms.get_strict("room a").unwrap().clone_state(),
|
|
|
|
RoomState::new(RoomVisibility::Public, 42)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|