From ae0ad49f36e8ba5983839581302ed16ddbd75d5f Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Thu, 2 Dec 2021 14:04:49 +0100 Subject: visit(Event, ...) -> switchOnType() It has not much to do with the Visitor design pattern; also, std::visit() has different conventions on the order of parameters. --- quotest/quotest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'quotest/quotest.cpp') diff --git a/quotest/quotest.cpp b/quotest/quotest.cpp index d006c7fb..764d5dfd 100644 --- a/quotest/quotest.cpp +++ b/quotest/quotest.cpp @@ -498,8 +498,8 @@ bool TestSuite::checkFileSendingOutcome(const TestToken& thisTest, clog << "File event " << txnId.toStdString() << " arrived in the timeline" << endl; - // This part tests visit() - return visit( + // This part tests switchOnType() + return switchOnType( *evt, [&](const RoomMessageEvent& e) { // TODO: check #366 once #368 is implemented -- cgit v1.2.3 From e5256e0b1e4c43ce96d99d1b82ca5d98a1baded6 Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Fri, 17 Dec 2021 08:07:07 +0100 Subject: RoomMemberEvent: fix an off-by-one error Also: extended quotest to cover member renames, not just user profile renames. --- lib/events/roommemberevent.cpp | 8 +++----- quotest/quotest.cpp | 35 +++++++++++++++++++++++++++-------- 2 files changed, 30 insertions(+), 13 deletions(-) (limited to 'quotest/quotest.cpp') diff --git a/lib/events/roommemberevent.cpp b/lib/events/roommemberevent.cpp index b0bc7bcb..3141f6b5 100644 --- a/lib/events/roommemberevent.cpp +++ b/lib/events/roommemberevent.cpp @@ -48,11 +48,9 @@ void MemberEventContent::fillJson(QJsonObject* o) const { Q_ASSERT(o); if (membership != Membership::Invalid) - o->insert( - QStringLiteral("membership"), - MembershipStrings[qCountTrailingZeroBits( - std::underlying_type_t(membership)) - + 1]); + o->insert(QStringLiteral("membership"), + MembershipStrings[qCountTrailingZeroBits( + std::underlying_type_t(membership))]); if (displayName) o->insert(QStringLiteral("displayname"), *displayName); if (avatarUrl && avatarUrl->isValid()) diff --git a/quotest/quotest.cpp b/quotest/quotest.cpp index 764d5dfd..8703efb2 100644 --- a/quotest/quotest.cpp +++ b/quotest/quotest.cpp @@ -214,6 +214,7 @@ TestManager::TestManager(int& argc, char** argv) // Big countdown watchdog QTimer::singleShot(180000, this, [this] { + clog << "Time is up, stopping the session"; if (testSuite) conclude(); else @@ -537,14 +538,32 @@ TEST_IMPL(setTopic) TEST_IMPL(changeName) { - auto* const localUser = connection()->user(); - const auto& newName = connection()->generateTxnId(); // See setTopic() - clog << "Renaming the user to " << newName.toStdString() << endl; - localUser->rename(newName); - connectUntil(localUser, &User::defaultNameChanged, this, - [this, thisTest, localUser, newName] { - FINISH_TEST(localUser->name() == newName); - }); + connectSingleShot(targetRoom, &Room::allMembersLoaded, this, [this, thisTest] { + auto* const localUser = connection()->user(); + const auto& newName = connection()->generateTxnId(); // See setTopic() + clog << "Renaming the user to " << newName.toStdString() + << " in the target room" << endl; + localUser->rename(newName, targetRoom); + connectUntil(targetRoom, &Room::memberRenamed, this, + [this, thisTest, localUser, newName](const User* u) { + if (localUser != u) + return false; + if (localUser->name(targetRoom) != newName) + FAIL_TEST(); + + clog + << "Member rename successful, renaming the account" + << endl; + const auto newN = newName.mid(0, 5); + localUser->rename(newN); + connectUntil(localUser, &User::defaultNameChanged, + this, [this, thisTest, localUser, newN] { + targetRoom->localUser()->rename({}); + FINISH_TEST(localUser->name() == newN); + }); + return true; + }); + }); return false; } -- cgit v1.2.3 From 24a562cc64e8fac6c55108ae2b7b6997ecdd2010 Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Sun, 19 Dec 2021 10:43:33 +0100 Subject: Quotest: add a missing \n in the output --- quotest/quotest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'quotest/quotest.cpp') diff --git a/quotest/quotest.cpp b/quotest/quotest.cpp index 8703efb2..7bd9c5c3 100644 --- a/quotest/quotest.cpp +++ b/quotest/quotest.cpp @@ -214,7 +214,7 @@ TestManager::TestManager(int& argc, char** argv) // Big countdown watchdog QTimer::singleShot(180000, this, [this] { - clog << "Time is up, stopping the session"; + clog << "Time is up, stopping the session\n"; if (testSuite) conclude(); else -- cgit v1.2.3 From 02fdd08b98d878168eb81376a44586176dfd9576 Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Sun, 26 Dec 2021 10:40:56 +0100 Subject: Quotest: test sending and receiving custom events This seems to be the crux of #413. --- quotest/quotest.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 5 deletions(-) (limited to 'quotest/quotest.cpp') diff --git a/quotest/quotest.cpp b/quotest/quotest.cpp index 7bd9c5c3..5a5642fe 100644 --- a/quotest/quotest.cpp +++ b/quotest/quotest.cpp @@ -101,6 +101,7 @@ private slots: TEST_DECL(sendMessage) TEST_DECL(sendReaction) TEST_DECL(sendFile) + TEST_DECL(sendCustomEvent) TEST_DECL(setTopic) TEST_DECL(changeName) TEST_DECL(sendAndRedact) @@ -125,6 +126,7 @@ private: [[nodiscard]] bool checkRedactionOutcome(const QByteArray& thisTest, const QString& evtIdToRedact); + template [[nodiscard]] bool validatePendingEvent(const QString& txnId); [[nodiscard]] bool checkDirectChat() const; void finishTest(const TestToken& token, bool condition, const char* file, @@ -152,12 +154,14 @@ void TestSuite::doTest(const QByteArray& testName) Q_ARG(TestToken, testName)); } +template bool TestSuite::validatePendingEvent(const QString& txnId) { auto it = targetRoom->findPendingEvent(txnId); return it != targetRoom->pendingEvents().end() && it->deliveryStatus() == EventStatus::Submitted - && (*it)->transactionId() == txnId; + && (*it)->transactionId() == txnId && is(**it) + && (*it)->matrixType() == EventT::matrixTypeId(); } void TestSuite::finishTest(const TestToken& token, bool condition, @@ -341,7 +345,7 @@ TEST_IMPL(loadMembers) TEST_IMPL(sendMessage) { auto txnId = targetRoom->postPlainText("Hello, " % origin % " is here"); - if (!validatePendingEvent(txnId)) { + if (!validatePendingEvent(txnId)) { clog << "Invalid pending event right after submitting" << endl; FAIL_TEST(); } @@ -367,7 +371,7 @@ TEST_IMPL(sendReaction) const auto targetEvtId = targetRoom->messageEvents().back()->id(); const auto key = QStringLiteral("+1"); const auto txnId = targetRoom->postReaction(targetEvtId, key); - if (!validatePendingEvent(txnId)) { + if (!validatePendingEvent(txnId)) { clog << "Invalid pending event right after submitting" << endl; FAIL_TEST(); } @@ -409,7 +413,7 @@ TEST_IMPL(sendFile) clog << "Sending file " << tfName.toStdString() << endl; const auto txnId = targetRoom->postFile( "Test file", new EventContent::FileContent(tfi)); - if (!validatePendingEvent(txnId)) { + if (!validatePendingEvent(txnId)) { clog << "Invalid pending event right after submitting" << endl; tf->deleteLater(); FAIL_TEST(); @@ -518,6 +522,50 @@ bool TestSuite::checkFileSendingOutcome(const TestToken& thisTest, return true; } +class CustomEvent : public RoomEvent { +public: + DEFINE_EVENT_TYPEID("quotest.custom", CustomEvent) + + CustomEvent(const QJsonObject& jo) + : RoomEvent(typeId(), jo) + {} + CustomEvent(int testValue) + : RoomEvent(typeId(), + basicEventJson(matrixTypeId(), + QJsonObject { { "testValue"_ls, + toJson(testValue) } })) + {} + + auto testValue() const { return contentPart("testValue"_ls); } +}; +REGISTER_EVENT_TYPE(CustomEvent) + +TEST_IMPL(sendCustomEvent) +{ + auto txnId = targetRoom->postEvent(new CustomEvent(42)); + if (!validatePendingEvent(txnId)) { + clog << "Invalid pending event right after submitting" << endl; + FAIL_TEST(); + } + connectUntil( + targetRoom, &Room::pendingEventAboutToMerge, this, + [this, thisTest, txnId](const RoomEvent* evt, int pendingIdx) { + const auto& pendingEvents = targetRoom->pendingEvents(); + Q_ASSERT(pendingIdx >= 0 && pendingIdx < int(pendingEvents.size())); + + if (evt->transactionId() != txnId) + return false; + + return switchOnType(*evt, + [this, thisTest, &evt](const CustomEvent& e) { + FINISH_TEST(!evt->id().isEmpty() && e.testValue() == 42); + }, + [this, thisTest] (const RoomEvent&) { FAIL_TEST(); }); + }); + return false; + +} + TEST_IMPL(setTopic) { const auto newTopic = connection()->generateTxnId(); // Just a way to make @@ -567,7 +615,6 @@ TEST_IMPL(changeName) return false; } - TEST_IMPL(showLocalUsername) { auto* const localUser = connection()->user(); -- cgit v1.2.3 From fdff209744ac4c422f63fe2549aa0132df7e6292 Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Fri, 21 Jan 2022 02:04:10 +0100 Subject: Redo EventRelation; deprecate RelatesTo RelatesTo and EventRelation have been two means to the same end in two different contexts. (Modernised) EventRelation is the one used now both for ReactionEvent and EventContent::TextContent. The modernisation mostly boils down to using inline variables instead of functions to return relation types and switching to QLatin1String from const char* (because we know exactly that those constants are Latin-1 and QLatin1String is more efficient than const char* to compare/convert to QString). --- CMakeLists.txt | 3 ++- lib/events/eventrelation.cpp | 38 ++++++++++++++++++++++++++++++ lib/events/eventrelation.h | 52 +++++++++++++++++++++++++++++++++++++++++ lib/events/reactionevent.cpp | 29 ----------------------- lib/events/reactionevent.h | 32 ++----------------------- lib/events/roommessageevent.cpp | 38 ++++++++---------------------- lib/events/roommessageevent.h | 27 +++++++++++---------- lib/room.cpp | 11 ++++----- lib/room.h | 5 ++-- quotest/quotest.cpp | 2 +- 10 files changed, 128 insertions(+), 109 deletions(-) create mode 100644 lib/events/eventrelation.cpp create mode 100644 lib/events/eventrelation.h delete mode 100644 lib/events/reactionevent.cpp (limited to 'quotest/quotest.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index fd5f1dca..df193b94 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,6 +153,7 @@ list(APPEND lib_SRCS lib/events/stateevent.h lib/events/stateevent.cpp lib/events/simplestateevents.h lib/events/eventcontent.h lib/events/eventcontent.cpp + lib/events/eventrelation.h lib/events/eventrelation.cpp lib/events/roomcreateevent.h lib/events/roomcreateevent.cpp lib/events/roomtombstoneevent.h lib/events/roomtombstoneevent.cpp lib/events/roommessageevent.h lib/events/roommessageevent.cpp @@ -162,7 +163,7 @@ list(APPEND lib_SRCS lib/events/typingevent.h lib/events/typingevent.cpp lib/events/accountdataevents.h lib/events/receiptevent.h lib/events/receiptevent.cpp - lib/events/reactionevent.h lib/events/reactionevent.cpp + lib/events/reactionevent.h lib/events/callinviteevent.h lib/events/callinviteevent.cpp lib/events/callcandidatesevent.h lib/events/callanswerevent.h lib/events/callanswerevent.cpp diff --git a/lib/events/eventrelation.cpp b/lib/events/eventrelation.cpp new file mode 100644 index 00000000..04972f45 --- /dev/null +++ b/lib/events/eventrelation.cpp @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: 2022 Kitsune Ral +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "eventrelation.h" + +#include "../logging.h" +#include "event.h" + +using namespace Quotient; + +void JsonObjectConverter::dumpTo(QJsonObject& jo, + const EventRelation& pod) +{ + if (pod.type.isEmpty()) { + qCWarning(MAIN) << "Empty relation type; won't dump to JSON"; + return; + } + jo.insert(RelTypeKey, pod.type); + jo.insert(EventIdKey, pod.eventId); + if (pod.type == EventRelation::AnnotationType) + jo.insert(QStringLiteral("key"), pod.key); +} + +void JsonObjectConverter::fillFrom(const QJsonObject& jo, + EventRelation& pod) +{ + if (const auto replyJson = jo.value(EventRelation::ReplyType).toObject(); + !replyJson.isEmpty()) { + pod.type = EventRelation::ReplyType; + fromJson(replyJson[EventIdKeyL], pod.eventId); + } else { + // The experimental logic for generic relationships (MSC1849) + fromJson(jo[RelTypeKey], pod.type); + fromJson(jo[EventIdKeyL], pod.eventId); + if (pod.type == EventRelation::AnnotationType) + fromJson(jo["key"_ls], pod.key); + } +} diff --git a/lib/events/eventrelation.h b/lib/events/eventrelation.h new file mode 100644 index 00000000..e445ee42 --- /dev/null +++ b/lib/events/eventrelation.h @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2022 Kitsune Ral +// SPDX-License-Identifier: LGPL-2.1-or-later + +#pragma once + +#include "converters.h" + +namespace Quotient { + +[[maybe_unused]] constexpr auto RelatesToKey = "m.relates_to"_ls; +constexpr auto RelTypeKey = "rel_type"_ls; + +struct QUOTIENT_API EventRelation { + using reltypeid_t = QLatin1String; + + QString type; + QString eventId; + QString key = {}; // Only used for m.annotation for now + + static constexpr auto ReplyType = "m.in_reply_to"_ls; + static constexpr auto AnnotationType = "m.annotation"_ls; + static constexpr auto ReplacementType = "m.replace"_ls; + + static EventRelation replyTo(QString eventId) + { + return { ReplyType, std::move(eventId) }; + } + static EventRelation annotate(QString eventId, QString key) + { + return { AnnotationType, std::move(eventId), std::move(key) }; + } + static EventRelation replace(QString eventId) + { + return { ReplacementType, std::move(eventId) }; + } + + [[deprecated("Use ReplyRelation variable instead")]] + static constexpr auto Reply() { return ReplyType; } + [[deprecated("Use AnnotationRelation variable instead")]] // + static constexpr auto Annotation() { return AnnotationType; } + [[deprecated("Use ReplacementRelation variable instead")]] // + static constexpr auto Replacement() { return ReplacementType; } +}; + +template <> +struct QUOTIENT_API JsonObjectConverter { + static void dumpTo(QJsonObject& jo, const EventRelation& pod); + static void fillFrom(const QJsonObject& jo, EventRelation& pod); +}; + +} + diff --git a/lib/events/reactionevent.cpp b/lib/events/reactionevent.cpp deleted file mode 100644 index b53fffd6..00000000 --- a/lib/events/reactionevent.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-FileCopyrightText: 2019 Kitsune Ral -// SPDX-License-Identifier: LGPL-2.1-or-later - -#include "reactionevent.h" - -using namespace Quotient; - -void JsonObjectConverter::dumpTo( - QJsonObject& jo, const EventRelation& pod) -{ - if (pod.type.isEmpty()) { - qCWarning(MAIN) << "Empty relation type; won't dump to JSON"; - return; - } - jo.insert(QStringLiteral("rel_type"), pod.type); - jo.insert(EventIdKey, pod.eventId); - if (pod.type == EventRelation::Annotation()) - jo.insert(QStringLiteral("key"), pod.key); -} - -void JsonObjectConverter::fillFrom( - const QJsonObject& jo, EventRelation& pod) -{ - // The experimental logic for generic relationships (MSC1849) - fromJson(jo["rel_type"_ls], pod.type); - fromJson(jo[EventIdKeyL], pod.eventId); - if (pod.type == EventRelation::Annotation()) - fromJson(jo["key"_ls], pod.key); -} diff --git a/lib/events/reactionevent.h b/lib/events/reactionevent.h index ce11eaed..b3cb3ca7 100644 --- a/lib/events/reactionevent.h +++ b/lib/events/reactionevent.h @@ -4,38 +4,10 @@ #pragma once #include "roomevent.h" +#include "eventrelation.h" namespace Quotient { -struct QUOTIENT_API EventRelation { - using reltypeid_t = const char*; - static constexpr reltypeid_t Reply() { return "m.in_reply_to"; } - static constexpr reltypeid_t Annotation() { return "m.annotation"; } - static constexpr reltypeid_t Replacement() { return "m.replace"; } - - QString type; - QString eventId; - QString key = {}; // Only used for m.annotation for now - - static EventRelation replyTo(QString eventId) - { - return { Reply(), std::move(eventId) }; - } - static EventRelation annotate(QString eventId, QString key) - { - return { Annotation(), std::move(eventId), std::move(key) }; - } - static EventRelation replace(QString eventId) - { - return { Replacement(), std::move(eventId) }; - } -}; -template <> -struct QUOTIENT_API JsonObjectConverter { - static void dumpTo(QJsonObject& jo, const EventRelation& pod); - static void fillFrom(const QJsonObject& jo, EventRelation& pod); -}; - class QUOTIENT_API ReactionEvent : public RoomEvent { public: DEFINE_EVENT_TYPEID("m.reaction", ReactionEvent) @@ -47,7 +19,7 @@ public: explicit ReactionEvent(const QJsonObject& obj) : RoomEvent(typeId(), obj) {} EventRelation relation() const { - return contentPart("m.relates_to"_ls); + return contentPart(RelatesToKey); } }; REGISTER_EVENT_TYPE(ReactionEvent) diff --git a/lib/events/roommessageevent.cpp b/lib/events/roommessageevent.cpp index 5ab0f845..c07a4f3c 100644 --- a/lib/events/roommessageevent.cpp +++ b/lib/events/roommessageevent.cpp @@ -6,6 +6,7 @@ #include "roommessageevent.h" #include "logging.h" +#include "events/eventrelation.h" #include #include @@ -20,7 +21,6 @@ using namespace EventContent; using MsgType = RoomMessageEvent::MsgType; namespace { // Supporting internal definitions - constexpr auto RelatesToKey = "m.relates_to"_ls; constexpr auto MsgTypeKey = "msgtype"_ls; constexpr auto FormattedBodyKey = "formatted_body"_ls; @@ -84,9 +84,9 @@ MsgType jsonToMsgType(const QString& matrixType) return MsgType::Unknown; } -inline bool isReplacement(const Omittable& rel) +inline bool isReplacement(const Omittable& rel) { - return rel && rel->type == RelatesTo::ReplacementTypeId(); + return rel && rel->type == EventRelation::ReplacementType; } } // anonymous namespace @@ -105,10 +105,10 @@ QJsonObject RoomMessageEvent::assembleContentJson(const QString& plainBody, << "messages; the relation has been stripped off"; } else { // After the above, we know for sure that the content is TextContent - // and that its RelatesTo structure is not omitted + // and that its EventRelation structure is not omitted auto* textContent = static_cast(content); Q_ASSERT(textContent && textContent->relatesTo.has_value()); - if (textContent->relatesTo->type == RelatesTo::ReplacementTypeId()) { + if (textContent->relatesTo->type == EventRelation::ReplacementType) { auto newContentJson = json.take("m.new_content"_ls).toObject(); newContentJson.insert(BodyKey, plainBody); newContentJson.insert(MsgTypeKey, jsonMsgType); @@ -269,7 +269,7 @@ QString RoomMessageEvent::rawMsgTypeForFile(const QFileInfo& fi) } TextContent::TextContent(QString text, const QString& contentType, - Omittable relatesTo) + Omittable relatesTo) : mimeType(QMimeDatabase().mimeTypeForName(contentType)) , body(std::move(text)) , relatesTo(std::move(relatesTo)) @@ -278,26 +278,8 @@ TextContent::TextContent(QString text, const QString& contentType, mimeType = QMimeDatabase().mimeTypeForName("text/html"); } -namespace Quotient { -// Overload the default fromJson<> logic that defined in converters.h -// as we want -template <> -Omittable fromJson(const QJsonValue& jv) -{ - const auto jo = jv.toObject(); - if (jo.isEmpty()) - return none; - const auto replyJson = jo.value(RelatesTo::ReplyTypeId()).toObject(); - if (!replyJson.isEmpty()) - return replyTo(fromJson(replyJson[EventIdKeyL])); - - return RelatesTo { jo.value("rel_type"_ls).toString(), - jo.value(EventIdKeyL).toString() }; -} -} // namespace Quotient - TextContent::TextContent(const QJsonObject& json) - : relatesTo(fromJson>(json[RelatesToKey])) + : relatesTo(fromJson>(json[RelatesToKey])) { QMimeDatabase db; static const auto PlainTextMimeType = db.mimeTypeForName("text/plain"); @@ -331,13 +313,13 @@ void TextContent::fillJson(QJsonObject* json) const if (relatesTo) { json->insert( QStringLiteral("m.relates_to"), - relatesTo->type == RelatesTo::ReplyTypeId() + relatesTo->type == EventRelation::ReplyType ? QJsonObject { { relatesTo->type, QJsonObject { { EventIdKey, relatesTo->eventId } } } } - : QJsonObject { { "rel_type", relatesTo->type }, + : QJsonObject { { RelTypeKey, relatesTo->type }, { EventIdKey, relatesTo->eventId } }); - if (relatesTo->type == RelatesTo::ReplacementTypeId()) { + if (relatesTo->type == EventRelation::ReplacementType) { QJsonObject newContentJson; if (mimeType.inherits("text/html")) { newContentJson.insert(FormatKey, HtmlContentTypeId); diff --git a/lib/events/roommessageevent.h b/lib/events/roommessageevent.h index 0c901b7a..44ef05fb 100644 --- a/lib/events/roommessageevent.h +++ b/lib/events/roommessageevent.h @@ -6,6 +6,7 @@ #pragma once #include "eventcontent.h" +#include "eventrelation.h" #include "roomevent.h" class QFileInfo; @@ -97,23 +98,25 @@ REGISTER_EVENT_TYPE(RoomMessageEvent) using MessageEventType = RoomMessageEvent::MsgType; namespace EventContent { - // Additional event content types - struct RelatesTo { - static constexpr const char* ReplyTypeId() { return "m.in_reply_to"; } - static constexpr const char* ReplacementTypeId() { return "m.replace"; } - QString type; // The only supported relation so far - QString eventId; + struct [[deprecated("Use Quotient::EventRelation instead")]] RelatesTo + : EventRelation { + static constexpr auto ReplyTypeId() { return Reply(); } + static constexpr auto ReplacementTypeId() { return Replacement(); } }; - inline RelatesTo replyTo(QString eventId) + [[deprecated("Use EventRelation::replyTo() instead")]] + inline auto replyTo(QString eventId) { - return { RelatesTo::ReplyTypeId(), std::move(eventId) }; + return EventRelation::replyTo(std::move(eventId)); } - inline RelatesTo replacementOf(QString eventId) + [[deprecated("Use EventRelation::replace() instead")]] + inline auto replacementOf(QString eventId) { - return { RelatesTo::ReplacementTypeId(), std::move(eventId) }; + return EventRelation::replace(std::move(eventId)); } + // Additional event content types + /** * Rich text content for m.text, m.emote, m.notice * @@ -123,14 +126,14 @@ namespace EventContent { class QUOTIENT_API TextContent : public TypedBase { public: TextContent(QString text, const QString& contentType, - Omittable relatesTo = none); + Omittable relatesTo = none); explicit TextContent(const QJsonObject& json); QMimeType type() const override { return mimeType; } QMimeType mimeType; QString body; - Omittable relatesTo; + Omittable relatesTo; protected: void fillJson(QJsonObject* json) const override; diff --git a/lib/room.cpp b/lib/room.cpp index 55efb5b9..ba63f50d 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -996,14 +996,14 @@ Room::findPendingEvent(const QString& txnId) const }); } -const Room::RelatedEvents Room::relatedEvents(const QString& evtId, - const char* relType) const +const Room::RelatedEvents Room::relatedEvents( + const QString& evtId, EventRelation::reltypeid_t relType) const { return d->relations.value({ evtId, relType }); } -const Room::RelatedEvents Room::relatedEvents(const RoomEvent& evt, - const char* relType) const +const Room::RelatedEvents Room::relatedEvents( + const RoomEvent& evt, EventRelation::reltypeid_t relType) const { return relatedEvents(evt.id(), relType); } @@ -2506,8 +2506,7 @@ bool Room::Private::processRedaction(const RedactionEvent& redaction) } if (const auto* reaction = eventCast(oldEvent)) { const auto& targetEvtId = reaction->relation().eventId; - const auto lookupKey = - qMakePair(targetEvtId, EventRelation::Annotation()); + const QPair lookupKey { targetEvtId, EventRelation::AnnotationType }; if (relations.contains(lookupKey)) { relations[lookupKey].removeOne(reaction); emit q->updatedEvent(targetEvtId); diff --git a/lib/room.h b/lib/room.h index 61f475e8..15bc7648 100644 --- a/lib/room.h +++ b/lib/room.h @@ -21,6 +21,7 @@ #include "events/roommessageevent.h" #include "events/roomcreateevent.h" #include "events/roomtombstoneevent.h" +#include "events/eventrelation.h" #include #include @@ -394,9 +395,9 @@ public: PendingEvents::const_iterator findPendingEvent(const QString& txnId) const; const RelatedEvents relatedEvents(const QString& evtId, - const char* relType) const; + EventRelation::reltypeid_t relType) const; const RelatedEvents relatedEvents(const RoomEvent& evt, - const char* relType) const; + EventRelation::reltypeid_t relType) const; const RoomCreateEvent* creation() const { diff --git a/quotest/quotest.cpp b/quotest/quotest.cpp index 5a5642fe..40bc456b 100644 --- a/quotest/quotest.cpp +++ b/quotest/quotest.cpp @@ -381,7 +381,7 @@ TEST_IMPL(sendReaction) if (actualTargetEvtId != targetEvtId) return false; const auto reactions = targetRoom->relatedEvents( - targetEvtId, EventRelation::Annotation()); + targetEvtId, EventRelation::AnnotationType); // It's a test room, assuming no interference there should // be exactly one reaction if (reactions.size() != 1) -- cgit v1.2.3 From 63c953800330017ebb2afbabf41e5c4932c4d640 Mon Sep 17 00:00:00 2001 From: Alexey Rusakov Date: Sat, 22 Jan 2022 13:43:15 +0100 Subject: Quotest: fix changeName test This test was very unreliable because memberRenamed() signal was emitted upon lazy-loading of past member renames. The new code connects to aboutToAddNewMessages() instead, which should only contain the latest renaming event (past events are delivered in the 'state' object). --- quotest/quotest.cpp | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) (limited to 'quotest/quotest.cpp') diff --git a/quotest/quotest.cpp b/quotest/quotest.cpp index 40bc456b..792faabd 100644 --- a/quotest/quotest.cpp +++ b/quotest/quotest.cpp @@ -14,6 +14,7 @@ #include "events/reactionevent.h" #include "events/redactionevent.h" #include "events/simplestateevents.h" +#include "events/roommemberevent.h" #include #include @@ -592,25 +593,31 @@ TEST_IMPL(changeName) clog << "Renaming the user to " << newName.toStdString() << " in the target room" << endl; localUser->rename(newName, targetRoom); - connectUntil(targetRoom, &Room::memberRenamed, this, - [this, thisTest, localUser, newName](const User* u) { - if (localUser != u) - return false; - if (localUser->name(targetRoom) != newName) - FAIL_TEST(); - - clog - << "Member rename successful, renaming the account" + connectUntil( + targetRoom, &Room::aboutToAddNewMessages, this, + [this, thisTest, localUser, newName](const RoomEventsRange& evts) { + for (const auto& e : evts) { + if (const auto* rme = eventCast(e)) { + if (rme->stateKey() != localUser->id() + || !rme->isRename()) + continue; + if (!rme->newDisplayName() + || *rme->newDisplayName() != newName) + FAIL_TEST(); + clog << "Member rename successful, renaming the account" << endl; - const auto newN = newName.mid(0, 5); - localUser->rename(newN); - connectUntil(localUser, &User::defaultNameChanged, - this, [this, thisTest, localUser, newN] { - targetRoom->localUser()->rename({}); - FINISH_TEST(localUser->name() == newN); - }); - return true; - }); + const auto newN = newName.mid(0, 5); + localUser->rename(newN); + connectUntil(localUser, &User::defaultNameChanged, this, + [this, thisTest, localUser, newN] { + targetRoom->localUser()->rename({}); + FINISH_TEST(localUser->name() == newN); + }); + return true; + } + } + return false; + }); }); return false; } -- cgit v1.2.3