Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F140539
room-test.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
15 KB
Referenced Files
None
Subscribers
None
room-test.cpp
View Options
/*
* This file is part of libkazv.
* SPDX-FileCopyrightText: 2021-2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include
<libkazv-config.hpp>
#include
<catch2/catch_all.hpp>
#include
<lager/event_loop/boost_asio.hpp>
#include
<boost/asio.hpp>
#include
<sdk.hpp>
#include
<cprjobhandler.hpp>
#include
<lagerstoreeventemitter.hpp>
#include
<asio-promise-handler.hpp>
#include
"client-test-util.hpp"
#include
"factory.hpp"
using
namespace
Kazv
;
using
namespace
Kazv
::
Factory
;
TEST_CASE
(
"Result of Room::toEventLoop() should not vary with the original cursor"
,
"[client][room]"
)
{
auto
io
=
boost
::
asio
::
io_context
{};
auto
jh
=
Kazv
::
CprJobHandler
{
io
.
get_executor
()};
auto
ee
=
Kazv
::
LagerStoreEventEmitter
(
lager
::
with_boost_asio_event_loop
{
io
.
get_executor
()});
auto
roomWithId
=
[](
std
::
string
roomId
)
{
auto
r
=
RoomModel
{};
r
.
roomId
=
roomId
;
return
r
;
};
auto
initModel
=
Kazv
::
SdkModel
{};
initModel
.
client
.
roomList
.
rooms
=
std
::
move
(
initModel
.
client
.
roomList
.
rooms
)
.
set
(
"!foo:example.org"
,
roomWithId
(
"!foo:example.org"
))
.
set
(
"!bar:example.org"
,
roomWithId
(
"!bar:example.org"
));
auto
sdk
=
Kazv
::
makeSdk
(
initModel
,
jh
,
ee
,
Kazv
::
AsioPromiseHandler
{
io
.
get_executor
()},
zug
::
identity
);
auto
ctx
=
sdk
.
context
();
auto
client
=
sdk
.
client
();
auto
roomId
=
lager
::
make_state
(
std
::
string
(
"!foo:example.org"
),
lager
::
automatic_tag
{});
auto
room
=
client
.
roomByCursor
(
roomId
);
using
namespace
Kazv
::
CursorOp
;
REQUIRE
(
+
room
.
roomId
()
==
"!foo:example.org"
);
auto
roomInEventLoop
=
room
.
toEventLoop
();
REQUIRE
(
+
roomInEventLoop
.
roomId
()
==
"!foo:example.org"
);
roomId
.
set
(
"!bar:example.org"
);
REQUIRE
(
+
room
.
roomId
()
==
"!bar:example.org"
);
REQUIRE
(
+
roomInEventLoop
.
roomId
()
==
"!foo:example.org"
);
}
static
const
std
::
string
exampleRoomId
=
"!example:example.org"
;
static
auto
memberFoo
=
Event
(
R
"
(
{
"content": {
"displayname": "foo's name",
"membership": "join"
},
"event_id": "some id2",
"room_id": "!example:example.org",
"type": "m.room.member",
"state_key": "@foo:example.org"
}
)
"
_json
);
static
auto
memberBar
=
Event
(
R
"
(
{
"content": {
"displayname": "bar's name",
"membership": "join"
},
"event_id": "some id3",
"room_id": "!example:example.org",
"type": "m.room.member",
"state_key": "@foo:example.org"
}
)
"
_json
);
static
auto
exampleRoomWithoutNameEvent
()
{
RoomModel
model
;
model
.
membership
=
RoomMembership
::
Join
;
model
.
roomId
=
"!example:example.org"
;
model
.
stateEvents
=
model
.
stateEvents
.
set
({
"m.room.member"
,
"@foo:example.org"
},
memberFoo
)
.
set
({
"m.room.member"
,
"@bar:example.org"
},
memberBar
);
model
.
heroIds
=
{
"@foo:example.org"
,
"@bar:example.org"
};
return
model
;
}
static
auto
roomNameEvent
=
Event
(
R
"
(
{
"content": {
"name": "some name"
},
"event_id": "some id",
"room_id": "!example:example.org",
"type": "m.room.name",
"state_key": ""
}
)
"
_json
);
// https://spec.matrix.org/v1.7/client-server-api/#mroomavatar
static
Event
avatarEvent
=
R
"
(
{
"content": {
"info": {
"h": 398,
"mimetype": "image/jpeg",
"size": 31037,
"w": 394
},
"url": "mxc://example.org/JWEIFJgwEIhweiWJE"
},
"event_id": "$143273582443PhrSn:example.org",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
"sender": "@example:example.org",
"state_key": "",
"type": "m.room.avatar",
"unsigned": {
"age": 1234
}
}
)
"
_json
;
static
auto
exampleRoomWithNameEvent
()
{
auto
model
=
exampleRoomWithoutNameEvent
();
model
.
stateEvents
=
model
.
stateEvents
.
set
({
"m.room.name"
,
""
},
roomNameEvent
);
return
model
;
};
static
auto
sdkWith
(
RoomModel
room
)
{
SdkModel
model
;
model
.
client
.
roomList
.
rooms
=
model
.
client
.
roomList
.
rooms
.
set
(
room
.
roomId
,
room
);
return
model
;
}
static
auto
makeRoomWithDumbContext
(
RoomModel
room
)
{
auto
cursor
=
lager
::
make_constant
(
sdkWith
(
room
));
auto
nameCursor
=
lager
::
make_constant
(
room
.
roomId
);
return
Room
(
cursor
,
nameCursor
,
dumbContext
());
}
TEST_CASE
(
"Room::nameOpt()"
,
"[client][room][getter]"
)
{
WHEN
(
"the room has a name"
)
{
auto
room
=
makeRoomWithDumbContext
(
exampleRoomWithNameEvent
());
THEN
(
"it should give out the name"
)
{
auto
val
=
room
.
nameOpt
().
make
().
get
();
REQUIRE
(
val
.
has_value
());
REQUIRE
(
val
.
value
()
==
"some name"
);
}
}
WHEN
(
"the room has no name"
)
{
auto
room
=
makeRoomWithDumbContext
(
exampleRoomWithoutNameEvent
());
THEN
(
"it should give out nullopt"
)
{
auto
val
=
room
.
nameOpt
().
make
().
get
();
REQUIRE
(
!
val
.
has_value
());
}
}
}
TEST_CASE
(
"Room::heroMemberEvents()"
,
"[client][room][getter]"
)
{
auto
r
=
exampleRoomWithNameEvent
();
{
auto
val
=
r
.
heroMemberEvents
();
REQUIRE
(
val
.
size
()
==
2
);
REQUIRE
(
std
::
any_of
(
val
.
begin
(),
val
.
end
(),
[](
const
auto
&
v
)
{
return
v
.
id
()
==
"some id2"
;
}));
REQUIRE
(
std
::
any_of
(
val
.
begin
(),
val
.
end
(),
[](
const
auto
&
v
)
{
return
v
.
id
()
==
"some id3"
;
}));
}
auto
room
=
makeRoomWithDumbContext
(
r
);
THEN
(
"it should give out the events"
)
{
auto
val
=
room
.
heroMemberEvents
().
make
().
get
();
REQUIRE
(
val
.
size
()
==
2
);
REQUIRE
(
std
::
any_of
(
val
.
begin
(),
val
.
end
(),
[](
const
auto
&
v
)
{
return
v
.
id
()
==
"some id2"
;
}));
REQUIRE
(
std
::
any_of
(
val
.
begin
(),
val
.
end
(),
[](
const
auto
&
v
)
{
return
v
.
id
()
==
"some id3"
;
}));
}
}
TEST_CASE
(
"Room::heroDisplayNames()"
,
"[client][room][getter]"
)
{
auto
room
=
makeRoomWithDumbContext
(
exampleRoomWithNameEvent
());
THEN
(
"it should give out the names"
)
{
auto
val
=
room
.
heroDisplayNames
().
make
().
get
();
REQUIRE
(
val
.
size
()
==
2
);
REQUIRE
(
std
::
any_of
(
val
.
begin
(),
val
.
end
(),
[](
const
auto
&
v
)
{
return
v
==
"foo's name"
;
}));
REQUIRE
(
std
::
any_of
(
val
.
begin
(),
val
.
end
(),
[](
const
auto
&
v
)
{
return
v
==
"bar's name"
;
}));
}
}
TEST_CASE
(
"Room::encrypted()"
,
"[client][room][getter]"
)
{
auto
roomModel
=
exampleRoomWithNameEvent
();
WHEN
(
"the room is encrypted"
)
{
roomModel
.
encrypted
=
true
;
auto
room
=
makeRoomWithDumbContext
(
roomModel
);
THEN
(
"it should give out true"
)
{
auto
val
=
room
.
encrypted
().
make
().
get
();
REQUIRE
(
val
);
}
}
WHEN
(
"the room is not encrypted"
)
{
roomModel
.
encrypted
=
false
;
auto
room
=
makeRoomWithDumbContext
(
roomModel
);
THEN
(
"it should give out false"
)
{
auto
val
=
room
.
encrypted
().
make
().
get
();
REQUIRE
(
!
val
);
}
}
}
TEST_CASE
(
"Room::avatarMxcUri()"
,
"[client][room][getter]"
)
{
auto
roomModel
=
exampleRoomWithoutNameEvent
();
roomModel
.
stateEvents
=
roomModel
.
stateEvents
.
set
(
KeyOfState
{
"m.room.avatar"
,
""
},
avatarEvent
);
auto
room
=
makeRoomWithDumbContext
(
roomModel
);
REQUIRE
(
room
.
avatarMxcUri
().
make
().
get
()
==
"mxc://example.org/JWEIFJgwEIhweiWJE"
);
}
TEST_CASE
(
"Room::typingMemberEvents()"
,
"[client][room][getter][ephemeral]"
)
{
auto
roomModel
=
exampleRoomWithoutNameEvent
();
auto
typingJson
=
R
"
(
{
"content": {
"user_ids": ["@foo:example.org", "@bar:example.org"]
},
"type": "m.typing"
}
)
"
_json
;
roomModel
.
ephemeral
=
roomModel
.
ephemeral
.
set
(
"m.typing"
,
Event
{
typingJson
});
auto
room
=
makeRoomWithDumbContext
(
roomModel
);
REQUIRE
(
room
.
typingMemberEvents
().
make
().
get
()
==
EventList
{
room
.
memberEventFor
(
"@foo:example.org"
).
make
().
get
(),
room
.
memberEventFor
(
"@bar:example.org"
).
make
().
get
(),
});
}
TEST_CASE
(
"Room::message()"
,
"[client][room][getter][timeline]"
)
{
auto
roomModel
=
exampleRoomWithoutNameEvent
();
auto
messageEvent
=
Event
(
R
"
(
{
"content": {
"body": "This is an example text message",
"msgtype": "m.text",
"format": "org.matrix.custom.html",
"formatted_body": "<b>This is an example text message</b>"
},
"type": "m.room.message",
"event_id": "$anothermessageevent:example.org",
"room_id": "!726s6s6q:example.com",
"sender": "@example:example.org",
"origin_server_ts": 1432735824653,
"unsigned": {
"age": 1234
}
}
)
"
_json
);
roomModel
.
messages
=
roomModel
.
messages
.
set
(
messageEvent
.
id
(),
messageEvent
);
auto
room
=
makeRoomWithDumbContext
(
roomModel
);
REQUIRE
(
room
.
message
(
lager
::
make_constant
(
messageEvent
.
id
())).
make
().
get
()
==
messageEvent
);
}
TEST_CASE
(
"Room::localEcho()"
,
"[client][room][getter][timeline]"
)
{
auto
roomModel
=
exampleRoomWithoutNameEvent
();
auto
messageEvent
=
Event
(
R
"
(
{
"content": {
"body": "This is an example text message",
"msgtype": "m.text",
"format": "org.matrix.custom.html",
"formatted_body": "<b>This is an example text message</b>"
},
"type": "m.room.message",
"event_id": "$anothermessageevent:example.org",
"room_id": "!726s6s6q:example.com",
"sender": "@example:example.org",
"origin_server_ts": 1432735824653,
"unsigned": {
"age": 1234
}
}
)
"
_json
);
auto
localEcho
=
LocalEchoDesc
{
"123456789"
,
messageEvent
};
auto
localEchoDefault
=
LocalEchoDesc
{};
roomModel
.
localEchoes
=
roomModel
.
localEchoes
.
push_back
(
localEcho
);
auto
room
=
makeRoomWithDumbContext
(
roomModel
);
REQUIRE
(
room
.
localEcho
(
lager
::
make_constant
(
localEcho
.
txnId
)).
make
().
get
()
==
localEcho
);
REQUIRE
(
room
.
localEcho
(
lager
::
make_constant
(
""
s
)).
make
().
get
()
==
localEchoDefault
);
}
TEST_CASE
(
"Room::memberEventFor(), Room::memberEventByCursor"
,
"[client][room][getter][state]"
)
{
auto
roomModel
=
exampleRoomWithoutNameEvent
();
auto
memberFooJson
=
memberFoo
.
raw
().
get
();
memberFooJson
[
"content"
][
"displayname"
]
=
"some other name"
;
auto
newMemberFooEvent
=
Event
(
memberFooJson
);
roomModel
.
inviteState
=
roomModel
.
inviteState
.
set
({
"m.room.member"
,
"@foo:example.org"
},
newMemberFooEvent
);
WHEN
(
"membership is Invite"
)
{
roomModel
.
membership
=
RoomMembership
::
Invite
;
auto
room
=
makeRoomWithDumbContext
(
roomModel
);
THEN
(
"should prefer inviteState"
)
{
REQUIRE
(
room
.
memberEventFor
(
"@foo:example.org"
).
make
().
get
()
==
newMemberFooEvent
);
REQUIRE
(
room
.
memberEventFor
(
"@bar:example.org"
).
make
().
get
()
==
memberBar
);
}
}
WHEN
(
"membership is not Invite"
)
{
roomModel
.
membership
=
RoomMembership
::
Leave
;
auto
room
=
makeRoomWithDumbContext
(
roomModel
);
THEN
(
"should ignore inviteState"
)
{
REQUIRE
(
room
.
memberEventFor
(
"@foo:example.org"
).
make
().
get
()
==
memberFoo
);
REQUIRE
(
room
.
memberEventFor
(
"@bar:example.org"
).
make
().
get
()
==
memberBar
);
}
}
}
TEST_CASE
(
"Room::name(), Room::nameOpt()"
,
"[client][room][getter][state]"
)
{
auto
roomModel
=
exampleRoomWithoutNameEvent
();
WHEN
(
"membership is invite and invite state contains name event"
)
{
roomModel
.
membership
=
RoomMembership
::
Invite
;
roomModel
.
inviteState
=
roomModel
.
inviteState
.
set
({
"m.room.name"
,
""
},
roomNameEvent
);
auto
room
=
makeRoomWithDumbContext
(
roomModel
);
THEN
(
"it should give that name"
)
{
auto
expectedName
=
roomNameEvent
.
content
().
get
()[
"name"
].
template
get
<
std
::
string
>
();
REQUIRE
(
room
.
nameOpt
().
make
().
get
().
value
()
==
expectedName
);
REQUIRE
(
room
.
name
().
make
().
get
()
==
expectedName
);
}
}
WHEN
(
"membership is not invite and invite state contains the name event"
)
{
roomModel
.
membership
=
RoomMembership
::
Join
;
roomModel
.
inviteState
=
roomModel
.
inviteState
.
set
({
"m.room.name"
,
""
},
roomNameEvent
);
auto
room
=
makeRoomWithDumbContext
(
roomModel
);
THEN
(
"it should ignore that name"
)
{
REQUIRE
(
!
room
.
nameOpt
().
make
().
get
().
has_value
());
REQUIRE
(
room
.
name
().
make
().
get
()
==
"<no name>"
);
}
}
}
TEST_CASE
(
"Room::avatarMxcUri()"
,
"[client][room][getter][state]"
)
{
auto
roomModel
=
exampleRoomWithoutNameEvent
();
roomModel
.
inviteState
=
roomModel
.
inviteState
.
set
({
"m.room.avatar"
,
""
},
avatarEvent
);
WHEN
(
"membership is invite and invite state contains name event"
)
{
roomModel
.
membership
=
RoomMembership
::
Invite
;
auto
room
=
makeRoomWithDumbContext
(
roomModel
);
THEN
(
"it should give that avatar"
)
{
auto
expectedAvatar
=
avatarEvent
.
content
().
get
()[
"url"
].
template
get
<
std
::
string
>
();
REQUIRE
(
room
.
avatarMxcUri
().
make
().
get
()
==
expectedAvatar
);
}
}
WHEN
(
"membership is not invite and invite state contains the name event"
)
{
roomModel
.
membership
=
RoomMembership
::
Join
;
auto
room
=
makeRoomWithDumbContext
(
roomModel
);
THEN
(
"it should ignore that avatar"
)
{
REQUIRE
(
room
.
avatarMxcUri
().
make
().
get
()
==
""
);
}
}
}
TEST_CASE
(
"Room::joinedMemberEvents()"
,
"[client][room][getter][state]"
)
{
auto
members
=
immer
::
flex_vector
<
Event
>
{
makeMemberEvent
(),
makeMemberEvent
(),
makeMemberEvent
()};
auto
roomModel
=
makeRoom
(
withRoomState
(
members
)
|
withRoomState
({
makeMemberEvent
(
withMembership
(
"leave"
)),
makeMemberEvent
(
withMembership
(
"invite"
)),
makeMemberEvent
(
withMembership
(
"ban"
)),
})
);
auto
room
=
makeRoomWithDumbContext
(
roomModel
);
THEN
(
"it returns the joined members only"
)
{
REQUIRE_THAT
(
room
.
joinedMemberEvents
().
make
().
get
(),
Catch
::
Matchers
::
UnorderedRangeEquals
(
members
));
}
}
TEST_CASE
(
"Room::powerLevels()"
,
"[client][room][state][power-levels]"
)
{
auto
content
=
json
{
{
"users"
,
{{
"@foo:example.com"
,
40
}}},
};
auto
powerLevelsEvent
=
makeEvent
(
withEventType
(
"m.room.power_levels"
)
|
withEventContent
(
content
)
);
auto
roomModel
=
makeRoom
(
withRoomState
({
powerLevelsEvent
}));
auto
room
=
makeRoomWithDumbContext
(
roomModel
);
REQUIRE
(
room
.
powerLevels
().
make
().
get
().
originalEvent
()
==
powerLevelsEvent
);
}
TEST_CASE
(
"Room::{timelineEvents,timelineEventIds,messagesMap}()"
,
"[client][room][getter][timeline]"
)
{
auto
timelineEvents
=
immer
::
flex_vector
<
Event
>
{
makeEvent
(),
makeEvent
(),
makeEvent
()};
auto
timelineEventIds
=
intoImmer
(
immer
::
flex_vector
<
std
::
string
>
{},
zug
::
map
([](
const
auto
&
ev
)
{
return
ev
.
id
();
}),
timelineEvents
);
auto
messagesMap
=
intoImmer
(
immer
::
map
<
std
::
string
,
Event
>
{},
zug
::
map
([](
const
auto
&
ev
)
{
return
std
::
make_pair
(
ev
.
id
(),
ev
);
}),
timelineEvents
);
auto
roomModel
=
makeRoom
(
withRoomTimeline
(
timelineEvents
)
);
auto
room
=
makeRoomWithDumbContext
(
roomModel
);
REQUIRE
(
room
.
timelineEvents
().
make
().
get
()
==
timelineEvents
);
REQUIRE
(
room
.
timelineEventIds
().
make
().
get
()
==
timelineEventIds
);
REQUIRE
(
room
.
messagesMap
().
make
().
get
()
==
messagesMap
);
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sun, Jan 19, 11:55 PM (1 d, 4 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
55531
Default Alt Text
room-test.cpp (15 KB)
Attached To
Mode
rL libkazv
Attached
Detach File
Event Timeline
Log In to Comment