mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
refactor(messages): Create class to manage sending/receiving group messages from core
This commit is contained in:
parent
3fd4ce5952
commit
f0d840002a
|
@ -331,6 +331,10 @@ set(${PROJECT_NAME}_SOURCES
|
|||
src/model/imessagedispatcher.h
|
||||
src/model/friendmessagedispatcher.h
|
||||
src/model/friendmessagedispatcher.cpp
|
||||
src/model/groupmessagedispatcher.h
|
||||
src/model/groupmessagedispatcher.cpp
|
||||
src/model/message.h
|
||||
src/model/message.cpp
|
||||
src/model/groupinvite.cpp
|
||||
src/model/groupinvite.h
|
||||
src/model/group.cpp
|
||||
|
|
|
@ -29,6 +29,8 @@ auto_test(persistence paths)
|
|||
auto_test(persistence dbschema)
|
||||
auto_test(persistence offlinemsgengine)
|
||||
auto_test(model friendmessagedispatcher)
|
||||
auto_test(model groupmessagedispatcher)
|
||||
auto_test(model messageprocessor)
|
||||
|
||||
if (UNIX)
|
||||
auto_test(platform posixsignalnotifier)
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
|
||||
#include "groupid.h"
|
||||
#include "icorefriendmessagesender.h"
|
||||
#include "icoregroupmessagesender.h"
|
||||
#include "icoregroupquery.h"
|
||||
#include "icoreidhandler.h"
|
||||
#include "receiptnum.h"
|
||||
#include "toxfile.h"
|
||||
#include "toxid.h"
|
||||
|
@ -50,7 +53,11 @@ class Core;
|
|||
|
||||
using ToxCorePtr = std::unique_ptr<Core>;
|
||||
|
||||
class Core : public QObject, public ICoreFriendMessageSender
|
||||
class Core : public QObject,
|
||||
public ICoreFriendMessageSender,
|
||||
public ICoreIdHandler,
|
||||
public ICoreGroupMessageSender,
|
||||
public ICoreGroupQuery
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -74,12 +81,12 @@ public:
|
|||
static QStringList splitMessage(const QString& message);
|
||||
QString getPeerName(const ToxPk& id) const;
|
||||
QVector<uint32_t> getFriendList() const;
|
||||
GroupId getGroupPersistentId(uint32_t groupNumber) const;
|
||||
uint32_t getGroupNumberPeers(int groupId) const;
|
||||
QString getGroupPeerName(int groupId, int peerId) const;
|
||||
ToxPk getGroupPeerPk(int groupId, int peerId) const;
|
||||
QStringList getGroupPeerNames(int groupId) const;
|
||||
bool getGroupAvEnabled(int groupId) const;
|
||||
GroupId getGroupPersistentId(uint32_t groupNumber) const override;
|
||||
uint32_t getGroupNumberPeers(int groupId) const override;
|
||||
QString getGroupPeerName(int groupId, int peerId) const override;
|
||||
ToxPk getGroupPeerPk(int groupId, int peerId) const override;
|
||||
QStringList getGroupPeerNames(int groupId) const override;
|
||||
bool getGroupAvEnabled(int groupId) const override;
|
||||
ToxPk getFriendPublicKey(uint32_t friendNumber) const;
|
||||
QString getFriendUsername(uint32_t friendNumber) const;
|
||||
|
||||
|
@ -88,11 +95,11 @@ public:
|
|||
uint32_t joinGroupchat(const GroupInvite& inviteInfo);
|
||||
void quitGroupChat(int groupId) const;
|
||||
|
||||
QString getUsername() const;
|
||||
QString getUsername() const override;
|
||||
Status::Status getStatus() const;
|
||||
QString getStatusMessage() const;
|
||||
ToxId getSelfId() const;
|
||||
ToxPk getSelfPublicKey() const;
|
||||
ToxId getSelfId() const override;
|
||||
ToxPk getSelfPublicKey() const override;
|
||||
QPair<QByteArray, QByteArray> getKeypair() const;
|
||||
|
||||
void sendFile(uint32_t friendId, QString filename, QString filePath, long long filesize);
|
||||
|
@ -115,8 +122,8 @@ public slots:
|
|||
void setStatusMessage(const QString& message);
|
||||
|
||||
bool sendMessage(uint32_t friendId, const QString& message, ReceiptNum& receipt) override;
|
||||
void sendGroupMessage(int groupId, const QString& message);
|
||||
void sendGroupAction(int groupId, const QString& message);
|
||||
void sendGroupMessage(int groupId, const QString& message) override;
|
||||
void sendGroupAction(int groupId, const QString& message) override;
|
||||
void changeGroupTitle(int groupId, const QString& title);
|
||||
bool sendAction(uint32_t friendId, const QString& action, ReceiptNum& receipt) override;
|
||||
void sendTyping(uint32_t friendId, bool typing);
|
||||
|
|
33
src/core/icoregroupmessagesender.h
Normal file
33
src/core/icoregroupmessagesender.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
Copyright © 2019 by The qTox Project Contributors
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
qTox is libre software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
qTox is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ICORE_GROUP_MESSAGE_SENDER_H
|
||||
#define ICORE_GROUP_MESSAGE_SENDER_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
class ICoreGroupMessageSender
|
||||
{
|
||||
public:
|
||||
virtual ~ICoreGroupMessageSender() = default;
|
||||
virtual void sendGroupAction(int groupId, const QString& message) = 0;
|
||||
virtual void sendGroupMessage(int groupId, const QString& message) = 0;
|
||||
};
|
||||
|
||||
#endif /*ICORE_GROUP_MESSAGE_SENDER_H*/
|
44
src/core/icoregroupquery.h
Normal file
44
src/core/icoregroupquery.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
Copyright (C) 2013 by Maxim Biro <nurupo.contributions@gmail.com>
|
||||
Copyright © 2014-2018 by The qTox Project Contributors
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
qTox is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ICORE_GROUP_QUERY_H
|
||||
#define ICORE_GROUP_QUERY_H
|
||||
|
||||
#include "groupid.h"
|
||||
#include "toxpk.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class ICoreGroupQuery
|
||||
{
|
||||
public:
|
||||
virtual ~ICoreGroupQuery() = default;
|
||||
virtual GroupId getGroupPersistentId(uint32_t groupNumber) const = 0;
|
||||
virtual uint32_t getGroupNumberPeers(int groupId) const = 0;
|
||||
virtual QString getGroupPeerName(int groupId, int peerId) const = 0;
|
||||
virtual ToxPk getGroupPeerPk(int groupId, int peerId) const = 0;
|
||||
virtual QStringList getGroupPeerNames(int groupId) const = 0;
|
||||
virtual bool getGroupAvEnabled(int groupId) const = 0;
|
||||
};
|
||||
|
||||
#endif /*ICORE_GROUP_QUERY_H*/
|
37
src/core/icoreidhandler.h
Normal file
37
src/core/icoreidhandler.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
Copyright © 2019 by The qTox Project Contributors
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
qTox is libre software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
qTox is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ICORE_ID_HANDLER_H
|
||||
#define ICORE_ID_HANDLER_H
|
||||
|
||||
#include "toxid.h"
|
||||
#include "toxpk.h"
|
||||
|
||||
class ICoreIdHandler
|
||||
{
|
||||
|
||||
public:
|
||||
virtual ~ICoreIdHandler() = default;
|
||||
virtual ToxId getSelfId() const = 0;
|
||||
virtual ToxPk getSelfPublicKey() const = 0;
|
||||
virtual QString getUsername() const = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif /*ICORE_ID_HANDLER_H*/
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include "grouplist.h"
|
||||
#include "src/core/core.h"
|
||||
#include "src/model/group.h"
|
||||
#include <QDebug>
|
||||
#include <QHash>
|
||||
|
@ -31,7 +32,10 @@ Group* GroupList::addGroup(int groupNum, const GroupId& groupId, const QString&
|
|||
if (checker != groupList.end())
|
||||
qWarning() << "addGroup: groupId already taken";
|
||||
|
||||
Group* newGroup = new Group(groupNum, groupId, name, isAvGroupchat, selfName);
|
||||
// TODO: Core instance is bad but grouplist is also an instance so we can
|
||||
// deal with this later
|
||||
auto core = Core::getInstance();
|
||||
Group* newGroup = new Group(groupNum, groupId, name, isAvGroupchat, selfName, *core, *core);
|
||||
groupList[groupId] = newGroup;
|
||||
id2key[groupNum] = groupId;
|
||||
return newGroup;
|
||||
|
|
|
@ -42,10 +42,12 @@ bool sendMessageToCore(ICoreFriendMessageSender& messageSender, const Friend& f,
|
|||
}
|
||||
} // namespace
|
||||
|
||||
FriendMessageDispatcher::FriendMessageDispatcher(Friend& f_, ICoreFriendMessageSender& messageSender_)
|
||||
FriendMessageDispatcher::FriendMessageDispatcher(Friend& f_, MessageProcessor processor_,
|
||||
ICoreFriendMessageSender& messageSender_)
|
||||
: f(f_)
|
||||
, messageSender(messageSender_)
|
||||
, offlineMsgEngine(&f_, &messageSender_)
|
||||
, processor(std::move(processor_))
|
||||
{
|
||||
connect(&f, &Friend::statusChanged, this, &FriendMessageDispatcher::onFriendStatusChange);
|
||||
}
|
||||
|
@ -58,7 +60,7 @@ FriendMessageDispatcher::sendMessage(bool isAction, const QString& content)
|
|||
{
|
||||
const auto firstId = nextMessageId;
|
||||
auto lastId = nextMessageId;
|
||||
for (const auto& message : processOutgoingMessage(isAction, content)) {
|
||||
for (const auto& message : processor.processOutgoingMessage(isAction, content)) {
|
||||
auto messageId = nextMessageId++;
|
||||
lastId = messageId;
|
||||
auto onOfflineMsgComplete = [this, messageId] { emit this->messageComplete(messageId); };
|
||||
|
@ -89,7 +91,7 @@ FriendMessageDispatcher::sendMessage(bool isAction, const QString& content)
|
|||
*/
|
||||
void FriendMessageDispatcher::onMessageReceived(bool isAction, const QString& content)
|
||||
{
|
||||
emit this->messageReceived(f.getPublicKey(), processIncomingMessage(isAction, content));
|
||||
emit this->messageReceived(f.getPublicKey(), processor.processIncomingMessage(isAction, content));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -35,7 +35,8 @@ class FriendMessageDispatcher : public IMessageDispatcher
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FriendMessageDispatcher(Friend& f, ICoreFriendMessageSender& messageSender);
|
||||
FriendMessageDispatcher(Friend& f, MessageProcessor processor,
|
||||
ICoreFriendMessageSender& messageSender);
|
||||
|
||||
std::pair<DispatchedMessageId, DispatchedMessageId> sendMessage(bool isAction,
|
||||
const QString& content) override;
|
||||
|
@ -51,6 +52,7 @@ private:
|
|||
|
||||
ICoreFriendMessageSender& messageSender;
|
||||
OfflineMsgEngine offlineMsgEngine;
|
||||
MessageProcessor processor;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -33,12 +33,14 @@
|
|||
static const int MAX_GROUP_TITLE_LENGTH = 128;
|
||||
|
||||
Group::Group(int groupId, const GroupId persistentGroupId, const QString& name, bool isAvGroupchat,
|
||||
const QString& selfName)
|
||||
const QString& selfName, ICoreGroupQuery& groupQuery, ICoreIdHandler& idHandler)
|
||||
: selfName{selfName}
|
||||
, title{name}
|
||||
, toxGroupNum(groupId)
|
||||
, groupId{persistentGroupId}
|
||||
, avGroupchat{isAvGroupchat}
|
||||
, groupQuery(groupQuery)
|
||||
, idHandler(idHandler)
|
||||
{
|
||||
// in groupchats, we only notify on messages containing your name <-- dumb
|
||||
// sound notifications should be on all messages, but system popup notification
|
||||
|
@ -88,15 +90,14 @@ void Group::regeneratePeerList()
|
|||
// receive the name changed signal a little later, we will emit userJoined before we have their
|
||||
// username, using just their ToxPk, then shortly after emit another peerNameChanged signal.
|
||||
// This can cause double-updated to UI and chatlog, but is unavoidable given the API of toxcore.
|
||||
const Core* core = Core::getInstance();
|
||||
QStringList peers = core->getGroupPeerNames(toxGroupNum);
|
||||
QStringList peers = groupQuery.getGroupPeerNames(toxGroupNum);
|
||||
const auto oldPeerNames = peerDisplayNames;
|
||||
peerDisplayNames.clear();
|
||||
const int nPeers = peers.size();
|
||||
for (int i = 0; i < nPeers; ++i) {
|
||||
const auto pk = core->getGroupPeerPk(toxGroupNum, i);
|
||||
if (pk == core->getSelfPublicKey()) {
|
||||
peerDisplayNames[pk] = core->getUsername();
|
||||
const auto pk = groupQuery.getGroupPeerPk(toxGroupNum, i);
|
||||
if (pk == idHandler.getSelfPublicKey()) {
|
||||
peerDisplayNames[pk] = idHandler.getUsername();
|
||||
} else {
|
||||
peerDisplayNames[pk] = FriendList::decideNickname(pk, peers[i]);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
#include "src/core/contactid.h"
|
||||
#include "src/core/groupid.h"
|
||||
#include "src/core/icoregroupquery.h"
|
||||
#include "src/core/icoreidhandler.h"
|
||||
#include "src/core/toxpk.h"
|
||||
|
||||
#include <QMap>
|
||||
|
@ -34,7 +36,8 @@ class Group : public Contact
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Group(int groupId, const GroupId persistentGroupId, const QString& name, bool isAvGroupchat, const QString& selfName);
|
||||
Group(int groupId, const GroupId persistentGroupId, const QString& name, bool isAvGroupchat,
|
||||
const QString& selfName, ICoreGroupQuery& groupQuery, ICoreIdHandler& idHandler);
|
||||
bool isAvGroupchat() const;
|
||||
uint32_t getId() const override;
|
||||
const GroupId& getPersistentId() const override;
|
||||
|
@ -70,6 +73,8 @@ private:
|
|||
void stopAudioOfDepartedPeers(const ToxPk& peerPk);
|
||||
|
||||
private:
|
||||
ICoreGroupQuery& groupQuery;
|
||||
ICoreIdHandler& idHandler;
|
||||
QString selfName;
|
||||
QString title;
|
||||
QMap<ToxPk, QString> peerDisplayNames;
|
||||
|
|
88
src/model/groupmessagedispatcher.cpp
Normal file
88
src/model/groupmessagedispatcher.cpp
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
Copyright © 2019 by The qTox Project Contributors
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
qTox is libre software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
qTox is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "groupmessagedispatcher.h"
|
||||
#include "src/persistence/igroupsettings.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
GroupMessageDispatcher::GroupMessageDispatcher(Group& g_, MessageProcessor processor_,
|
||||
ICoreIdHandler& idHandler_,
|
||||
ICoreGroupMessageSender& messageSender_,
|
||||
const IGroupSettings& groupSettings_)
|
||||
: group(g_)
|
||||
, processor(processor_)
|
||||
, idHandler(idHandler_)
|
||||
, messageSender(messageSender_)
|
||||
, groupSettings(groupSettings_)
|
||||
{
|
||||
processor.enableMentions();
|
||||
}
|
||||
|
||||
std::pair<DispatchedMessageId, DispatchedMessageId>
|
||||
GroupMessageDispatcher::sendMessage(bool isAction, QString const& content)
|
||||
{
|
||||
const auto firstMessageId = nextMessageId;
|
||||
auto lastMessageId = firstMessageId;
|
||||
|
||||
for (auto const& message : processor.processOutgoingMessage(isAction, content)) {
|
||||
auto messageId = nextMessageId++;
|
||||
lastMessageId = messageId;
|
||||
if (group.getPeersCount() != 1) {
|
||||
if (message.isAction) {
|
||||
messageSender.sendGroupAction(group.getId(), message.content);
|
||||
} else {
|
||||
messageSender.sendGroupMessage(group.getId(), message.content);
|
||||
}
|
||||
}
|
||||
|
||||
// Emit both signals since we do not have receipts for groups
|
||||
//
|
||||
// NOTE: We could in theory keep track of our sent message and wait for
|
||||
// toxcore to send it back to us to indicate a completed message, but
|
||||
// this isn't necessarily the design of toxcore and associating the
|
||||
// received message back would be difficult.
|
||||
emit this->messageSent(messageId, message);
|
||||
emit this->messageComplete(messageId);
|
||||
}
|
||||
|
||||
return std::make_pair(firstMessageId, lastMessageId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Processes and dispatches received message from toxcore
|
||||
* @param[in] sender
|
||||
* @param[in] isAction True if is action
|
||||
* @param[in] content Message content
|
||||
*/
|
||||
void GroupMessageDispatcher::onMessageReceived(const ToxPk& sender, bool isAction, QString const& content)
|
||||
{
|
||||
bool isSelf = sender == idHandler.getSelfPublicKey();
|
||||
|
||||
if (isSelf) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (groupSettings.getBlackList().contains(sender.toString())) {
|
||||
qDebug() << "onGroupMessageReceived: Filtered:" << sender.toString();
|
||||
return;
|
||||
}
|
||||
|
||||
emit messageReceived(sender, processor.processIncomingMessage(isAction, content));
|
||||
}
|
58
src/model/groupmessagedispatcher.h
Normal file
58
src/model/groupmessagedispatcher.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
Copyright © 2019 by The qTox Project Contributors
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
qTox is libre software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
qTox is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GROUP_MESSAGE_DISPATCHER_H
|
||||
#define GROUP_MESSAGE_DISPATCHER_H
|
||||
|
||||
#include "src/core/icoregroupmessagesender.h"
|
||||
#include "src/core/icoreidhandler.h"
|
||||
#include "src/model/group.h"
|
||||
#include "src/model/imessagedispatcher.h"
|
||||
#include "src/model/message.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class IGroupSettings;
|
||||
|
||||
class GroupMessageDispatcher : public IMessageDispatcher
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
GroupMessageDispatcher(Group& group, MessageProcessor processor, ICoreIdHandler& idHandler,
|
||||
ICoreGroupMessageSender& messageSender,
|
||||
const IGroupSettings& groupSettings);
|
||||
|
||||
std::pair<DispatchedMessageId, DispatchedMessageId> sendMessage(bool isAction,
|
||||
QString const& content) override;
|
||||
void onMessageReceived(ToxPk const& sender, bool isAction, QString const& content);
|
||||
|
||||
private:
|
||||
Group& group;
|
||||
MessageProcessor processor;
|
||||
ICoreIdHandler& idHandler;
|
||||
ICoreGroupMessageSender& messageSender;
|
||||
const IGroupSettings& groupSettings;
|
||||
DispatchedMessageId nextMessageId{0};
|
||||
};
|
||||
|
||||
|
||||
#endif /* IMESSAGE_DISPATCHER_H */
|
|
@ -18,9 +18,25 @@
|
|||
*/
|
||||
|
||||
#include "message.h"
|
||||
#include "friend.h"
|
||||
#include "src/core/core.h"
|
||||
|
||||
std::vector<Message> processOutgoingMessage(bool isAction, const QString& content)
|
||||
void MessageProcessor::SharedParams::onUserNameSet(const QString& username)
|
||||
{
|
||||
QString sanename = username;
|
||||
sanename.remove(QRegExp("[\\t\\n\\v\\f\\r\\x0000]"));
|
||||
nameMention = QRegExp("\\b" + QRegExp::escape(username) + "\\b", Qt::CaseInsensitive);
|
||||
sanitizedNameMention = nameMention;
|
||||
}
|
||||
|
||||
MessageProcessor::MessageProcessor(const MessageProcessor::SharedParams& sharedParams)
|
||||
: sharedParams(sharedParams)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Converts an outgoing message into one (or many) sanitized Message(s)
|
||||
*/
|
||||
std::vector<Message> MessageProcessor::processOutgoingMessage(bool isAction, QString const& content)
|
||||
{
|
||||
std::vector<Message> ret;
|
||||
|
||||
|
@ -40,12 +56,34 @@ std::vector<Message> processOutgoingMessage(bool isAction, const QString& conten
|
|||
return ret;
|
||||
}
|
||||
|
||||
Message processIncomingMessage(bool isAction, const QString& message)
|
||||
|
||||
/**
|
||||
* @brief Converts an incoming message into a sanitized Message
|
||||
*/
|
||||
Message MessageProcessor::processIncomingMessage(bool isAction, QString const& message)
|
||||
{
|
||||
QDateTime timestamp = QDateTime::currentDateTime();
|
||||
auto ret = Message{};
|
||||
ret.isAction = isAction;
|
||||
ret.content = message;
|
||||
ret.timestamp = timestamp;
|
||||
|
||||
if (detectingMentions) {
|
||||
auto nameMention = sharedParams.GetNameMention();
|
||||
auto sanitizedNameMention = sharedParams.GetSanitizedNameMention();
|
||||
|
||||
for (auto const& mention : {nameMention, sanitizedNameMention}) {
|
||||
if (mention.indexIn(ret.content) == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto pos = static_cast<size_t>(mention.pos(0));
|
||||
auto length = static_cast<size_t>(mention.matchedLength());
|
||||
|
||||
ret.metadata.push_back({MessageMetadataType::selfMention, pos, pos + length});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -25,15 +25,87 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
class Friend;
|
||||
|
||||
// NOTE: This could be extended in the future to handle all text processing (see
|
||||
// ChatMessage::createChatMessage)
|
||||
enum class MessageMetadataType
|
||||
{
|
||||
selfMention,
|
||||
};
|
||||
|
||||
// May need to be extended in the future to have a more varianty type (imagine
|
||||
// if we wanted to add message replies and shoved a reply id in here)
|
||||
struct MessageMetadata
|
||||
{
|
||||
MessageMetadataType type;
|
||||
// Indicates start position within a Message::content
|
||||
size_t start;
|
||||
// Indicates end position within a Message::content
|
||||
size_t end;
|
||||
};
|
||||
|
||||
struct Message
|
||||
{
|
||||
bool isAction;
|
||||
QString content;
|
||||
QDateTime timestamp;
|
||||
std::vector<MessageMetadata> metadata;
|
||||
};
|
||||
|
||||
|
||||
std::vector<Message> processOutgoingMessage(bool isAction, const QString& content);
|
||||
Message processIncomingMessage(bool isAction, const QString& message);
|
||||
class MessageProcessor
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* Parameters needed by all message processors. Used to reduce duplication
|
||||
* of expensive data looked at by all message processors
|
||||
*/
|
||||
class SharedParams
|
||||
{
|
||||
|
||||
public:
|
||||
QRegExp GetNameMention() const
|
||||
{
|
||||
return nameMention;
|
||||
}
|
||||
QRegExp GetSanitizedNameMention() const
|
||||
{
|
||||
return sanitizedNameMention;
|
||||
}
|
||||
void onUserNameSet(const QString& username);
|
||||
|
||||
private:
|
||||
QRegExp nameMention;
|
||||
QRegExp sanitizedNameMention;
|
||||
};
|
||||
|
||||
MessageProcessor(const SharedParams& sharedParams);
|
||||
|
||||
std::vector<Message> processOutgoingMessage(bool isAction, QString const& content);
|
||||
|
||||
Message processIncomingMessage(bool isAction, QString const& message);
|
||||
|
||||
/**
|
||||
* @brief Enables mention detection in the processor
|
||||
*/
|
||||
inline void enableMentions()
|
||||
{
|
||||
detectingMentions = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables mention detection in the processor
|
||||
*/
|
||||
inline void disableMentions()
|
||||
{
|
||||
detectingMentions = false;
|
||||
};
|
||||
|
||||
private:
|
||||
bool detectingMentions = false;
|
||||
const SharedParams& sharedParams;
|
||||
};
|
||||
|
||||
#endif /*MESSAGE_H*/
|
||||
|
|
35
src/persistence/igroupsettings.h
Normal file
35
src/persistence/igroupsettings.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
Copyright © 2014-2019 by The qTox Project Contributors
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
qTox is libre software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
qTox is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef IGROUP_SETTINGS_H
|
||||
#define IGROUP_SETTINGS_H
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
class IGroupSettings
|
||||
{
|
||||
public:
|
||||
virtual ~IGroupSettings() = default;
|
||||
virtual QStringList getBlackList() const = 0;
|
||||
virtual void setBlackList(const QStringList& blist) = 0;
|
||||
virtual bool getGroupAlwaysNotify() const = 0;
|
||||
virtual void setGroupAlwaysNotify(bool newValue) = 0;
|
||||
};
|
||||
|
||||
#endif /*IGROUP_SETTINGS_H*/
|
|
@ -26,6 +26,7 @@
|
|||
#include "src/core/toxencrypt.h"
|
||||
#include "src/core/toxfile.h"
|
||||
#include "src/persistence/ifriendsettings.h"
|
||||
#include "src/persistence/igroupsettings.h"
|
||||
#include "src/video/ivideosettings.h"
|
||||
|
||||
#include <QDateTime>
|
||||
|
@ -46,6 +47,7 @@ enum class syncType;
|
|||
class Settings : public QObject,
|
||||
public ICoreSettings,
|
||||
public IFriendSettings,
|
||||
public IGroupSettings,
|
||||
public IAudioSettings,
|
||||
public IVideoSettings
|
||||
{
|
||||
|
@ -343,8 +345,8 @@ public:
|
|||
bool getBusySound() const;
|
||||
void setBusySound(bool newValue);
|
||||
|
||||
bool getGroupAlwaysNotify() const;
|
||||
void setGroupAlwaysNotify(bool newValue);
|
||||
bool getGroupAlwaysNotify() const override;
|
||||
void setGroupAlwaysNotify(bool newValue) override;
|
||||
|
||||
QString getInDev() const override;
|
||||
void setInDev(const QString& deviceSpecifier) override;
|
||||
|
@ -476,8 +478,8 @@ public:
|
|||
// Privacy
|
||||
bool getTypingNotification() const;
|
||||
void setTypingNotification(bool enabled);
|
||||
QStringList getBlackList() const;
|
||||
void setBlackList(const QStringList& blist);
|
||||
QStringList getBlackList() const override;
|
||||
void setBlackList(const QStringList& blist) override;
|
||||
|
||||
// State
|
||||
QByteArray getWindowGeometry() const;
|
||||
|
|
|
@ -74,6 +74,8 @@ private:
|
|||
// All unique_ptrs to make construction/init() easier to manage
|
||||
std::unique_ptr<Friend> f;
|
||||
std::unique_ptr<MockFriendMessageSender> messageSender;
|
||||
std::unique_ptr<MessageProcessor::SharedParams> sharedProcessorParams;
|
||||
std::unique_ptr<MessageProcessor> messageProcessor;
|
||||
std::unique_ptr<FriendMessageDispatcher> friendMessageDispatcher;
|
||||
std::map<DispatchedMessageId, Message> outgoingMessages;
|
||||
std::deque<Message> receivedMessages;
|
||||
|
@ -89,8 +91,11 @@ void TestFriendMessageDispatcher::init()
|
|||
f = std::unique_ptr<Friend>(new Friend(0, ToxPk()));
|
||||
f->setStatus(Status::Status::Online);
|
||||
messageSender = std::unique_ptr<MockFriendMessageSender>(new MockFriendMessageSender());
|
||||
friendMessageDispatcher =
|
||||
std::unique_ptr<FriendMessageDispatcher>(new FriendMessageDispatcher(*f, *messageSender));
|
||||
sharedProcessorParams =
|
||||
std::unique_ptr<MessageProcessor::SharedParams>(new MessageProcessor::SharedParams());
|
||||
messageProcessor = std::unique_ptr<MessageProcessor>(new MessageProcessor(*sharedProcessorParams));
|
||||
friendMessageDispatcher = std::unique_ptr<FriendMessageDispatcher>(
|
||||
new FriendMessageDispatcher(*f, *messageProcessor, *messageSender));
|
||||
|
||||
connect(friendMessageDispatcher.get(), &FriendMessageDispatcher::messageSent, this,
|
||||
&TestFriendMessageDispatcher::onMessageSent);
|
||||
|
|
300
test/model/groupmessagedispatcher_test.cpp
Normal file
300
test/model/groupmessagedispatcher_test.cpp
Normal file
|
@ -0,0 +1,300 @@
|
|||
#include "src/core/icoregroupmessagesender.h"
|
||||
#include "src/model/group.h"
|
||||
#include "src/model/groupmessagedispatcher.h"
|
||||
#include "src/model/message.h"
|
||||
#include "src/persistence/settings.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
#include <deque>
|
||||
|
||||
|
||||
class MockGroupMessageSender : public ICoreGroupMessageSender
|
||||
{
|
||||
public:
|
||||
void sendGroupAction(int groupId, const QString& action) override
|
||||
{
|
||||
numSentActions++;
|
||||
}
|
||||
|
||||
void sendGroupMessage(int groupId, const QString& message) override
|
||||
{
|
||||
numSentMessages++;
|
||||
}
|
||||
|
||||
size_t numSentActions = 0;
|
||||
size_t numSentMessages = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Mock 1 peer at group number 0
|
||||
*/
|
||||
class MockGroupQuery : public ICoreGroupQuery
|
||||
{
|
||||
public:
|
||||
GroupId getGroupPersistentId(uint32_t groupNumber) const override
|
||||
{
|
||||
return GroupId(0);
|
||||
}
|
||||
|
||||
uint32_t getGroupNumberPeers(int groupId) const override
|
||||
{
|
||||
if (emptyGroup) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
QString getGroupPeerName(int groupId, int peerId) const override
|
||||
{
|
||||
return QString("peer") + peerId;
|
||||
}
|
||||
|
||||
ToxPk getGroupPeerPk(int groupId, int peerId) const override
|
||||
{
|
||||
uint8_t id[TOX_PUBLIC_KEY_SIZE] = {static_cast<uint8_t>(peerId)};
|
||||
return ToxPk(id);
|
||||
}
|
||||
|
||||
QStringList getGroupPeerNames(int groupId) const override
|
||||
{
|
||||
if (emptyGroup) {
|
||||
return QStringList({QString("me")});
|
||||
}
|
||||
return QStringList({QString("me"), QString("other")});
|
||||
}
|
||||
|
||||
bool getGroupAvEnabled(int groupId) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void setAsEmptyGroup()
|
||||
{
|
||||
emptyGroup = true;
|
||||
}
|
||||
|
||||
void setAsFunctionalGroup()
|
||||
{
|
||||
emptyGroup = false;
|
||||
}
|
||||
|
||||
private:
|
||||
bool emptyGroup = false;
|
||||
};
|
||||
|
||||
class MockCoreIdHandler : public ICoreIdHandler
|
||||
{
|
||||
public:
|
||||
ToxId getSelfId() const override
|
||||
{
|
||||
std::terminate();
|
||||
return ToxId();
|
||||
}
|
||||
|
||||
ToxPk getSelfPublicKey() const override
|
||||
{
|
||||
static uint8_t id[TOX_PUBLIC_KEY_SIZE] = {0};
|
||||
return ToxPk(id);
|
||||
}
|
||||
|
||||
QString getUsername() const override
|
||||
{
|
||||
return "me";
|
||||
}
|
||||
};
|
||||
|
||||
class MockGroupSettings : public IGroupSettings
|
||||
{
|
||||
public:
|
||||
QStringList getBlackList() const override
|
||||
{
|
||||
return blacklist;
|
||||
}
|
||||
|
||||
void setBlackList(const QStringList& blist) override
|
||||
{
|
||||
blacklist = blist;
|
||||
}
|
||||
|
||||
bool getGroupAlwaysNotify() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void setGroupAlwaysNotify(bool newValue) override {}
|
||||
|
||||
private:
|
||||
QStringList blacklist;
|
||||
};
|
||||
|
||||
class TestGroupMessageDispatcher : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TestGroupMessageDispatcher();
|
||||
|
||||
private slots:
|
||||
void init();
|
||||
void testSignals();
|
||||
void testMessageSending();
|
||||
void testEmptyGroup();
|
||||
void testSelfReceive();
|
||||
void testBlacklist();
|
||||
|
||||
void onMessageSent(DispatchedMessageId id, Message message)
|
||||
{
|
||||
auto it = outgoingMessages.find(id);
|
||||
QVERIFY(it == outgoingMessages.end());
|
||||
outgoingMessages.emplace(id);
|
||||
sentMessages.push_back(std::move(message));
|
||||
}
|
||||
|
||||
void onMessageComplete(DispatchedMessageId id)
|
||||
{
|
||||
auto it = outgoingMessages.find(id);
|
||||
QVERIFY(it != outgoingMessages.end());
|
||||
outgoingMessages.erase(it);
|
||||
}
|
||||
|
||||
void onMessageReceived(const ToxPk& sender, Message message)
|
||||
{
|
||||
receivedMessages.push_back(std::move(message));
|
||||
}
|
||||
|
||||
private:
|
||||
// All unique_ptrs to make construction/init() easier to manage
|
||||
std::unique_ptr<MockGroupSettings> groupSettings;
|
||||
std::unique_ptr<MockGroupQuery> groupQuery;
|
||||
std::unique_ptr<MockCoreIdHandler> coreIdHandler;
|
||||
std::unique_ptr<Group> g;
|
||||
std::unique_ptr<MockGroupMessageSender> messageSender;
|
||||
std::unique_ptr<MessageProcessor::SharedParams> sharedProcessorParams;
|
||||
std::unique_ptr<MessageProcessor> messageProcessor;
|
||||
std::unique_ptr<GroupMessageDispatcher> groupMessageDispatcher;
|
||||
std::set<DispatchedMessageId> outgoingMessages;
|
||||
std::deque<Message> sentMessages;
|
||||
std::deque<Message> receivedMessages;
|
||||
};
|
||||
|
||||
TestGroupMessageDispatcher::TestGroupMessageDispatcher() {}
|
||||
|
||||
/**
|
||||
* @brief Test initialization. Resets all members to initial state
|
||||
*/
|
||||
void TestGroupMessageDispatcher::init()
|
||||
{
|
||||
groupSettings = std::unique_ptr<MockGroupSettings>(new MockGroupSettings());
|
||||
groupQuery = std::unique_ptr<MockGroupQuery>(new MockGroupQuery());
|
||||
coreIdHandler = std::unique_ptr<MockCoreIdHandler>(new MockCoreIdHandler());
|
||||
g = std::unique_ptr<Group>(
|
||||
new Group(0, GroupId(0), "TestGroup", false, "me", *groupQuery, *coreIdHandler));
|
||||
messageSender = std::unique_ptr<MockGroupMessageSender>(new MockGroupMessageSender());
|
||||
sharedProcessorParams =
|
||||
std::unique_ptr<MessageProcessor::SharedParams>(new MessageProcessor::SharedParams());
|
||||
messageProcessor = std::unique_ptr<MessageProcessor>(new MessageProcessor(*sharedProcessorParams));
|
||||
groupMessageDispatcher = std::unique_ptr<GroupMessageDispatcher>(
|
||||
new GroupMessageDispatcher(*g, *messageProcessor, *coreIdHandler, *messageSender,
|
||||
*groupSettings));
|
||||
|
||||
connect(groupMessageDispatcher.get(), &GroupMessageDispatcher::messageSent, this,
|
||||
&TestGroupMessageDispatcher::onMessageSent);
|
||||
connect(groupMessageDispatcher.get(), &GroupMessageDispatcher::messageComplete, this,
|
||||
&TestGroupMessageDispatcher::onMessageComplete);
|
||||
connect(groupMessageDispatcher.get(), &GroupMessageDispatcher::messageReceived, this,
|
||||
&TestGroupMessageDispatcher::onMessageReceived);
|
||||
|
||||
outgoingMessages = std::set<DispatchedMessageId>();
|
||||
sentMessages = std::deque<Message>();
|
||||
receivedMessages = std::deque<Message>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests that the signals emitted by the dispatcher are all emitted at the correct times
|
||||
*/
|
||||
void TestGroupMessageDispatcher::testSignals()
|
||||
{
|
||||
groupMessageDispatcher->sendMessage(false, "test");
|
||||
|
||||
// For groups we pair our sent and completed signals since we have no receiver reports
|
||||
QVERIFY(outgoingMessages.size() == 0);
|
||||
QVERIFY(!sentMessages.empty());
|
||||
QVERIFY(sentMessages.front().isAction == false);
|
||||
QVERIFY(sentMessages.front().content == "test");
|
||||
|
||||
// If signals are emitted correctly we should have one message in our received message buffer
|
||||
QVERIFY(receivedMessages.empty());
|
||||
groupMessageDispatcher->onMessageReceived(ToxPk(), false, "test2");
|
||||
|
||||
QVERIFY(!receivedMessages.empty());
|
||||
QVERIFY(receivedMessages.front().isAction == false);
|
||||
QVERIFY(receivedMessages.front().content == "test2");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests that sent messages actually go through to core
|
||||
*/
|
||||
void TestGroupMessageDispatcher::testMessageSending()
|
||||
{
|
||||
groupMessageDispatcher->sendMessage(false, "Test");
|
||||
|
||||
QVERIFY(messageSender->numSentMessages == 1);
|
||||
QVERIFY(messageSender->numSentActions == 0);
|
||||
|
||||
groupMessageDispatcher->sendMessage(true, "Test");
|
||||
|
||||
QVERIFY(messageSender->numSentMessages == 1);
|
||||
QVERIFY(messageSender->numSentActions == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests that if we are the only member in a group we do _not_ send messages to core. Toxcore
|
||||
* isn't too happy if we send messages and we're the only one in the group
|
||||
*/
|
||||
void TestGroupMessageDispatcher::testEmptyGroup()
|
||||
{
|
||||
groupQuery->setAsEmptyGroup();
|
||||
g->regeneratePeerList();
|
||||
|
||||
groupMessageDispatcher->sendMessage(false, "Test");
|
||||
groupMessageDispatcher->sendMessage(true, "Test");
|
||||
|
||||
QVERIFY(messageSender->numSentMessages == 0);
|
||||
QVERIFY(messageSender->numSentActions == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests that we do not emit any signals if we receive a message from ourself. Toxcore will send us back messages we sent
|
||||
*/
|
||||
void TestGroupMessageDispatcher::testSelfReceive()
|
||||
{
|
||||
uint8_t selfId[TOX_PUBLIC_KEY_SIZE] = {0};
|
||||
groupMessageDispatcher->onMessageReceived(ToxPk(selfId), false, "Test");
|
||||
QVERIFY(receivedMessages.size() == 0);
|
||||
|
||||
uint8_t id[TOX_PUBLIC_KEY_SIZE] = {1};
|
||||
groupMessageDispatcher->onMessageReceived(ToxPk(id), false, "Test");
|
||||
QVERIFY(receivedMessages.size() == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests that messages from blacklisted peers do not get propogated from the dispatcher
|
||||
*/
|
||||
void TestGroupMessageDispatcher::testBlacklist()
|
||||
{
|
||||
uint8_t id[TOX_PUBLIC_KEY_SIZE] = {1};
|
||||
auto otherPk = ToxPk(id);
|
||||
groupMessageDispatcher->onMessageReceived(otherPk, false, "Test");
|
||||
QVERIFY(receivedMessages.size() == 1);
|
||||
|
||||
groupSettings->setBlackList({otherPk.toString()});
|
||||
groupMessageDispatcher->onMessageReceived(otherPk, false, "Test");
|
||||
QVERIFY(receivedMessages.size() == 1);
|
||||
}
|
||||
|
||||
// Cannot be guiless due to a settings instance in GroupMessageDispatcher
|
||||
QTEST_GUILESS_MAIN(TestGroupMessageDispatcher)
|
||||
#include "groupmessagedispatcher_test.moc"
|
113
test/model/messageprocessor_test.cpp
Normal file
113
test/model/messageprocessor_test.cpp
Normal file
|
@ -0,0 +1,113 @@
|
|||
#include "src/model/message.h"
|
||||
|
||||
#include <tox/tox.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
namespace {
|
||||
bool messageHasSelfMention(const Message& message)
|
||||
{
|
||||
return std::any_of(message.metadata.begin(), message.metadata.end(), [](MessageMetadata meta) {
|
||||
return meta.type == MessageMetadataType::selfMention;
|
||||
});
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class TestMessageProcessor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TestMessageProcessor(){};
|
||||
|
||||
private slots:
|
||||
void testSelfMention();
|
||||
void testOutgoingMessage();
|
||||
void testIncomingMessage();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Tests detection of username
|
||||
*/
|
||||
void TestMessageProcessor::testSelfMention()
|
||||
{
|
||||
MessageProcessor::SharedParams sharedParams;
|
||||
sharedParams.onUserNameSet("MyUserName");
|
||||
|
||||
auto messageProcessor = MessageProcessor(sharedParams);
|
||||
messageProcessor.enableMentions();
|
||||
|
||||
// Using my name should match
|
||||
auto processedMessage = messageProcessor.processIncomingMessage(false, "MyUserName hi");
|
||||
QVERIFY(messageHasSelfMention(processedMessage));
|
||||
|
||||
// Action messages should match too
|
||||
processedMessage = messageProcessor.processIncomingMessage(true, "MyUserName hi");
|
||||
QVERIFY(messageHasSelfMention(processedMessage));
|
||||
|
||||
// Too much text shouldn't match
|
||||
processedMessage = messageProcessor.processIncomingMessage(false, "MyUserName2");
|
||||
QVERIFY(!messageHasSelfMention(processedMessage));
|
||||
|
||||
// Unless it's a colon
|
||||
processedMessage = messageProcessor.processIncomingMessage(false, "MyUserName: test");
|
||||
QVERIFY(messageHasSelfMention(processedMessage));
|
||||
|
||||
// Too little text shouldn't match
|
||||
processedMessage = messageProcessor.processIncomingMessage(false, "MyUser");
|
||||
QVERIFY(!messageHasSelfMention(processedMessage));
|
||||
|
||||
// The regex should be case insensitive
|
||||
processedMessage = messageProcessor.processIncomingMessage(false, "myusername hi");
|
||||
QVERIFY(messageHasSelfMention(processedMessage));
|
||||
|
||||
// New user name changes should be detected
|
||||
sharedParams.onUserNameSet("NewUserName");
|
||||
processedMessage = messageProcessor.processIncomingMessage(false, "NewUserName: hi");
|
||||
QVERIFY(messageHasSelfMention(processedMessage));
|
||||
|
||||
// Special characters should be removed
|
||||
sharedParams.onUserNameSet("New\nUserName");
|
||||
processedMessage = messageProcessor.processIncomingMessage(false, "NewUserName: hi");
|
||||
QVERIFY(messageHasSelfMention(processedMessage));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests behavior of the processor for outgoing messages
|
||||
*/
|
||||
void TestMessageProcessor::testOutgoingMessage()
|
||||
{
|
||||
auto sharedParams = MessageProcessor::SharedParams();
|
||||
auto messageProcessor = MessageProcessor(sharedParams);
|
||||
|
||||
QString testStr;
|
||||
|
||||
for (size_t i = 0; i < tox_max_message_length() + 50; ++i) {
|
||||
testStr += "a";
|
||||
}
|
||||
|
||||
auto messages = messageProcessor.processOutgoingMessage(false, testStr);
|
||||
|
||||
// The message processor should split our messages
|
||||
QVERIFY(messages.size() == 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests behavior of the processor for incoming messages
|
||||
*/
|
||||
void TestMessageProcessor::testIncomingMessage()
|
||||
{
|
||||
// Nothing too special happening on the incoming side if we aren't looking for self mentions
|
||||
auto sharedParams = MessageProcessor::SharedParams();
|
||||
auto messageProcessor = MessageProcessor(sharedParams);
|
||||
auto message = messageProcessor.processIncomingMessage(false, "test");
|
||||
|
||||
QVERIFY(message.isAction == false);
|
||||
QVERIFY(message.content == "test");
|
||||
QVERIFY(message.timestamp.isValid());
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(TestMessageProcessor)
|
||||
#include "messageprocessor_test.moc"
|
Loading…
Reference in New Issue
Block a user