Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F7889406
push-rules-desc-test.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
16 KB
Referenced Files
None
Subscribers
None
push-rules-desc-test.cpp
View Options
/*
* This file is part of libkazv.
* SPDX-FileCopyrightText: 2020-2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include
<libkazv-config.hpp>
#include
<catch2/catch_test_macros.hpp>
#include
<push-rules-desc-p.hpp>
#include
<factory.hpp>
using
namespace
Kazv
;
using
namespace
Kazv
::
Factory
;
// adapted from https://spec.matrix.org/v1.8/client-server-api/#default-override-rules
static
auto
masterRule
=
R
"
(
{
"rule_id": ".m.rule.master",
"default": true,
"enabled": true,
"conditions": [],
"actions": []
}
)
"
_json
;
static
auto
suppressNoticesRule
=
R
"
(
{
"rule_id": ".m.rule.suppress_notices",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_match",
"key": "content.msgtype",
"pattern": "m.notice"
}
],
"actions": []
}
)
"
_json
;
static
auto
inviteForMeRule
=
R
"
(
{
"rule_id": ".m.rule.invite_for_me",
"default": true,
"enabled": true,
"conditions": [
{
"key": "type",
"kind": "event_match",
"pattern": "m.room.member"
},
{
"key": "content.membership",
"kind": "event_match",
"pattern": "invite"
},
{
"key": "state_key",
"kind": "event_match",
"pattern": "@foo:example.com"
}
],
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "default"
}
]
}
)
"
_json
;
static
auto
memberEventRule
=
R
"
(
{
"rule_id": ".m.rule.member_event",
"default": true,
"enabled": true,
"conditions": [
{
"key": "type",
"kind": "event_match",
"pattern": "m.room.member"
}
],
"actions": []
}
)
"
_json
;
static
auto
isUserMentionRule
=
R
"
(
{
"rule_id": ".m.rule.is_user_mention",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_property_contains",
"key": "content.m\\.mentions.user_ids",
"value": "@foo:example.com"
}
],
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "default"
},
{
"set_tweak": "highlight"
}
]
}
)
"
_json
;
static
auto
callRule
=
R
"
(
{
"rule_id": ".m.rule.call",
"default": true,
"enabled": true,
"conditions": [
{
"key": "type",
"kind": "event_match",
"pattern": "m.call.invite"
}
],
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "ring"
}
]
}
)
"
_json
;
static
auto
encryptedOneToOneRule
=
R
"
(
{
"rule_id": ".m.rule.encrypted_room_one_to_one",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "room_member_count",
"is": "2"
},
{
"kind": "event_match",
"key": "type",
"pattern": "m.room.encrypted"
}
],
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "default"
}
]
}
)
"
_json
;
static
auto
oneToOneRule
=
R
"
(
{
"rule_id": ".m.rule.room_one_to_one",
"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"
}
]
}
)
"
_json
;
static
auto
messageRule
=
R
"
(
{
"rule_id": ".m.rule.message",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_match",
"key": "type",
"pattern": "m.room.message"
}
],
"actions": [
"notify"
]
}
)
"
_json
;
static
auto
encryptedRule
=
R
"
(
{
"rule_id": ".m.rule.encrypted",
"default": true,
"enabled": true,
"conditions": [
{
"kind": "event_match",
"key": "type",
"pattern": "m.room.encrypted"
}
],
"actions": [
"notify"
]
}
)
"
_json
;
static
auto
catchAllRule
=
R
"
(
{
"rule_id": "moe.kazv.mxc.catch_all",
"default": true,
"enabled": true,
"conditions": [],
"actions": ["notify"]
}
)
"
_json
;
static
auto
emptyRulesContent
=
json
{
{
"global"
,
{
{
"override"
,
{}},
{
"content"
,
{}},
{
"room"
,
{}},
{
"sender"
,
{}},
{
"underride"
,
{}},
}},
};
static
Event
makePushRulesEvent
(
const
json
&
pushRulesContent
)
{
return
makeEvent
(
withEventContent
(
pushRulesContent
)
|
withEventType
(
"m.push_rules"
)
);
}
TEST_CASE
(
"splitPath()"
,
"[client][push-rules]"
)
{
REQUIRE
(
splitPath
(
"content.body"
)
==
std
::
vector
<
std
::
string
>
{
"content"
,
"body"
});
REQUIRE
(
splitPath
(
"content.m
\\
.relates_to"
)
==
std
::
vector
<
std
::
string
>
{
"content"
,
"m.relates_to"
});
REQUIRE
(
splitPath
(
"content.m
\\\\
foo"
)
==
std
::
vector
<
std
::
string
>
{
"content"
,
"m
\\
foo"
});
REQUIRE
(
splitPath
(
"content.m
\\
x"
)
==
std
::
vector
<
std
::
string
>
{
"content"
,
"m
\\
x"
});
}
TEST_CASE
(
"matchGlob()"
,
"[client][push-rules]"
)
{
REQUIRE
(
matchGlob
(
"m.notice"
,
"m.notice"
));
REQUIRE
(
!
matchGlob
(
"m.notice"
,
"m.+notice"
));
REQUIRE
(
!
matchGlob
(
"m.notice"
,
"m.(notice)"
));
REQUIRE
(
!
matchGlob
(
"mxnotice"
,
"m.notice"
));
REQUIRE
(
!
matchGlob
(
"m.notice"
,
"^m.notice"
));
REQUIRE
(
!
matchGlob
(
"m.notice"
,
"m.notice$"
));
REQUIRE
(
!
matchGlob
(
"m.notice"
,
"m.notice|m.notice"
));
REQUIRE
(
!
matchGlob
(
"m.notice"
,
"m.notic[e]"
));
REQUIRE
(
!
matchGlob
(
"m.notice"
,
"m.notic
\\
e"
));
REQUIRE
(
matchGlob
(
"m
\n
notice"
,
"m?notice"
));
REQUIRE
(
matchGlob
(
"Lunch plans"
,
"lunc?*"
));
REQUIRE
(
matchGlob
(
"LUNCH"
,
"lunc?*"
));
REQUIRE
(
!
matchGlob
(
" lunch"
,
"lunc?*"
));
REQUIRE
(
!
matchGlob
(
"lunc"
,
"lunc?*"
));
}
TEST_CASE
(
"validateRule()"
,
"[client][push-rules]"
)
{
json
rule
=
masterRule
;
SECTION
(
"minimum push rule"
)
{
auto
validated
=
validateRule
(
"override"
,
rule
);
REQUIRE
(
validated
.
has_value
());
REQUIRE
(
validated
.
value
()
==
rule
);
}
SECTION
(
"strips extra properties"
)
{
rule
[
"something"
]
=
"else"
;
auto
validated
=
validateRule
(
"override"
,
rule
);
REQUIRE
(
validated
.
has_value
());
REQUIRE
(
validated
.
value
()
==
masterRule
);
}
SECTION
(
"must have rule_id"
)
{
rule
.
erase
(
"rule_id"
);
auto
validated
=
validateRule
(
"override"
,
rule
);
REQUIRE
(
!
validated
.
has_value
());
}
SECTION
(
"must have default"
)
{
rule
.
erase
(
"default"
);
auto
validated
=
validateRule
(
"override"
,
rule
);
REQUIRE
(
!
validated
.
has_value
());
}
SECTION
(
"must have enabled"
)
{
rule
.
erase
(
"enabled"
);
auto
validated
=
validateRule
(
"override"
,
rule
);
REQUIRE
(
!
validated
.
has_value
());
}
SECTION
(
"must have conditions array"
)
{
rule
[
"conditions"
]
=
json
::
object
();
auto
validated
=
validateRule
(
"override"
,
rule
);
REQUIRE
(
!
validated
.
has_value
());
}
SECTION
(
"add empty array if conditions not present"
)
{
rule
.
erase
(
"conditions"
);
auto
validated
=
validateRule
(
"override"
,
rule
);
REQUIRE
(
validated
.
has_value
());
REQUIRE
(
validated
.
value
()
==
masterRule
);
}
SECTION
(
"reject if there is unknown condition"
)
{
rule
[
"conditions"
]
=
json
::
array
({{{
"kind"
,
"moe.kazv.mxc.unknown-condition"
}}});
auto
validated
=
validateRule
(
"override"
,
rule
);
REQUIRE
(
!
validated
.
has_value
());
}
SECTION
(
"event_match condition"
)
{
rule
[
"conditions"
]
=
json
::
array
({{
{
"kind"
,
"event_match"
},
{
"key"
,
"some"
},
{
"pattern"
,
"patt*n"
},
}});
auto
validated
=
validateRule
(
"override"
,
rule
);
REQUIRE
(
validated
.
has_value
());
REQUIRE
(
validated
.
value
()
==
rule
);
auto
ruleWithExtraProp
=
rule
;
ruleWithExtraProp
[
"conditions"
][
0
][
"some"
]
=
"thing"
;
validated
=
validateRule
(
"override"
,
ruleWithExtraProp
);
REQUIRE
(
validated
.
has_value
());
REQUIRE
(
validated
.
value
()
==
rule
);
}
}
TEST_CASE
(
"validatePushRules()"
,
"[client][push-rules]"
)
{
json
content
=
{
{
"global"
,
{
{
"override"
,
{
masterRule
,
suppressNoticesRule
,
isUserMentionRule
}},
{
"content"
,
{}},
{
"room"
,
{}},
{
"sender"
,
{}},
{
"underride"
,
{}},
}},
};
auto
e
=
Event
{
json
{
{
"type"
,
"m.push_rules"
},
{
"content"
,
content
},
}};
SECTION
(
"nothing unrecognized"
)
{
auto
validated
=
validatePushRules
(
e
);
REQUIRE
(
validated
==
e
);
}
SECTION
(
"extra param in content"
)
{
content
[
"something"
]
=
"else"
;
auto
extra
=
Event
{
json
{
{
"type"
,
"m.push_rules"
},
{
"content"
,
content
},
}};
auto
validated
=
validatePushRules
(
extra
);
REQUIRE
(
validated
==
e
);
}
SECTION
(
"extra param in global"
)
{
content
[
"global"
][
"something"
]
=
"else"
;
auto
extra
=
Event
{
json
{
{
"type"
,
"m.push_rules"
},
{
"content"
,
content
},
}};
auto
validated
=
validatePushRules
(
extra
);
REQUIRE
(
validated
==
e
);
}
SECTION
(
"extra param in rule"
)
{
content
[
"global"
][
"override"
][
0
][
"something"
]
=
"else"
;
auto
extra
=
Event
{
json
{
{
"type"
,
"m.push_rules"
},
{
"content"
,
content
},
}};
auto
validated
=
validatePushRules
(
extra
);
REQUIRE
(
validated
==
e
);
}
SECTION
(
"extra param in condition"
)
{
content
[
"global"
][
"override"
][
1
][
"conditions"
][
0
][
"something"
]
=
"else"
;
auto
extra
=
Event
{
json
{
{
"type"
,
"m.push_rules"
},
{
"content"
,
content
},
}};
auto
validated
=
validatePushRules
(
extra
);
REQUIRE
(
validated
==
e
);
}
SECTION
(
"unrecognized condition"
)
{
content
[
"global"
][
"override"
][
1
][
"conditions"
].
push_back
(
json
::
object
({{
"kind"
,
"moe.kazv.mxc.unknown-condition"
}}));
auto
extra
=
Event
{
json
{
{
"type"
,
"m.push_rules"
},
{
"content"
,
content
},
}};
content
[
"global"
][
"override"
].
erase
(
1
);
auto
expected
=
Event
{
json
{
{
"type"
,
"m.push_rules"
},
{
"content"
,
content
},
}};
auto
validated
=
validatePushRules
(
extra
);
REQUIRE
(
validated
==
expected
);
}
SECTION
(
"unrecognized action"
)
{
content
[
"global"
][
"override"
][
1
][
"actions"
].
push_back
(
"moe.kazv.mxc.unknown-action"
);
auto
extra
=
Event
{
json
{
{
"type"
,
"m.push_rules"
},
{
"content"
,
content
},
}};
auto
validated
=
validatePushRules
(
extra
);
REQUIRE
(
validated
==
e
);
}
}
TEST_CASE
(
"PushRulesDescPrivate::matchP()"
,
"[client][push-rules]"
)
{
PushRulesDescPrivate
rp
{
Event
()};
auto
room
=
makeRoom
();
SECTION
(
"master rule"
)
{
REQUIRE
(
rp
.
matchP
(
"override"
,
masterRule
,
makeEvent
(),
room
));
}
SECTION
(
"suppress notices rule"
)
{
auto
notice
=
makeEvent
(
withEventContent
(
json
{{
"msgtype"
,
"m.notice"
}}));
REQUIRE
(
rp
.
matchP
(
"override"
,
suppressNoticesRule
,
notice
,
room
));
auto
notNotice
=
makeEvent
(
withEventContent
(
json
{{
"msgtype"
,
"m.noticexxx"
}}));
REQUIRE
(
!
rp
.
matchP
(
"override"
,
suppressNoticesRule
,
notNotice
,
room
));
}
SECTION
(
"invite for me rule"
)
{
auto
invite
=
makeEvent
(
withEventContent
(
json
{{
"membership"
,
"invite"
}})
|
withEventType
(
"m.room.member"
)
|
withStateKey
(
"@foo:example.com"
)
);
REQUIRE
(
rp
.
matchP
(
"override"
,
inviteForMeRule
,
invite
,
room
));
auto
inviteForOthers
=
makeEvent
(
withEventContent
(
json
{{
"membership"
,
"invite"
}})
|
withEventType
(
"m.room.member"
)
|
withStateKey
(
"@foo:example.com.tw"
)
);
REQUIRE
(
!
rp
.
matchP
(
"override"
,
inviteForMeRule
,
inviteForOthers
,
room
));
}
SECTION
(
"member event rule"
)
{
auto
member
=
makeEvent
(
withEventContent
(
json
{{
"membership"
,
"join"
}})
|
withEventType
(
"m.room.member"
)
|
withStateKey
(
"@foo:example.com"
)
);
REQUIRE
(
rp
.
matchP
(
"override"
,
memberEventRule
,
member
,
room
));
}
SECTION
(
"is user mention rule"
)
{
auto
mentionedEvent
=
makeEvent
(
withEventContent
(
json
{
{
"m.mentions"
,
{
{
"user_ids"
,
{
"@foo:example.com"
}}
}}
})
);
auto
notMentionedEvent
=
makeEvent
(
withEventContent
(
json
{
{
"m.mentions"
,
{
{
"user_ids"
,
{
"@foo:example.com.tw"
}}
}}
})
);
REQUIRE
(
rp
.
matchP
(
"override"
,
isUserMentionRule
,
mentionedEvent
,
room
));
REQUIRE
(
!
rp
.
matchP
(
"override"
,
isUserMentionRule
,
notMentionedEvent
,
room
));
}
}
TEST_CASE
(
"Push rules works with predefined rules"
,
"[client][push-rules]"
)
{
auto
rulesContent
=
emptyRulesContent
;
auto
room
=
makeRoom
();
SECTION
(
"master rule"
)
{
rulesContent
[
"global"
][
"override"
].
push_back
(
masterRule
);
rulesContent
[
"global"
][
"underride"
].
push_back
(
catchAllRule
);
auto
pushRules
=
PushRulesDesc
(
makePushRulesEvent
(
rulesContent
));
auto
result
=
pushRules
.
handle
(
makeEvent
(),
room
);
REQUIRE
(
!
result
.
shouldNotify
);
}
SECTION
(
"suppress notices rule"
)
{
rulesContent
[
"global"
][
"override"
].
push_back
(
suppressNoticesRule
);
rulesContent
[
"global"
][
"underride"
].
push_back
(
catchAllRule
);
auto
pushRules
=
PushRulesDesc
(
makePushRulesEvent
(
rulesContent
));
auto
result
=
pushRules
.
handle
(
makeEvent
(
withEventContent
(
json
{{
"msgtype"
,
"m.notice"
}})),
room
);
REQUIRE
(
!
result
.
shouldNotify
);
}
SECTION
(
"invite for me rule"
)
{
rulesContent
[
"global"
][
"override"
].
push_back
(
inviteForMeRule
);
auto
pushRules
=
PushRulesDesc
(
makePushRulesEvent
(
rulesContent
));
auto
result
=
pushRules
.
handle
(
makeEvent
(
withEventContent
(
json
{{
"membership"
,
"invite"
}})
|
withEventType
(
"m.room.member"
)
|
withStateKey
(
"@foo:example.com"
)
),
room
);
REQUIRE
(
result
.
shouldNotify
);
}
SECTION
(
"member event rule"
)
{
rulesContent
[
"global"
][
"override"
].
push_back
(
memberEventRule
);
rulesContent
[
"global"
][
"underride"
].
push_back
(
catchAllRule
);
auto
pushRules
=
PushRulesDesc
(
makePushRulesEvent
(
rulesContent
));
auto
result
=
pushRules
.
handle
(
makeEvent
(
withEventContent
(
json
{{
"membership"
,
"invite"
}})
|
withEventType
(
"m.room.member"
)
|
withStateKey
(
"@foo:example.com"
)
),
room
);
REQUIRE
(
!
result
.
shouldNotify
);
}
SECTION
(
"is user mention rule"
)
{
auto
mentionedEvent
=
makeEvent
(
withEventContent
(
json
{
{
"m.mentions"
,
{
{
"user_ids"
,
{
"@foo:example.com"
}}
}}
})
);
auto
notMentionedEvent
=
makeEvent
(
withEventContent
(
json
{
{
"m.mentions"
,
{
{
"user_ids"
,
{
"@foo:example.com.tw"
}}
}}
})
);
rulesContent
[
"global"
][
"override"
].
push_back
(
isUserMentionRule
);
auto
pushRules
=
PushRulesDesc
(
makePushRulesEvent
(
rulesContent
));
REQUIRE
(
pushRules
.
handle
(
mentionedEvent
,
room
).
shouldNotify
);
REQUIRE
(
!
pushRules
.
handle
(
notMentionedEvent
,
room
).
shouldNotify
);
}
}
TEST_CASE
(
"Push rules would not crash with broken rules"
,
"[client][push-rules]"
)
{
auto
rulesContent
=
emptyRulesContent
;
auto
room
=
makeRoom
();
REQUIRE
(
!
PushRulesDesc
(
Event
()).
handle
(
makeEvent
(),
room
).
shouldNotify
);
SECTION
(
"rule missing required param"
)
{
auto
rule
=
catchAllRule
;
rule
.
erase
(
"rule_id"
);
rulesContent
[
"global"
][
"override"
].
push_back
(
rule
);
REQUIRE
(
!
PushRulesDesc
(
makePushRulesEvent
(
rulesContent
)).
handle
(
makeEvent
(),
room
).
shouldNotify
);
}
SECTION
(
"rule containing invalid condition"
)
{
auto
rule
=
catchAllRule
;
rule
[
"conditions"
].
push_back
(
"something"
);
rulesContent
[
"global"
][
"override"
].
push_back
(
rule
);
REQUIRE
(
!
PushRulesDesc
(
makePushRulesEvent
(
rulesContent
)).
handle
(
makeEvent
(),
room
).
shouldNotify
);
}
SECTION
(
"rule containing unknown action"
)
{
auto
rule
=
catchAllRule
;
rule
[
"actions"
].
push_back
(
"something"
);
rulesContent
[
"global"
][
"override"
].
push_back
(
rule
);
REQUIRE
(
PushRulesDesc
(
makePushRulesEvent
(
rulesContent
)).
handle
(
makeEvent
(),
room
).
shouldNotify
);
}
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Thu, Oct 2, 2:30 AM (1 d, 14 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
486953
Default Alt Text
push-rules-desc-test.cpp (16 KB)
Attached To
Mode
rL libkazv
Attached
Detach File
Event Timeline
Log In to Comment