diff options
Diffstat (limited to 'examples')
-rw-r--r-- | examples/CMakeLists.txt | 8 | ||||
-rw-r--r-- | examples/qmc-example.cpp | 516 |
2 files changed, 268 insertions, 256 deletions
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index cd5e15ed..1f512958 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -48,8 +48,8 @@ endforeach () find_package(Qt5 5.6 REQUIRED Network Gui Multimedia) get_filename_component(Qt5_Prefix "${Qt5_DIR}/../../../.." ABSOLUTE) -find_package(QMatrixClient REQUIRED) -get_filename_component(QMC_Prefix "${QMatrixClient_DIR}/../.." ABSOLUTE) +find_package(Quotient REQUIRED) +get_filename_component(QMC_Prefix "${Quotient_DIR}/../.." ABSOLUTE) message( STATUS "qmc-example configuration:" ) if (CMAKE_BUILD_TYPE) @@ -57,12 +57,12 @@ if (CMAKE_BUILD_TYPE) endif(CMAKE_BUILD_TYPE) message( STATUS " Compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}" ) message( STATUS " Qt: ${Qt5_VERSION} at ${Qt5_Prefix}" ) -message( STATUS " QMatrixClient: ${QMatrixClient_VERSION} at ${QMC_Prefix}" ) +message( STATUS " Quotient: ${Quotient_VERSION} at ${QMC_Prefix}" ) set(example_SRCS qmc-example.cpp) add_executable(qmc-example ${example_SRCS}) -target_link_libraries(qmc-example Qt5::Core QMatrixClient) +target_link_libraries(qmc-example Qt5::Core Quotient) # Installation diff --git a/examples/qmc-example.cpp b/examples/qmc-example.cpp index fc8ddb61..bf4d04c7 100644 --- a/examples/qmc-example.cpp +++ b/examples/qmc-example.cpp @@ -2,91 +2,92 @@ #include "connection.h" #include "room.h" #include "user.h" -#include "csapi/room_send.h" + #include "csapi/joining.h" #include "csapi/leaving.h" -#include "events/simplestateevents.h" +#include "csapi/room_send.h" + #include "events/reactionevent.h" +#include "events/simplestateevents.h" #include <QtCore/QCoreApplication> +#include <QtCore/QFileInfo> #include <QtCore/QStringBuilder> -#include <QtCore/QTimer> #include <QtCore/QTemporaryFile> -#include <QtCore/QFileInfo> -#include <iostream> +#include <QtCore/QTimer> + #include <functional> +#include <iostream> -using namespace QMatrixClient; +using namespace Quotient; using std::cout; using std::endl; using namespace std::placeholders; -class QMCTest : public QObject -{ - public: - QMCTest(Connection* conn, QString testRoomName, QString source); - - private slots: - // clang-format off - void setupAndRun(); - void onNewRoom(Room* r); - void run(); - void doTests(); - void loadMembers(); - void sendMessage(); - void sendReaction(const QString& targetEvtId); - void sendFile(); - void checkFileSendingOutcome(const QString& txnId, - const QString& fileName); - void setTopic(); - void addAndRemoveTag(); - void sendAndRedact(); - bool checkRedactionOutcome(const QString& evtIdToRedact); - void markDirectChat(); - void checkDirectChatOutcome( - const Connection::DirectChatsMap& added); - void conclude(); - void finalize(); - // clang-format on - - private: - QScopedPointer<Connection, QScopedPointerDeleteLater> c; - QStringList running; - QStringList succeeded; - QStringList failed; - QString origin; - QString targetRoomName; - Room* targetRoom = nullptr; - - bool validatePendingEvent(const QString& txnId); +class QMCTest : public QObject { +public: + QMCTest(Connection* conn, QString testRoomName, QString source); + +private slots: + // clang-format off + void setupAndRun(); + void onNewRoom(Room* r); + void run(); + void doTests(); + void loadMembers(); + void sendMessage(); + void sendReaction(const QString& targetEvtId); + void sendFile(); + void checkFileSendingOutcome(const QString& txnId, + const QString& fileName); + void setTopic(); + void addAndRemoveTag(); + void sendAndRedact(); + bool checkRedactionOutcome(const QString& evtIdToRedact); + void markDirectChat(); + void checkDirectChatOutcome( + const Connection::DirectChatsMap& added); + void conclude(); + void finalize(); + // clang-format on + +private: + QScopedPointer<Connection, QScopedPointerDeleteLater> c; + QStringList running; + QStringList succeeded; + QStringList failed; + QString origin; + QString targetRoomName; + Room* targetRoom = nullptr; + + bool validatePendingEvent(const QString& txnId); }; -#define QMC_CHECK(description, condition) \ -{ \ - Q_ASSERT(running.removeOne(description)); \ - if (!!(condition)) \ - { \ - succeeded.push_back(description); \ - cout << (description) << " successful" << endl; \ - if (targetRoom) \ - targetRoom->postMessage( \ - origin % ": " % (description) % " successful", \ - MessageEventType::Notice); \ - } else { \ - failed.push_back(description); \ - cout << (description) << " FAILED" << endl; \ - if (targetRoom) \ - targetRoom->postPlainText( \ - origin % ": " % (description) % " FAILED"); \ - } \ -} +#define QMC_CHECK(description, condition) \ + { \ + Q_ASSERT(running.removeOne(description)); \ + if (!!(condition)) { \ + succeeded.push_back(description); \ + cout << (description) << " successful" << endl; \ + if (targetRoom) \ + targetRoom->postMessage(origin % ": " % (description) \ + % " successful", \ + MessageEventType::Notice); \ + } else { \ + failed.push_back(description); \ + cout << (description) << " FAILED" << endl; \ + if (targetRoom) \ + targetRoom->postPlainText(origin % ": " % (description) \ + % " FAILED"); \ + } \ + } bool QMCTest::validatePendingEvent(const QString& txnId) { auto it = targetRoom->findPendingEvent(txnId); - return it != targetRoom->pendingEvents().end() && - it->deliveryStatus() == EventStatus::Submitted && - (*it)->transactionId() == txnId; + return it != targetRoom->pendingEvents().end() + && it->deliveryStatus() == EventStatus::Submitted + && (*it)->transactionId() == txnId; } QMCTest::QMCTest(Connection* conn, QString testRoomName, QString source) @@ -111,16 +112,17 @@ void QMCTest::setupAndRun() << c->homeserver().toDisplayString().toStdString() << endl; cout << "Access token: " << c->accessToken().toStdString() << endl; - if (!targetRoomName.isEmpty()) - { + if (!targetRoomName.isEmpty()) { cout << "Joining " << targetRoomName.toStdString() << endl; running.push_back("Join room"); auto joinJob = c->joinRoom(targetRoomName); - connect(joinJob, &BaseJob::failure, this, - [this] { QMC_CHECK("Join room", false); conclude(); }); + connect(joinJob, &BaseJob::failure, this, [this] { + QMC_CHECK("Join room", false); + conclude(); + }); // Connection::joinRoom() creates a Room object upon JoinRoomJob::success // but this object is empty until the first sync is done. - connect(joinJob, &BaseJob::success, this, [this,joinJob] { + connect(joinJob, &BaseJob::success, this, [this, joinJob] { targetRoom = c->room(joinJob->roomId(), JoinState::Join); QMC_CHECK("Join room", targetRoom != nullptr); @@ -136,17 +138,18 @@ void QMCTest::onNewRoom(Room* r) << " Name: " << r->name().toStdString() << endl << " Canonical alias: " << r->canonicalAlias().toStdString() << endl << endl; - connect(r, &Room::aboutToAddNewMessages, r, [r] (RoomEventsRange timeline) { + connect(r, &Room::aboutToAddNewMessages, r, [r](RoomEventsRange timeline) { cout << timeline.size() << " new event(s) in room " << r->canonicalAlias().toStdString() << endl; -// for (const auto& item: timeline) -// { -// cout << "From: " -// << r->roomMembername(item->senderId()).toStdString() -// << endl << "Timestamp:" -// << item->timestamp().toString().toStdString() << endl -// << "JSON:" << endl << item->originalJson().toStdString() << endl; -// } + // for (const auto& item: timeline) + // { + // cout << "From: " + // << r->roomMembername(item->senderId()).toStdString() + // << endl << "Timestamp:" + // << item->timestamp().toString().toStdString() << endl + // << "JSON:" << endl << + // item->originalJson().toStdString() << endl; + // } }); } @@ -156,8 +159,9 @@ void QMCTest::run() c->syncLoop(); connectSingleShot(c.data(), &Connection::syncDone, this, &QMCTest::doTests); connect(c.data(), &Connection::syncDone, c.data(), [this] { - cout << "Sync complete, " << running.size() << " test(s) in the air: " - << running.join(", ").toStdString() << endl; + cout << "Sync complete, " << running.size() + << " test(s) in the air: " << running.join(", ").toStdString() + << endl; if (running.isEmpty()) conclude(); }); @@ -186,8 +190,7 @@ void QMCTest::loadMembers() running.push_back("Loading members"); auto* r = c->roomByAlias(QStringLiteral("#quotient:matrix.org"), JoinState::Join); - if (!r) - { + if (!r) { cout << "#test:matrix.org is not found in the test user's rooms" << endl; QMC_CHECK("Loading members", false); return; @@ -195,14 +198,13 @@ void QMCTest::loadMembers() // It's not exactly correct because an arbitrary server might not support // lazy loading; but in the absence of capabilities framework we assume // it does. - if (r->memberNames().size() >= r->joinedCount()) - { + if (r->memberNames().size() >= r->joinedCount()) { cout << "Lazy loading doesn't seem to be enabled" << endl; QMC_CHECK("Loading members", false); return; } r->setDisplayed(); - connect(r, &Room::allMembersLoaded, [this,r] { + connect(r, &Room::allMembersLoaded, [this, r] { QMC_CHECK("Loading members", r->memberNames().size() >= r->joinedCount()); }); @@ -213,15 +215,15 @@ void QMCTest::sendMessage() running.push_back("Message sending"); cout << "Sending a message" << endl; auto txnId = targetRoom->postPlainText("Hello, " % origin % " is here"); - if (!validatePendingEvent(txnId)) - { + if (!validatePendingEvent(txnId)) { cout << "Invalid pending event right after submitting" << endl; QMC_CHECK("Message sending", false); return; } - connectUntil(targetRoom, &Room::pendingEventAboutToMerge, this, - [this,txnId] (const RoomEvent* evt, int pendingIdx) { + connectUntil( + targetRoom, &Room::pendingEventAboutToMerge, this, + [this, txnId](const RoomEvent* evt, int pendingIdx) { const auto& pendingEvents = targetRoom->pendingEvents(); Q_ASSERT(pendingIdx >= 0 && pendingIdx < int(pendingEvents.size())); @@ -229,12 +231,12 @@ void QMCTest::sendMessage() return false; QMC_CHECK("Message sending", - is<RoomMessageEvent>(*evt) && !evt->id().isEmpty() && - pendingEvents[size_t(pendingIdx)]->transactionId() - == evt->transactionId()); + is<RoomMessageEvent>(*evt) && !evt->id().isEmpty() + && pendingEvents[size_t(pendingIdx)]->transactionId() + == evt->transactionId()); sendReaction(evt->id()); return true; - }); + }); } void QMCTest::sendReaction(const QString& targetEvtId) @@ -252,28 +254,27 @@ void QMCTest::sendReaction(const QString& targetEvtId) // TODO: Check that it came back as a reaction event and that it attached to // the right event - connectUntil(targetRoom, &Room::updatedEvent, this, - [this, txnId, key, - targetEvtId](const QString& actualTargetEvtId) { - if (actualTargetEvtId != targetEvtId) - return false; - const auto reactions = targetRoom->relatedEvents( - targetEvtId, EventRelation::Annotation()); - // It's a test room, assuming no interference there should - // be exactly one reaction - if (reactions.size() != 1) { - QMC_CHECK("Reaction sending", false); - } else { - const auto* evt = - eventCast<const ReactionEvent>(reactions.back()); - QMC_CHECK("Reaction sending", - is<ReactionEvent>(*evt) - && !evt->id().isEmpty() - && evt->relation().key == key - && evt->transactionId() == txnId); - } - return true; - }); + connectUntil( + targetRoom, &Room::updatedEvent, this, + [this, txnId, key, targetEvtId](const QString& actualTargetEvtId) { + if (actualTargetEvtId != targetEvtId) + return false; + const auto reactions = targetRoom->relatedEvents( + targetEvtId, EventRelation::Annotation()); + // It's a test room, assuming no interference there should + // be exactly one reaction + if (reactions.size() != 1) { + QMC_CHECK("Reaction sending", false); + } else { + const auto* evt = + eventCast<const ReactionEvent>(reactions.back()); + QMC_CHECK("Reaction sending", + is<ReactionEvent>(*evt) && !evt->id().isEmpty() + && evt->relation().key == key + && evt->transactionId() == txnId); + } + return true; + }); } void QMCTest::sendFile() @@ -281,8 +282,7 @@ void QMCTest::sendFile() running.push_back("File sending"); cout << "Sending a file" << endl; auto* tf = new QTemporaryFile; - if (!tf->open()) - { + if (!tf->open()) { cout << "Failed to create a temporary file" << endl; QMC_CHECK("File sending", false); return; @@ -293,10 +293,9 @@ void QMCTest::sendFile() // the full path const auto tfName = QFileInfo(*tf).fileName(); cout << "Sending file" << tfName.toStdString() << endl; - const auto txnId = targetRoom->postFile("Test file", - QUrl::fromLocalFile(tf->fileName())); - if (!validatePendingEvent(txnId)) - { + const auto txnId = + targetRoom->postFile("Test file", QUrl::fromLocalFile(tf->fileName())); + if (!validatePendingEvent(txnId)) { cout << "Invalid pending event right after submitting" << endl; QMC_CHECK("File sending", false); delete tf; @@ -305,43 +304,40 @@ void QMCTest::sendFile() // FIXME: Clean away connections (connectUntil doesn't help here). connect(targetRoom, &Room::fileTransferCompleted, this, - [this,txnId,tf,tfName] (const QString& id) { - auto fti = targetRoom->fileTransferInfo(id); - Q_ASSERT(fti.status == FileTransferInfo::Completed); + [this, txnId, tf, tfName](const QString& id) { + auto fti = targetRoom->fileTransferInfo(id); + Q_ASSERT(fti.status == FileTransferInfo::Completed); - if (id != txnId) - return; + if (id != txnId) + return; - delete tf; + delete tf; - checkFileSendingOutcome(txnId, tfName); - }); + checkFileSendingOutcome(txnId, tfName); + }); connect(targetRoom, &Room::fileTransferFailed, this, - [this,txnId,tf] - (const QString& id, const QString& error) { - if (id != txnId) - return; + [this, txnId, tf](const QString& id, const QString& error) { + if (id != txnId) + return; - targetRoom->postPlainText(origin % ": File upload failed: " % error); - delete tf; + targetRoom->postPlainText(origin % ": File upload failed: " + % error); + delete tf; - QMC_CHECK("File sending", false); - }); + QMC_CHECK("File sending", false); + }); } void QMCTest::checkFileSendingOutcome(const QString& txnId, const QString& fileName) { auto it = targetRoom->findPendingEvent(txnId); - if (it == targetRoom->pendingEvents().end()) - { - cout << "Pending file event dropped before upload completion" - << endl; + if (it == targetRoom->pendingEvents().end()) { + cout << "Pending file event dropped before upload completion" << endl; QMC_CHECK("File sending", false); return; } - if (it->deliveryStatus() != EventStatus::FileUploaded) - { + if (it->deliveryStatus() != EventStatus::FileUploaded) { cout << "Pending file event status upon upload completion is " << it->deliveryStatus() << " != FileUploaded(" << EventStatus::FileUploaded << ')' << endl; @@ -349,8 +345,9 @@ void QMCTest::checkFileSendingOutcome(const QString& txnId, return; } - connectUntil(targetRoom, &Room::pendingEventAboutToMerge, this, - [this,txnId,fileName] (const RoomEvent* evt, int pendingIdx) { + connectUntil( + targetRoom, &Room::pendingEventAboutToMerge, this, + [this, txnId, fileName](const RoomEvent* evt, int pendingIdx) { const auto& pendingEvents = targetRoom->pendingEvents(); Q_ASSERT(pendingIdx >= 0 && pendingIdx < int(pendingEvents.size())); @@ -359,58 +356,78 @@ void QMCTest::checkFileSendingOutcome(const QString& txnId, cout << "File event " << txnId.toStdString() << " arrived in the timeline" << endl; - visit(*evt, - [&] (const RoomMessageEvent& e) { - QMC_CHECK("File sending", - !e.id().isEmpty() && - pendingEvents[size_t(pendingIdx)] - ->transactionId() == txnId && - e.hasFileContent() && - e.content()->fileInfo()->originalName == fileName); + visit( + *evt, + [&](const RoomMessageEvent& e) { + QMC_CHECK( + "File sending", + !e.id().isEmpty() + && pendingEvents[size_t(pendingIdx)]->transactionId() + == txnId + && e.hasFileContent() + && e.content()->fileInfo()->originalName == fileName); }, - [this] (const RoomEvent&) { - QMC_CHECK("File sending", false); - }); + [this](const RoomEvent&) { QMC_CHECK("File sending", false); }); return true; - }); + }); } void QMCTest::setTopic() { static const char* const stateTestName = "State setting test"; - static const char* const fakeStateTestName = "Fake state event immunity test"; running.push_back(stateTestName); - running.push_back(fakeStateTestName); - auto initialTopic = targetRoom->topic(); - const auto newTopic = c->generateTxnId(); + const auto newTopic = c->generateTxnId(); // Just a way to get a unique id targetRoom->setTopic(newTopic); // Sets the state by proper means const auto fakeTopic = c->generateTxnId(); - targetRoom->postJson(RoomTopicEvent::matrixTypeId(), // Fake state event - RoomTopicEvent(fakeTopic).contentJson()); + const auto fakeTxnId = + targetRoom->postJson(RoomTopicEvent::matrixTypeId(), // Fake state event + RoomTopicEvent(fakeTopic).contentJson()); connectUntil(targetRoom, &Room::topicChanged, this, - [this,newTopic,fakeTopic,initialTopic] { - if (targetRoom->topic() == newTopic) - { - QMC_CHECK(stateTestName, true); - // Don't reset the topic yet if the negative test still runs - if (!running.contains(fakeStateTestName)) - targetRoom->setTopic(initialTopic); + [this, newTopic] { + if (targetRoom->topic() == newTopic) { + QMC_CHECK(stateTestName, true); + return true; + } + return false; + }); + + // Older Synapses allowed sending fake state events through, although + // did not process them; // https://github.com/matrix-org/synapse/pull/5805 + // changed that and now Synapse 400's in response to fake state events. + // The following two-step approach handles both cases, assuming that + // Room::pendingEventChanged() with EventStatus::ReachedServer is guaranteed + // to be emitted before Room::pendingEventAboutToMerge. + connectUntil( + targetRoom, &Room::pendingEventChanged, this, + [this, fakeTopic, fakeTxnId](int pendingIdx) { + const auto& pendingEvents = targetRoom->pendingEvents(); + Q_ASSERT(pendingIdx >= 0 && pendingIdx < int(pendingEvents.size())); + const auto& evt = pendingEvents[pendingIdx]; + if (evt->transactionId() != fakeTxnId) + return false; + // If Synapse rejected the event, skip the immunity test. + if (evt.deliveryStatus() == EventStatus::SendingFailed) return true; - } - return false; - }); - connectUntil(targetRoom, &Room::pendingEventAboutToMerge, this, - [this,fakeTopic,initialTopic] (const RoomEvent* e, int) { - if (e->contentJson().value("topic").toString() != fakeTopic) - return false; // Wait on for the right event + if (evt.deliveryStatus() != EventStatus::ReachedServer) + return false; - QMC_CHECK(fakeStateTestName, !e->isStateEvent()); - if (!running.contains(fakeStateTestName)) - targetRoom->setTopic(initialTopic); + // All before was just a preparation, this is where the test starts. + static const char* const fakeStateTestName = + "Fake state event immunity test"; + running.push_back(fakeStateTestName); + connectUntil( + targetRoom, &Room::pendingEventAboutToMerge, this, + [this, fakeTopic](const RoomEvent* e, int) { + if (e->contentJson().value("topic").toString() != fakeTopic) + return false; // Wait on for the right event + + QMC_CHECK(fakeStateTestName, !e->isStateEvent()); + return true; + }); return true; }); } @@ -418,7 +435,7 @@ void QMCTest::setTopic() void QMCTest::addAndRemoveTag() { running.push_back("Tagging test"); - static const auto TestTag = QStringLiteral("org.qmatrixclient.test"); + static const auto TestTag = QStringLiteral("org.quotient.test"); // Pre-requisite if (targetRoom->tags().contains(TestTag)) targetRoom->removeTag(TestTag); @@ -428,8 +445,7 @@ void QMCTest::addAndRemoveTag() cout << "Room " << targetRoom->id().toStdString() << ", tag(s) changed:" << endl << " " << targetRoom->tagNames().join(", ").toStdString() << endl; - if (targetRoom->tags().contains(TestTag)) - { + if (targetRoom->tags().contains(TestTag)) { cout << "Test tag set, removing it now" << endl; targetRoom->removeTag(TestTag); QMC_CHECK("Tagging test", !targetRoom->tags().contains(TestTag)); @@ -445,22 +461,23 @@ void QMCTest::sendAndRedact() running.push_back("Redaction"); cout << "Sending a message to redact" << endl; auto txnId = targetRoom->postPlainText(origin % ": message to redact"); - if (txnId.isEmpty()) - { + if (txnId.isEmpty()) { QMC_CHECK("Redaction", false); return; } connect(targetRoom, &Room::messageSent, this, - [this,txnId] (const QString& tId, const QString& evtId) { - if (tId != txnId) - return; + [this, txnId](const QString& tId, const QString& evtId) { + if (tId != txnId) + return; - cout << "Redacting the message" << endl; - targetRoom->redactEvent(evtId, origin); + cout << "Redacting the message" << endl; + targetRoom->redactEvent(evtId, origin); - connectUntil(targetRoom, &Room::addedMessages, this, - [this,evtId] { return checkRedactionOutcome(evtId); }); - }); + connectUntil(targetRoom, &Room::addedMessages, this, + [this, evtId] { + return checkRedactionOutcome(evtId); + }); + }); } bool QMCTest::checkRedactionOutcome(const QString& evtIdToRedact) @@ -472,39 +489,39 @@ bool QMCTest::checkRedactionOutcome(const QString& evtIdToRedact) if (it == targetRoom->timelineEdge()) return false; // Waiting for the next sync - if ((*it)->isRedacted()) - { + if ((*it)->isRedacted()) { cout << "The sync brought already redacted message" << endl; QMC_CHECK("Redaction", true); } else { cout << "Message came non-redacted with the sync, waiting for redaction" << endl; connectUntil(targetRoom, &Room::replacedEvent, this, - [this,evtIdToRedact] - (const RoomEvent* newEvent, const RoomEvent* oldEvent) { - if (oldEvent->id() != evtIdToRedact) - return false; - - QMC_CHECK("Redaction", newEvent->isRedacted() && - newEvent->redactionReason() == origin); - return true; - }); + [this, evtIdToRedact](const RoomEvent* newEvent, + const RoomEvent* oldEvent) { + if (oldEvent->id() != evtIdToRedact) + return false; + + QMC_CHECK("Redaction", + newEvent->isRedacted() + && newEvent->redactionReason() == origin); + return true; + }); } return true; } void QMCTest::markDirectChat() { - if (targetRoom->directChatUsers().contains(c->user())) - { + if (targetRoom->directChatUsers().contains(c->user())) { cout << "Warning: the room is already a direct chat," - " only unmarking will be tested" << endl; - checkDirectChatOutcome({{ c->user(), targetRoom->id() }}); + " only unmarking will be tested" + << endl; + checkDirectChatOutcome({ { c->user(), targetRoom->id() } }); return; } // Connect first because the signal is emitted synchronously. - connect(c.data(), &Connection::directChatsListChanged, - this, &QMCTest::checkDirectChatOutcome); + connect(c.data(), &Connection::directChatsListChanged, this, + &QMCTest::checkDirectChatOutcome); cout << "Marking the room as a direct chat" << endl; c->addToDirectChats(targetRoom, c->user()); } @@ -513,14 +530,12 @@ void QMCTest::checkDirectChatOutcome(const Connection::DirectChatsMap& added) { running.push_back("Direct chat test"); disconnect(c.data(), &Connection::directChatsListChanged, nullptr, nullptr); - if (!targetRoom->isDirectChat()) - { + if (!targetRoom->isDirectChat()) { cout << "The room has not been marked as a direct chat" << endl; QMC_CHECK("Direct chat test", false); return; } - if (!added.contains(c->user(), targetRoom->id())) - { + if (!added.contains(c->user(), targetRoom->id())) { cout << "The room has not been listed in new direct chats" << endl; QMC_CHECK("Direct chat test", false); return; @@ -536,45 +551,42 @@ void QMCTest::conclude() c->stopSync(); auto succeededRec = QString::number(succeeded.size()) + " tests succeeded"; if (!failed.isEmpty() || !running.isEmpty()) - succeededRec += " of " % - QString::number(succeeded.size() + failed.size() + running.size()) % - " total"; + succeededRec += + " of " + % QString::number(succeeded.size() + failed.size() + running.size()) + % " total"; QString plainReport = origin % ": Testing complete, " % succeededRec; QString color = failed.isEmpty() && running.isEmpty() ? "00AA00" : "AA0000"; - QString htmlReport = origin % ": <strong><font data-mx-color='#" % color % - "' color='#" % color % "'>Testing complete</font></strong>, " % - succeededRec; - if (!failed.isEmpty()) - { + QString htmlReport = origin % ": <strong><font data-mx-color='#" % color + % "' color='#" % color + % "'>Testing complete</font></strong>, " % succeededRec; + if (!failed.isEmpty()) { plainReport += "\nFAILED: " % failed.join(", "); htmlReport += "<br><strong>Failed:</strong> " % failed.join(", "); } - if (!running.isEmpty()) - { + if (!running.isEmpty()) { plainReport += "\nDID NOT FINISH: " % running.join(", "); - htmlReport += - "<br><strong>Did not finish:</strong> " % running.join(", "); + htmlReport += "<br><strong>Did not finish:</strong> " + % running.join(", "); } cout << plainReport.toStdString() << endl; - if (targetRoom) - { - // TODO: Waiting for proper futures to come so that it could be: -// targetRoom->postHtmlText(...) -// .then(this, &QMCTest::finalize); // Qt-style or -// .then([this] { finalize(); }); // STL-style + if (targetRoom) { + // TODO: Waiting for proper futures to come so that it could be: + // targetRoom->postHtmlText(...) + // .then(this, &QMCTest::finalize); // Qt-style or + // .then([this] { finalize(); }); // STL-style auto txnId = targetRoom->postHtmlText(plainReport, htmlReport); connect(targetRoom, &Room::messageSent, this, - [this,txnId] (QString serverTxnId) { - if (txnId != serverTxnId) - return; + [this, txnId](QString serverTxnId) { + if (txnId != serverTxnId) + return; - cout << "Leaving the room" << endl; - connect(targetRoom->leaveRoom(), &BaseJob::finished, - this, &QMCTest::finalize); - }); - } - else + cout << "Leaving the room" << endl; + connect(targetRoom->leaveRoom(), &BaseJob::finished, this, + &QMCTest::finalize); + }); + } else finalize(); } @@ -582,19 +594,19 @@ void QMCTest::finalize() { cout << "Logging out" << endl; c->logout(); - connect(c.data(), &Connection::loggedOut, qApp, - [this] { - QCoreApplication::processEvents(); - QCoreApplication::exit(failed.size() + running.size()); - }); + connect(c.data(), &Connection::loggedOut, qApp, [this] { + QCoreApplication::processEvents(); + QCoreApplication::exit(failed.size() + running.size()); + }); } int main(int argc, char* argv[]) { QCoreApplication app(argc, argv); - if (argc < 4) - { - cout << "Usage: qmc-example <user> <passwd> <device_name> [<room_alias> [origin]]" << endl; + if (argc < 4) { + cout << "Usage: qmc-example <user> <passwd> <device_name> " + "[<room_alias> [origin]]" + << endl; return -1; } @@ -602,6 +614,6 @@ int main(int argc, char* argv[]) auto conn = new Connection; conn->connectToServer(argv[1], argv[2], argv[3]); QMCTest test { conn, argc >= 5 ? argv[4] : nullptr, - argc >= 6 ? argv[5] : nullptr }; + argc >= 6 ? argv[5] : nullptr }; return app.exec(); } |