From df58c60d2e552b6eaf315c275a1374ee80290e41 Mon Sep 17 00:00:00 2001 From: Devin R Date: Tue, 31 Mar 2020 09:01:48 -0400 Subject: [PATCH] add tests in models files, run coverage --- src/async_client.rs | 2 +- src/base_client.rs | 61 ++++++++++++++++++++++++- src/models/room.rs | 54 ++++++++++++++++++++++ src/models/room_member.rs | 90 ++++++++++++++++++++++++++++++++++++- tests/async_client_tests.rs | 32 ++++++++++++- tests/data/sync.json | 20 ++++++++- 6 files changed, 251 insertions(+), 8 deletions(-) diff --git a/src/async_client.rs b/src/async_client.rs index 2d0e0097..43e2c4f3 100644 --- a/src/async_client.rs +++ b/src/async_client.rs @@ -62,7 +62,7 @@ pub struct AsyncClient { /// The underlying HTTP client. http_client: reqwest::Client, /// User session data. - base_client: Arc>, + pub(crate) base_client: Arc>, /// The transaction id. transaction_id: Arc, /// Event callbacks diff --git a/src/base_client.rs b/src/base_client.rs index 613c189c..6333992f 100644 --- a/src/base_client.rs +++ b/src/base_client.rs @@ -71,9 +71,20 @@ pub struct CurrentRoom { } impl CurrentRoom { + // TODO when UserId is isomorphic to &str clean this up. pub(crate) fn comes_after(&self, user: &Uid, event: &PresenceEvent) -> bool { - if user == &event.sender { - event.content.last_active_ago < self.last_active + let u = user.to_string(); + let u = u.split(':').next(); + + let s = event.sender.to_string(); + let s = s.split(':').next(); + + if u == s { + if self.last_active.is_none() { + true + } else { + event.content.last_active_ago < self.last_active + } } else { false } @@ -327,6 +338,7 @@ impl Client { .as_ref() .expect("to receive events you must be logged in") .user_id; + if self.current_room_id.comes_after(user_id, event) { self.current_room_id.update(room_id, event); } @@ -424,3 +436,48 @@ impl Client { Ok(()) } } + +#[cfg(test)] +mod test { + use super::*; + + use crate::events::room::member::MembershipState; + use crate::identifiers::UserId; + use crate::{AsyncClient, Session, SyncSettings}; + + use mockito::{mock, Matcher}; + use tokio::runtime::Runtime; + use url::Url; + + use std::convert::TryFrom; + use std::str::FromStr; + use std::time::Duration; + + #[tokio::test] + async fn account_data() { + let homeserver = Url::from_str(&mockito::server_url()).unwrap(); + + let session = Session { + access_token: "1234".to_owned(), + user_id: UserId::try_from("@example:example.com").unwrap(), + device_id: "DEVICEID".to_owned(), + }; + + let _m = mock( + "GET", + Matcher::Regex(r"^/_matrix/client/r0/sync\?.*$".to_string()), + ) + .with_status(200) + .with_body_from_file("tests/data/sync.json") + .create(); + + let mut client = AsyncClient::new(homeserver, Some(session)).unwrap(); + + let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000)); + + let _response = client.sync(sync_settings).await.unwrap(); + + let bc = &client.base_client.read().await; + assert_eq!(1, bc.ignored_users.len()) + } +} diff --git a/src/models/room.rs b/src/models/room.rs index 9e847295..428d7342 100644 --- a/src/models/room.rs +++ b/src/models/room.rs @@ -296,3 +296,57 @@ impl Room { } } } + +#[cfg(test)] +mod test { + use super::*; + + use crate::events::room::member::MembershipState; + use crate::identifiers::UserId; + use crate::{AsyncClient, Session, SyncSettings}; + + use mockito::{mock, Matcher}; + use tokio::runtime::Runtime; + use url::Url; + + use std::convert::TryFrom; + use std::str::FromStr; + use std::time::Duration; + + #[tokio::test] + async fn user_presence() { + let homeserver = Url::from_str(&mockito::server_url()).unwrap(); + + let session = Session { + access_token: "1234".to_owned(), + user_id: UserId::try_from("@example:example.com").unwrap(), + device_id: "DEVICEID".to_owned(), + }; + + let _m = mock( + "GET", + Matcher::Regex(r"^/_matrix/client/r0/sync\?.*$".to_string()), + ) + .with_status(200) + .with_body_from_file("tests/data/sync.json") + .create(); + + let mut client = AsyncClient::new(homeserver, Some(session)).unwrap(); + + let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000)); + + let _response = client.sync(sync_settings).await.unwrap(); + + let rooms = &client.base_client.read().await.joined_rooms; + let room = &rooms + .get("!SVkFJHzfwvuaIEawgC:localhost") + .unwrap() + .read() + .unwrap(); + + assert_eq!(2, room.members.len()); + for (id, member) in &room.members { + assert_eq!(MembershipState::Join, member.membership); + } + } +} diff --git a/src/models/room_member.rs b/src/models/room_member.rs index d86eeff0..9c806c18 100644 --- a/src/models/room_member.rs +++ b/src/models/room_member.rs @@ -110,10 +110,10 @@ impl RoomMember { let mut changed = false; if let Some(user_power) = event.content.users.get(&self.user_id) { - changed = self.power_level == Some(*user_power); + changed = self.power_level != Some(*user_power); self.power_level = Some(*user_power); } else { - changed = self.power_level == Some(event.content.users_default); + changed = self.power_level != Some(event.content.users_default); self.power_level = Some(event.content.users_default); } @@ -124,3 +124,89 @@ impl RoomMember { changed } } + +#[cfg(test)] +mod test { + use super::*; + + use crate::identifiers::{EventId, RoomId, UserId}; + use crate::{AsyncClient, Session, SyncSettings}; + + use js_int::{Int, UInt}; + use mockito::{mock, Matcher}; + use tokio::runtime::Runtime; + use url::Url; + + use std::collections::HashMap; + use std::convert::TryFrom; + use std::str::FromStr; + use std::time::Duration; + + use crate::events::room::power_levels::{ + NotificationPowerLevels, PowerLevelsEvent, PowerLevelsEventContent, + }; + + #[tokio::test] + async fn member_power() { + let homeserver = Url::from_str(&mockito::server_url()).unwrap(); + + let session = Session { + access_token: "1234".to_owned(), + user_id: UserId::try_from("@example:example.com").unwrap(), + device_id: "DEVICEID".to_owned(), + }; + + let _m = mock( + "GET", + Matcher::Regex(r"^/_matrix/client/r0/sync\?.*$".to_string()), + ) + .with_status(200) + .with_body_from_file("tests/data/sync.json") + .create(); + + let mut client = AsyncClient::new(homeserver, Some(session)).unwrap(); + + let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000)); + + let _response = client.sync(sync_settings).await.unwrap(); + + let mut rooms = client.base_client.write().await.joined_rooms.clone(); + let mut room = rooms + .get_mut("!SVkFJHzfwvuaIEawgC:localhost") + .unwrap() + .write() + .unwrap(); + + for (id, member) in &mut room.members { + let power = power_levels(); + assert!(member.update_power(&power)); + assert_eq!(MembershipState::Join, member.membership); + } + } + + fn power_levels() -> PowerLevelsEvent { + PowerLevelsEvent { + content: PowerLevelsEventContent { + ban: Int::new(40).unwrap(), + events: HashMap::default(), + events_default: Int::new(40).unwrap(), + invite: Int::new(40).unwrap(), + kick: Int::new(40).unwrap(), + redact: Int::new(40).unwrap(), + state_default: Int::new(40).unwrap(), + users: HashMap::default(), + users_default: Int::new(40).unwrap(), + notifications: NotificationPowerLevels { + room: Int::new(35).unwrap(), + }, + }, + event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(), + origin_server_ts: UInt::new(1520372800469).unwrap(), + prev_content: None, + room_id: RoomId::try_from("!roomid:room.com").ok(), + unsigned: None, + sender: UserId::try_from("@example:example.com").unwrap(), + state_key: "@example:example.com".into(), + } + } +} diff --git a/tests/async_client_tests.rs b/tests/async_client_tests.rs index e37de610..415dec98 100644 --- a/tests/async_client_tests.rs +++ b/tests/async_client_tests.rs @@ -59,7 +59,7 @@ async fn sync() { } #[tokio::test] -async fn timeline() { +async fn room_names() { let homeserver = Url::from_str(&mockito::server_url()).unwrap(); let session = Session { @@ -88,3 +88,33 @@ async fn timeline() { client.get_room_name("!SVkFJHzfwvuaIEawgC:localhost").await ); } + +#[tokio::test] +async fn current_room() { + let homeserver = Url::from_str(&mockito::server_url()).unwrap(); + + let session = Session { + access_token: "1234".to_owned(), + user_id: UserId::try_from("@example:example.com").unwrap(), + device_id: "DEVICEID".to_owned(), + }; + + let _m = mock( + "GET", + Matcher::Regex(r"^/_matrix/client/r0/sync\?.*$".to_string()), + ) + .with_status(200) + .with_body_from_file("tests/data/sync.json") + .create(); + + let mut client = AsyncClient::new(homeserver, Some(session)).unwrap(); + + let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000)); + + let _response = client.sync(sync_settings).await.unwrap(); + + assert_eq!( + Some("!SVkFJHzfwvuaIEawgC:localhost".into()), + client.current_room_id().await.map(|id| id.to_string()) + ); +} diff --git a/tests/data/sync.json b/tests/data/sync.json index d873fb47..32cd4629 100644 --- a/tests/data/sync.json +++ b/tests/data/sync.json @@ -12,7 +12,23 @@ "join": { "!SVkFJHzfwvuaIEawgC:localhost": { "account_data": { - "events": [] + "events": [ + { + "content": { + "event_id": "$someplace:example.org" + }, + "room_id": "!roomid:room.com", + "type": "m.fully_read" + }, + { + "content": { + "ignored_users": { + "@someone:example.org": {} + } + }, + "type": "m.ignored_user_list" + } + ] }, "ephemeral": { "events": [ @@ -248,7 +264,7 @@ "content": { "avatar_url": "mxc://localhost:wefuiwegh8742w", "currently_active": false, - "last_active_ago": 2478593, + "last_active_ago": 1, "presence": "online", "status_msg": "Making cupcakes" },