From 945e085c7a0d00d57c07d3e7d1399733074abb11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Mon, 22 Mar 2021 12:08:57 +0100 Subject: [PATCH] common: Add tests for push rules --- ruma-common/src/push.rs | 496 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 496 insertions(+) diff --git a/ruma-common/src/push.rs b/ruma-common/src/push.rs index da9954ce..d2e7f6dc 100644 --- a/ruma-common/src/push.rs +++ b/ruma-common/src/push.rs @@ -430,3 +430,499 @@ pub enum PushFormat { #[doc(hidden)] _Custom(String), } + +#[cfg(test)] +mod tests { + use js_int::uint; + use matches::assert_matches; + use serde_json::{ + from_value as from_json_value, json, to_value as to_json_value, + value::RawValue as RawJsonValue, Value as JsonValue, + }; + + use super::{ + action::{Action, Tweak}, + condition::{PushCondition, RoomMemberCountIs}, + AnyPushRule, ConditionalPushRule, PatternedPushRule, Ruleset, SimplePushRule, + }; + + fn example_ruleset() -> Ruleset { + let mut set = Ruleset::new(); + + set.add(AnyPushRule::Override(ConditionalPushRule { + conditions: vec![PushCondition::EventMatch { + key: "type".into(), + pattern: "m.call.invite".into(), + }], + actions: vec![Action::Notify, Action::SetTweak(Tweak::Highlight(true))], + rule_id: ".m.rule.call".into(), + enabled: true, + default: true, + })); + + set + } + + #[test] + fn cannot_add_same_rule_id() { + let mut set = example_ruleset(); + + let added = set.add(AnyPushRule::Override(ConditionalPushRule { + conditions: vec![], + actions: vec![], + rule_id: ".m.rule.call".into(), + enabled: true, + default: true, + })); + + assert!(!added); + } + + #[test] + fn can_add_same_rule_id_different_kind() { + let mut set = example_ruleset(); + + let added = set.add(AnyPushRule::Underride(ConditionalPushRule { + conditions: vec![], + actions: vec![], + rule_id: ".m.rule.call".into(), + enabled: true, + default: true, + })); + + assert!(added); + } + + #[test] + fn get_by_rule_id() { + let set = example_ruleset(); + + let rule = set.override_.get(".m.rule.call"); + assert!(rule.is_some()); + assert_eq!(rule.unwrap().rule_id, ".m.rule.call"); + + let rule = set.override_.get(".m.rule.doesntexist"); + assert!(rule.is_none()); + } + + #[test] + fn iter() { + let mut set = example_ruleset(); + + let added = set.add(AnyPushRule::Override(ConditionalPushRule { + conditions: vec![PushCondition::EventMatch { + key: "room_id".into(), + pattern: "!roomid:matrix.org".into(), + }], + actions: vec![Action::DontNotify], + rule_id: "!roomid:matrix.org".into(), + enabled: true, + default: false, + })); + assert!(added); + + let added = set.add(AnyPushRule::Override(ConditionalPushRule { + conditions: vec![], + actions: vec![], + rule_id: ".m.rule.suppress_notices".into(), + enabled: false, + default: true, + })); + assert!(added); + + let mut iter = set.into_iter(); + + let rule_opt = iter.next(); + assert!(rule_opt.is_some()); + assert_matches!( + rule_opt.unwrap(), + AnyPushRule::Override(ConditionalPushRule { rule_id, .. }) + if rule_id == ".m.rule.call" + ); + + let rule_opt = iter.next(); + assert!(rule_opt.is_some()); + assert_matches!( + rule_opt.unwrap(), + AnyPushRule::Override(ConditionalPushRule { rule_id, .. }) + if rule_id == "!roomid:matrix.org" + ); + + let rule_opt = iter.next(); + assert!(rule_opt.is_some()); + assert_matches!( + rule_opt.unwrap(), + AnyPushRule::Override(ConditionalPushRule { rule_id, .. }) + if rule_id == ".m.rule.suppress_notices" + ); + + assert!(iter.next().is_none()); + } + + #[test] + fn serialize_conditional_push_rule() { + let rule = ConditionalPushRule { + actions: vec![Action::Notify, Action::SetTweak(Tweak::Highlight(true))], + default: true, + enabled: true, + rule_id: ".m.rule.call".into(), + conditions: vec![ + PushCondition::EventMatch { key: "type".into(), pattern: "m.call.invite".into() }, + PushCondition::ContainsDisplayName, + PushCondition::RoomMemberCount { is: RoomMemberCountIs::gt(uint!(2)) }, + PushCondition::SenderNotificationPermission { key: "room".into() }, + ], + }; + + let rule_value: JsonValue = to_json_value(rule).unwrap(); + assert_eq!( + rule_value, + json!({ + "conditions": [ + { + "kind": "event_match", + "key": "type", + "pattern": "m.call.invite" + }, + { + "kind": "contains_display_name" + }, + { + "kind": "room_member_count", + "is": ">2" + }, + { + "kind": "sender_notification_permission", + "key": "room" + } + ], + "actions": [ + "notify", + { + "set_tweak": "highlight" + } + ], + "rule_id": ".m.rule.call", + "default": true, + "enabled": true + }) + ); + } + + #[test] + fn serialize_simple_push_rule() { + let rule = SimplePushRule { + actions: vec![Action::DontNotify], + default: false, + enabled: false, + rule_id: "!roomid:server.name".into(), + }; + + let rule_value: JsonValue = to_json_value(rule).unwrap(); + assert_eq!( + rule_value, + json!({ + "actions": [ + "dont_notify" + ], + "rule_id": "!roomid:server.name", + "default": false, + "enabled": false + }) + ); + } + + #[test] + fn serialize_patterned_push_rule() { + let rule = PatternedPushRule { + actions: vec![ + Action::Notify, + Action::SetTweak(Tweak::Sound("default".into())), + Action::SetTweak(Tweak::Custom { + name: "dance".into(), + value: RawJsonValue::from_string("true".into()).unwrap(), + }), + ], + default: true, + enabled: true, + pattern: "user_id".into(), + rule_id: ".m.rule.contains_user_name".into(), + }; + + let rule_value: JsonValue = to_json_value(rule).unwrap(); + assert_eq!( + rule_value, + json!({ + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "dance", + "value": true + } + ], + "pattern": "user_id", + "rule_id": ".m.rule.contains_user_name", + "default": true, + "enabled": true + }) + ); + } + + #[test] + fn serialize_ruleset() { + let mut set = example_ruleset(); + + set.add(AnyPushRule::Override(ConditionalPushRule { + conditions: vec![ + PushCondition::RoomMemberCount { is: RoomMemberCountIs::from(uint!(2)) }, + PushCondition::EventMatch { key: "type".into(), pattern: "m.room.message".into() }, + ], + actions: vec![ + Action::Notify, + Action::SetTweak(Tweak::Sound("default".into())), + Action::SetTweak(Tweak::Highlight(false)), + ], + rule_id: ".m.rule.room_one_to_one".into(), + enabled: true, + default: true, + })); + set.add(AnyPushRule::Content(PatternedPushRule { + actions: vec![ + Action::Notify, + Action::SetTweak(Tweak::Sound("default".into())), + Action::SetTweak(Tweak::Highlight(true)), + ], + rule_id: ".m.rule.contains_user_name".into(), + pattern: "user_id".into(), + enabled: true, + default: true, + })); + + let set_value: JsonValue = to_json_value(set).unwrap(); + assert_eq!( + set_value, + json!({ + "override": [ + { + "actions": [ + "notify", + { + "set_tweak": "highlight", + }, + ], + "conditions": [ + { + "kind": "event_match", + "key": "type", + "pattern": "m.call.invite" + }, + ], + "rule_id": ".m.rule.call", + "default": true, + "enabled": true, + }, + { + "conditions": [ + { + "kind": "room_member_count", + "is": "2" + }, + { + "kind": "event_match", + "key": "type", + "pattern": "m.room.message" + } + ], + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "highlight", + "value": false + } + ], + "rule_id": ".m.rule.room_one_to_one", + "default": true, + "enabled": true + }, + ], + "room": [], + "content": [ + { + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "highlight" + } + ], + "pattern": "user_id", + "rule_id": ".m.rule.contains_user_name", + "default": true, + "enabled": true + } + ], + "sender": [], + "underride": [], + }) + ); + } + + #[test] + fn deserialize_patterned_push_rule() { + let rule = from_json_value(json!({ + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "highlight", + "value": true + } + ], + "pattern": "user_id", + "rule_id": ".m.rule.contains_user_name", + "default": true, + "enabled": true + })) + .unwrap(); + assert_matches!( + rule, + PatternedPushRule { + actions: _, + default: true, + enabled: true, + pattern, + rule_id, + } + if pattern == "user_id" && rule_id == ".m.rule.contains_user_name" + ); + + let mut iter = rule.actions.iter(); + assert_matches!(iter.next(), Some(Action::Notify)); + assert_matches!(iter.next(), Some(Action::SetTweak(Tweak::Sound(sound))) if sound == "default"); + assert_matches!(iter.next(), Some(Action::SetTweak(Tweak::Highlight(true)))); + assert_matches!(iter.next(), None); + } + + #[test] + fn deserialize_ruleset() { + let set: Ruleset = from_json_value(json!({ + "override": [ + { + "actions": [], + "conditions": [], + "rule_id": "!roomid:server.name", + "default": false, + "enabled": true + }, + { + "actions": [], + "conditions": [], + "rule_id": ".m.rule.call", + "default": true, + "enabled": true + }, + ], + "underride": [ + { + "actions": [], + "conditions": [], + "rule_id": ".m.rule.room_one_to_one", + "default": true, + "enabled": true + }, + ], + "room": [ + { + "actions": [], + "rule_id": "!roomid:server.name", + "default": false, + "enabled": false + } + ], + "sender": [], + "content": [ + { + "actions": [], + "pattern": "user_id", + "rule_id": ".m.rule.contains_user_name", + "default": true, + "enabled": true + }, + { + "actions": [], + "pattern": "ruma", + "rule_id": "ruma", + "default": false, + "enabled": true + } + ] + })) + .unwrap(); + + let mut iter = set.into_iter(); + + let rule_opt = iter.next(); + assert!(rule_opt.is_some()); + assert_matches!( + rule_opt.unwrap(), + AnyPushRule::Override(ConditionalPushRule { rule_id, .. }) + if rule_id == "!roomid:server.name" + ); + + let rule_opt = iter.next(); + assert!(rule_opt.is_some()); + assert_matches!( + rule_opt.unwrap(), + AnyPushRule::Override(ConditionalPushRule { rule_id, .. }) + if rule_id == ".m.rule.call" + ); + + let rule_opt = iter.next(); + assert!(rule_opt.is_some()); + assert_matches!( + rule_opt.unwrap(), + AnyPushRule::Content(PatternedPushRule { rule_id, .. }) + if rule_id == ".m.rule.contains_user_name" + ); + + let rule_opt = iter.next(); + assert!(rule_opt.is_some()); + assert_matches!( + rule_opt.unwrap(), + AnyPushRule::Content(PatternedPushRule { rule_id, .. }) + if rule_id == "ruma" + ); + + let rule_opt = iter.next(); + assert!(rule_opt.is_some()); + assert_matches!( + rule_opt.unwrap(), + AnyPushRule::Room(SimplePushRule { rule_id, .. }) + if rule_id == "!roomid:server.name" + ); + + let rule_opt = iter.next(); + assert!(rule_opt.is_some()); + assert_matches!( + rule_opt.unwrap(), + AnyPushRule::Underride(ConditionalPushRule { rule_id, .. }) + if rule_id == ".m.rule.room_one_to_one" + ); + + assert!(iter.next().is_none()); + } +}