Page MenuHomePhorge

room-test.cpp
No OneTemporary

Size
15 KB
Referenced Files
None
Subscribers
None

room-test.cpp

/*
* 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

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)

Event Timeline