summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swift/Controllers/Chat/UnitTest')
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatControllerTest.cpp162
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatListWindowChatTest.cpp292
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp344
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp2339
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChattablesTest.cpp140
-rw-r--r--Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp1301
-rw-r--r--Swift/Controllers/Chat/UnitTest/MockChatListWindow.h35
7 files changed, 3714 insertions, 899 deletions
diff --git a/Swift/Controllers/Chat/UnitTest/ChatControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatControllerTest.cpp
new file mode 100644
index 0000000..e010656
--- /dev/null
+++ b/Swift/Controllers/Chat/UnitTest/ChatControllerTest.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <memory>
+#include <string>
+
+#include <gtest/gtest.h>
+#include <hippomocks.h>
+
+#include <Swiften/Avatars/NullAvatarManager.h>
+#include <Swiften/Client/ClientBlockListManager.h>
+#include <Swiften/Client/DummyStanzaChannel.h>
+#include <Swiften/Client/NickResolver.h>
+#include <Swiften/Disco/DummyEntityCapsProvider.h>
+#include <Swiften/Network/DummyTimerFactory.h>
+#include <Swiften/Queries/DummyIQChannel.h>
+#include <Swiften/Roster/XMPPRoster.h>
+#include <Swiften/Roster/XMPPRosterImpl.h>
+#include <Swiften/VCards/VCardManager.h>
+#include <Swiften/VCards/VCardMemoryStorage.h>
+
+#include <Swift/Controllers/Chat/AutoAcceptMUCInviteDecider.h>
+#include <Swift/Controllers/Chat/ChatController.h>
+#include <Swift/Controllers/Chat/ChatMessageParser.h>
+#include <Swift/Controllers/Chat/Chattables.h>
+#include <Swift/Controllers/Settings/DummySettingsProvider.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
+#include <Swift/Controllers/UnitTest/MockChatWindow.h>
+#include <Swift/Controllers/XMPPEvents/EventController.h>
+
+using namespace Swift;
+
+/**
+ * Most of the ChatController tests are in ChatsManagerTest.
+ * New tests related with ChatController should be added here,
+ * and old tests should be migrated when possible.
+ */
+
+class ExtendedChatController : public ChatController {
+public:
+ ExtendedChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, SettingsProvider* settings, Chattables& chattables) :
+ ChatController(self, stanzaChannel, iqRouter, chatWindowFactory, contact, nickResolver, presenceOracle, avatarManager, isInMUC, useDelayForLatency, eventStream, timerFactory, eventController, entityCapsProvider, userWantsReceipts, historyController, mucRegistry, highlightManager, clientBlockListManager, chatMessageParser, autoAcceptMUCInviteDecider, settings, chattables) {
+ }
+
+ std::map<std::shared_ptr<Stanza>, std::string> getUnackedStanzas() { return unackedStanzas_; }
+ std::map<std::string, std::shared_ptr<Stanza>> getFailedStanzas() { return failedStanzas_; }
+};
+
+class ChatControllerTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
+ self_ = JID("alice@wonderland.lit");
+ other_ = JID("whiterabbit@wonderland.lit");
+ stanzaChannel_ = new DummyStanzaChannel();
+ iqChannel_ = new DummyIQChannel();
+ iqRouter_ = new IQRouter(iqChannel_);
+ eventController_ = new EventController();
+ xmppRoster_ = new XMPPRosterImpl();
+ vCardManager_ = new VCardManager(self_, iqRouter_, vCardMemoryStorage_);
+ mucRegistry_ = new MUCRegistry();
+ nickResolver_ = new NickResolver(self_, xmppRoster_, vCardManager_, mucRegistry_);
+ presenceOracle_ = new PresenceOracle(stanzaChannel_, xmppRoster_);
+ avatarManager_ = new NullAvatarManager();
+ uiEventStream_ = new UIEventStream();
+ timerFactory_ = new DummyTimerFactory();
+ entityCapsProvider_ = new DummyEntityCapsProvider();
+ settings_ = new DummySettingsProvider();
+ highlightManager_ = new HighlightManager(settings_);
+ highlightManager_->resetToDefaultConfiguration();
+ clientBlockListManager_ = new ClientBlockListManager(iqRouter_);
+ autoAcceptMUCInviteDecider_ = new AutoAcceptMUCInviteDecider(self_.getDomain(), xmppRoster_, settings_);
+ chatMessageParser_ = std::make_shared<ChatMessageParser>(std::map<std::string, std::string>(), highlightManager_->getConfiguration(), ChatMessageParser::Mode::GroupChat);
+ mocks_ = new MockRepository();
+ window_ = new MockChatWindow();
+ chatWindowFactory_ = mocks_->InterfaceMock<ChatWindowFactory>();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(other_, uiEventStream_).Return(window_);
+ chattables_ = std::make_unique<Chattables>();
+
+ controller_ = new ExtendedChatController(self_, stanzaChannel_, iqRouter_, chatWindowFactory_, other_, nickResolver_, presenceOracle_, avatarManager_, false, false, uiEventStream_, timerFactory_, eventController_, entityCapsProvider_, false, nullptr, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser_, nullptr, settings_, *chattables_);
+ }
+ virtual void TearDown() {
+ delete controller_;
+ chattables_.reset();
+ chatMessageParser_.reset();
+ delete autoAcceptMUCInviteDecider_;
+ delete clientBlockListManager_;
+ delete highlightManager_;
+ delete settings_;
+ delete entityCapsProvider_;
+ delete timerFactory_;
+ delete uiEventStream_;
+ delete avatarManager_;
+ delete presenceOracle_;
+ delete nickResolver_;
+ delete mucRegistry_;
+ delete vCardManager_;
+ delete xmppRoster_;
+ delete eventController_;
+ delete iqRouter_;
+ delete iqChannel_;
+ delete stanzaChannel_;
+ }
+
+ JID self_, other_;
+ AvatarManager* avatarManager_ = nullptr;
+ ExtendedChatController* controller_ = nullptr;
+ ChatWindowFactory* chatWindowFactory_;
+ ClientBlockListManager* clientBlockListManager_;
+ EventController* eventController_ = nullptr;
+ EntityCapsProvider* entityCapsProvider_ = nullptr;
+ IQChannel* iqChannel_ = nullptr;
+ IQRouter* iqRouter_ = nullptr;
+ MockRepository* mocks_;
+ MockChatWindow* window_;
+ MUCRegistry* mucRegistry_ = nullptr;
+ NickResolver* nickResolver_ = nullptr;
+ PresenceOracle* presenceOracle_ = nullptr;
+ DummyStanzaChannel* stanzaChannel_ = nullptr;
+ TimerFactory* timerFactory_;
+ XMPPRosterImpl* xmppRoster_ = nullptr;
+ UIEventStream* uiEventStream_;
+ VCardManager* vCardManager_ = nullptr;
+ VCardMemoryStorage* vCardMemoryStorage_ = nullptr;
+ DummySettingsProvider* settings_;
+ HighlightManager* highlightManager_;
+ std::shared_ptr<ChatMessageParser> chatMessageParser_;
+ AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider_;
+ std::unique_ptr<Chattables> chattables_;
+
+};
+
+TEST_F(ChatControllerTest, testResendMessage) {
+ std::string msgBody("TestMsg");
+ stanzaChannel_->setStreamManagementEnabled(true);
+ window_->onSendMessageRequest(msgBody, false);
+ {
+ auto failedStanzas = controller_->getFailedStanzas();
+ auto unackedStanzas = controller_->getUnackedStanzas();
+ ASSERT_EQ(failedStanzas.size(), 0);
+ ASSERT_EQ(unackedStanzas.size(), 1);
+ }
+ //Disconnecting to fail the stanza
+ controller_->setOnline(false);
+ controller_->setOnline(true);
+ {
+ auto failedStanzas = controller_->getFailedStanzas();
+ auto unackedStanzas = controller_->getUnackedStanzas();
+ ASSERT_EQ(failedStanzas.size(), 1);
+ ASSERT_EQ(unackedStanzas.size(), 0);
+ }
+ window_->onResendMessageRequest("id");
+ {
+ auto failedStanzas = controller_->getFailedStanzas();
+ auto unackedStanzas = controller_->getUnackedStanzas();
+ ASSERT_EQ(failedStanzas.size(), 0);
+ ASSERT_EQ(unackedStanzas.size(), 1);
+ }
+}
diff --git a/Swift/Controllers/Chat/UnitTest/ChatListWindowChatTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatListWindowChatTest.cpp
new file mode 100644
index 0000000..9561e2b
--- /dev/null
+++ b/Swift/Controllers/Chat/UnitTest/ChatListWindowChatTest.cpp
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2017 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/version.hpp>
+
+#include <gtest/gtest.h>
+
+#include <Swiften/Base/ByteArray.h>
+#include <Swiften/StringCodecs/Base64.h>
+
+#include <Swift/Controllers/Chat/ChatListWindowChatBoostSerialize.h>
+#include <Swift/Controllers/UIInterfaces/ChatListWindow.h>
+
+using namespace Swift;
+
+class ChatListWindowChatTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {}
+ virtual void TearDown() {}
+
+ void testOptionalPasswordValue(const boost::optional<std::string>& value1, const std::string& value2) {
+ auto archiveLibraryVersion = boost::archive::BOOST_ARCHIVE_VERSION();
+ if (archiveLibraryVersion != Swift::BoostArchiveSkipVersion) {
+ EXPECT_EQ(value1.get_value_or(""), value2);
+ }
+ else {
+ EXPECT_EQ(value1.get_value_or(""), "");
+ }
+ }
+
+ std::string chatsSerialise(const std::vector<ChatListWindow::Chat>& chats) {
+ std::stringstream serializeStream;
+ boost::archive::text_oarchive oa(serializeStream);
+ oa & chats;
+ std::string serializedStr = Base64::encode(createByteArray(serializeStream.str()));
+ return serializedStr;
+ }
+
+ std::vector<ChatListWindow::Chat> chatsDeserialise(const std::string& b64chats) {
+ ByteArray debase64 = Base64::decode(b64chats);
+ std::vector<ChatListWindow::Chat> recentChats;
+ std::stringstream deserializeStream(std::string(reinterpret_cast<const char*>(vecptr(debase64)), debase64.size()));
+ try {
+ boost::archive::text_iarchive ia(deserializeStream);
+ ia >> recentChats;
+ }
+ catch (const boost::archive::archive_exception& e) {
+ EXPECT_TRUE(false) << "Archive Version:" << boost::archive::BOOST_ARCHIVE_VERSION() << " " << e.what() << std::endl;
+ recentChats.clear();
+ return recentChats;
+ }
+ recentChats.erase(std::remove(recentChats.begin(), recentChats.end(), ChatListWindow::Chat()), recentChats.end());
+ return recentChats;
+ }
+};
+
+TEST_F(ChatListWindowChatTest, testNormalSerialization) {
+ ChatListWindow::Chat chat1("swift@rooms.swift.im", "swift@rooms.swift.im", "Some text 0", 0, StatusShow::None, "", false, false, "Nick Name");
+ ChatListWindow::Chat chat2("testuser1@domain.com", "swift@rooms2.swift.im", "Some text 1", 0, StatusShow::None, "", false, false, "Nick Name", std::string("pass"));
+ ChatListWindow::Chat chat3("testuser2@domain.com", "room 2", "Some text 2", 0, StatusShow::None, "", true, false, "Nick Name");
+ ChatListWindow::Chat chat4("testuser3@domain.com", "room 3", "Some text 2", 0, StatusShow::None, "", true, false, "Nick Name", std::string("pass"));
+
+ std::map<std::string, JID> impromptuJIDs;
+ impromptuJIDs["testuser1@domain.com"] = "testuser1@domain.com";
+ impromptuJIDs["testuser2@domain.com"] = "testuser2@domain.com";
+ std::map<JID, std::string> inviteesNames;
+ inviteesNames["user1@domain.com"] = "user1@domain.com";
+
+ chat3.impromptuJIDs = impromptuJIDs;
+ chat3.inviteesNames = inviteesNames;
+ chat4.impromptuJIDs = impromptuJIDs;
+ chat4.inviteesNames = inviteesNames;
+
+ std::vector<ChatListWindow::Chat> chats;
+ chats.push_back(chat1);
+ chats.push_back(chat2);
+ chats.push_back(chat3);
+ chats.push_back(chat4);
+
+ auto base64 = chatsSerialise(chats);
+ ASSERT_TRUE(base64.size() > 0);
+ auto restoredChats = chatsDeserialise(base64);
+ ASSERT_EQ(restoredChats.size(), 4);
+
+ EXPECT_FALSE(restoredChats[0].isMUC);
+ EXPECT_EQ(restoredChats[0].jid, "swift@rooms.swift.im");
+ EXPECT_EQ(restoredChats[0].chatName, "swift@rooms.swift.im");
+ EXPECT_EQ(restoredChats[0].activity, "Some text 0");
+ EXPECT_EQ(restoredChats[0].nick, "Nick Name");
+ EXPECT_EQ(restoredChats[0].impromptuJIDs.size(), 0);
+ testOptionalPasswordValue(restoredChats[0].password, "");
+ EXPECT_EQ(restoredChats[0].inviteesNames.size(), 0);
+
+ EXPECT_FALSE(restoredChats[1].isMUC);
+ EXPECT_EQ(restoredChats[1].jid, "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[1].chatName, "swift@rooms2.swift.im");
+ EXPECT_EQ(restoredChats[1].activity, "Some text 1");
+ EXPECT_EQ(restoredChats[1].nick, "Nick Name");
+ EXPECT_EQ(restoredChats[1].impromptuJIDs.size(), 0);
+ testOptionalPasswordValue(restoredChats[1].password, "pass");
+ EXPECT_EQ(restoredChats[1].inviteesNames.size(), 0);
+
+ EXPECT_TRUE(restoredChats[2].isMUC);
+ EXPECT_EQ(restoredChats[2].jid, "testuser2@domain.com");
+ EXPECT_EQ(restoredChats[2].chatName, "room 2");
+ EXPECT_EQ(restoredChats[2].activity, "Some text 2");
+ EXPECT_EQ(restoredChats[2].nick, "Nick Name");
+ ASSERT_EQ(restoredChats[2].impromptuJIDs.size(), 2);
+ EXPECT_EQ(restoredChats[2].impromptuJIDs["testuser1@domain.com"], "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[2].impromptuJIDs["testuser2@domain.com"], "testuser2@domain.com");
+ testOptionalPasswordValue(restoredChats[2].password, "");
+ ASSERT_EQ(restoredChats[2].inviteesNames.size(), 1);
+ EXPECT_EQ(restoredChats[2].inviteesNames["user1@domain.com"], "user1@domain.com");
+
+ EXPECT_TRUE(restoredChats[3].isMUC);
+ EXPECT_EQ(restoredChats[3].jid, "testuser3@domain.com");
+ EXPECT_EQ(restoredChats[3].chatName, "room 3");
+ EXPECT_EQ(restoredChats[3].activity, "Some text 2");
+ EXPECT_EQ(restoredChats[3].nick, "Nick Name");
+ ASSERT_EQ(restoredChats[3].impromptuJIDs.size(), 2);
+ EXPECT_EQ(restoredChats[3].impromptuJIDs["testuser1@domain.com"], "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[3].impromptuJIDs["testuser2@domain.com"], "testuser2@domain.com");
+ testOptionalPasswordValue(restoredChats[3].password, "pass");
+ ASSERT_EQ(restoredChats[3].inviteesNames.size(), 1);
+ EXPECT_EQ(restoredChats[3].inviteesNames["user1@domain.com"], "user1@domain.com");
+}
+
+TEST_F(ChatListWindowChatTest, testVersionsSerialization) {
+ auto archiveLibraryVersion = boost::archive::BOOST_ARCHIVE_VERSION();
+ /*
+ The following strings are base64 serialised vectors with these Swift::ChatListWindow::Chat elements:
+
+ Chat1: Jid = "swift@rooms.swift.im", ChatName = "swift@rooms.swift.im", Activity = "Some text 0", isMUC = false, nick="Nick Name"
+ Chat2: Jid = "testuser1@domain.com", ChatName = "swift@rooms2.swift.im", Activity = "Some text 1", isMUC = false, nick="Nick Name", password = "pass"
+ Chat3: Jid = "testuser2@domain.com", ChatName = "room2", Activity = "Some text 2", isMUC = true, nick="Nick Name", impromptuJIDs, inviteesNames
+ Chat4: Jid = "testuser3@domain.com", ChatName = "room3", Activity = "Some text 2", isMUC = true, nick="Nick Name", impromptuJIDs, password = "pass", inviteesNames
+
+ impromptuJIDs = {("testuser1@domain.com","testuser1@domain.com"), ("testuser2@domain.com", "testuser2@domain.com")}
+ inviteesNames = {("user1@domain.com","user1@domain.com")}
+ */
+ std::string serializedChats_BoostArchiveV10_ClassVersion_0 = "MjIgc2VyaWFsaXphdGlvbjo6YXJjaGl2ZSAxMCAwIDAgNCAwIDAgMCAwIDAgMjAgc3dpZnRAcm9vbXMuc3dpZnQuaW0gMjAgc3dpZnRAcm9vbXMuc3dpZnQuaW0gMTEgU29tZSB0ZXh0IDAgMCA5IE5pY2sgTmFtZSAwIDAgMCAwIDIwIHRlc3R1c2VyMUBkb21haW4uY29tIDIxIHN3aWZ0QHJvb21zMi5zd2lmdC5pbSAxMSBTb21lIHRleHQgMSAwIDkgTmljayBOYW1lIDAgMCAyMCB0ZXN0dXNlcjJAZG9tYWluLmNvbSA2IHJvb20gMiAxMSBTb21lIHRleHQgMiAxIDkgTmljayBOYW1lIDIgMCAwIDAgMjAgdGVzdHVzZXIxQGRvbWFpbi5jb20gMjAgdGVzdHVzZXIxQGRvbWFpbi5jb20gMjAgdGVzdHVzZXIyQGRvbWFpbi5jb20gMjAgdGVzdHVzZXIyQGRvbWFpbi5jb20gMjAgdGVzdHVzZXIzQGRvbWFpbi5jb20gNiByb29tIDMgMTEgU29tZSB0ZXh0IDIgMSA5IE5pY2sgTmFtZSAyIDAgMjAgdGVzdHVzZXIxQGRvbWFpbi5jb20gMjAgdGVzdHVzZXIxQGRvbWFpbi5jb20gMjAgdGVzdHVzZXIyQGRvbWFpbi5jb20gMjAgdGVzdHVzZXIyQGRvbWFpbi5jb20=";
+ {
+ auto restoredChats = chatsDeserialise(serializedChats_BoostArchiveV10_ClassVersion_0);
+ if (archiveLibraryVersion == Swift::BoostArchiveSkipVersion) {
+ ASSERT_EQ(restoredChats.size(), 0);
+ }
+ else {
+ ASSERT_EQ(restoredChats.size(), 4);
+
+ EXPECT_FALSE(restoredChats[0].isMUC);
+ EXPECT_EQ(restoredChats[0].jid, "swift@rooms.swift.im");
+ EXPECT_EQ(restoredChats[0].chatName, "swift@rooms.swift.im");
+ EXPECT_EQ(restoredChats[0].activity, "Some text 0");
+ EXPECT_EQ(restoredChats[0].nick, "Nick Name");
+ EXPECT_EQ(restoredChats[0].impromptuJIDs.size(), 0);
+
+ EXPECT_FALSE(restoredChats[1].isMUC);
+ EXPECT_EQ(restoredChats[1].jid, "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[1].chatName, "swift@rooms2.swift.im");
+ EXPECT_EQ(restoredChats[1].activity, "Some text 1");
+ EXPECT_EQ(restoredChats[1].nick, "Nick Name");
+ EXPECT_EQ(restoredChats[1].impromptuJIDs.size(), 0);
+
+ EXPECT_TRUE(restoredChats[2].isMUC);
+ EXPECT_EQ(restoredChats[2].jid, "testuser2@domain.com");
+ EXPECT_EQ(restoredChats[2].chatName, "room 2");
+ EXPECT_EQ(restoredChats[2].activity, "Some text 2");
+ EXPECT_EQ(restoredChats[2].nick, "Nick Name");
+ ASSERT_EQ(restoredChats[2].impromptuJIDs.size(), 2);
+ EXPECT_EQ(restoredChats[2].impromptuJIDs["testuser1@domain.com"], "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[2].impromptuJIDs["testuser2@domain.com"], "testuser2@domain.com");
+
+ EXPECT_TRUE(restoredChats[3].isMUC);
+ EXPECT_EQ(restoredChats[3].jid, "testuser3@domain.com");
+ EXPECT_EQ(restoredChats[3].chatName, "room 3");
+ EXPECT_EQ(restoredChats[3].activity, "Some text 2");
+ EXPECT_EQ(restoredChats[3].nick, "Nick Name");
+ ASSERT_EQ(restoredChats[3].impromptuJIDs.size(), 2);
+ EXPECT_EQ(restoredChats[3].impromptuJIDs["testuser1@domain.com"], "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[3].impromptuJIDs["testuser2@domain.com"], "testuser2@domain.com");
+ }
+ }
+
+ std::string serializedChats_BoostArchiveV10_ClassVersion_1 = "MjIgc2VyaWFsaXphdGlvbjo6YXJjaGl2ZSAxMCAwIDAgNCAxIDAgMSAwIDAgMjAgc3dpZnRAcm9vbXMuc3dpZnQuaW0gMjAgc3dpZnRAcm9vbXMuc3dpZnQuaW0gMTEgU29tZSB0ZXh0IDAgMCA5IE5pY2sgTmFtZSAwIDAgMCAwIDAgMCAwIDIwIHRlc3R1c2VyMUBkb21haW4uY29tIDIxIHN3aWZ0QHJvb21zMi5zd2lmdC5pbSAxMSBTb21lIHRleHQgMSAwIDkgTmljayBOYW1lIDAgMCAxIDAgNCBwYXNzIDIwIHRlc3R1c2VyMkBkb21haW4uY29tIDYgcm9vbSAyIDExIFNvbWUgdGV4dCAyIDEgOSBOaWNrIE5hbWUgMiAwIDAgMCAyMCB0ZXN0dXNlcjFAZG9tYWluLmNvbSAyMCB0ZXN0dXNlcjFAZG9tYWluLmNvbSAyMCB0ZXN0dXNlcjJAZG9tYWluLmNvbSAyMCB0ZXN0dXNlcjJAZG9tYWluLmNvbSAwIDIwIHRlc3R1c2VyM0Bkb21haW4uY29tIDYgcm9vbSAzIDExIFNvbWUgdGV4dCAyIDEgOSBOaWNrIE5hbWUgMiAwIDIwIHRlc3R1c2VyMUBkb21haW4uY29tIDIwIHRlc3R1c2VyMUBkb21haW4uY29tIDIwIHRlc3R1c2VyMkBkb21haW4uY29tIDIwIHRlc3R1c2VyMkBkb21haW4uY29tIDEgMCA0IHBhc3M=";
+ {
+ auto restoredChats = chatsDeserialise(serializedChats_BoostArchiveV10_ClassVersion_1);
+ if (archiveLibraryVersion == Swift::BoostArchiveSkipVersion) {
+ ASSERT_EQ(restoredChats.size(), 0);
+ }
+ else {
+ ASSERT_EQ(restoredChats.size(), 4);
+
+ EXPECT_FALSE(restoredChats[0].isMUC);
+ EXPECT_EQ(restoredChats[0].jid, "swift@rooms.swift.im");
+ EXPECT_EQ(restoredChats[0].chatName, "swift@rooms.swift.im");
+ EXPECT_EQ(restoredChats[0].activity, "Some text 0");
+ EXPECT_EQ(restoredChats[0].nick, "Nick Name");
+ EXPECT_EQ(restoredChats[0].impromptuJIDs.size(), 0);
+ EXPECT_EQ(restoredChats[0].password.get_value_or(""), "");
+
+ EXPECT_FALSE(restoredChats[1].isMUC);
+ EXPECT_EQ(restoredChats[1].jid, "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[1].chatName, "swift@rooms2.swift.im");
+ EXPECT_EQ(restoredChats[1].activity, "Some text 1");
+ EXPECT_EQ(restoredChats[1].nick, "Nick Name");
+ EXPECT_EQ(restoredChats[1].impromptuJIDs.size(), 0);
+ EXPECT_EQ(restoredChats[1].password.get_value_or(""), "pass");
+
+ EXPECT_TRUE(restoredChats[2].isMUC);
+ EXPECT_EQ(restoredChats[2].jid, "testuser2@domain.com");
+ EXPECT_EQ(restoredChats[2].chatName, "room 2");
+ EXPECT_EQ(restoredChats[2].activity, "Some text 2");
+ EXPECT_EQ(restoredChats[2].nick, "Nick Name");
+ ASSERT_EQ(restoredChats[2].impromptuJIDs.size(), 2);
+ EXPECT_EQ(restoredChats[2].impromptuJIDs["testuser1@domain.com"], "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[2].impromptuJIDs["testuser2@domain.com"], "testuser2@domain.com");
+ EXPECT_EQ(restoredChats[2].password.get_value_or(""), "");
+
+ EXPECT_TRUE(restoredChats[3].isMUC);
+ EXPECT_EQ(restoredChats[3].jid, "testuser3@domain.com");
+ EXPECT_EQ(restoredChats[3].chatName, "room 3");
+ EXPECT_EQ(restoredChats[3].activity, "Some text 2");
+ EXPECT_EQ(restoredChats[3].nick, "Nick Name");
+ ASSERT_EQ(restoredChats[3].impromptuJIDs.size(), 2);
+ EXPECT_EQ(restoredChats[3].impromptuJIDs["testuser1@domain.com"], "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[3].impromptuJIDs["testuser2@domain.com"], "testuser2@domain.com");
+ EXPECT_EQ(restoredChats[3].password.get_value_or(""), "pass");
+ }
+ }
+
+ std::string serializedChats_BoostArchiveV10_ClassVersion_2 = "MjIgc2VyaWFsaXphdGlvbjo6YXJjaGl2ZSAxMCAwIDAgNCAyIDAgMiAwIDAgMjAgc3dpZnRAcm9vbXMuc3dpZnQuaW0gMjAgc3dpZnRAcm9vbXMuc3dpZnQuaW0gMTEgU29tZSB0ZXh0IDAgMCA5IE5pY2sgTmFtZSAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMjAgdGVzdHVzZXIxQGRvbWFpbi5jb20gMjEgc3dpZnRAcm9vbXMyLnN3aWZ0LmltIDExIFNvbWUgdGV4dCAxIDAgOSBOaWNrIE5hbWUgMCAwIDEgMCA0IHBhc3MgMCAwIDIwIHRlc3R1c2VyMkBkb21haW4uY29tIDYgcm9vbSAyIDExIFNvbWUgdGV4dCAyIDEgOSBOaWNrIE5hbWUgMiAwIDAgMCAyMCB0ZXN0dXNlcjFAZG9tYWluLmNvbSAyMCB0ZXN0dXNlcjFAZG9tYWluLmNvbSAyMCB0ZXN0dXNlcjJAZG9tYWluLmNvbSAyMCB0ZXN0dXNlcjJAZG9tYWluLmNvbSAwIDEgMCAwIDAgMTYgdXNlcjFAZG9tYWluLmNvbSAxNiB1c2VyMUBkb21haW4uY29tIDIwIHRlc3R1c2VyM0Bkb21haW4uY29tIDYgcm9vbSAzIDExIFNvbWUgdGV4dCAyIDEgOSBOaWNrIE5hbWUgMiAwIDIwIHRlc3R1c2VyMUBkb21haW4uY29tIDIwIHRlc3R1c2VyMUBkb21haW4uY29tIDIwIHRlc3R1c2VyMkBkb21haW4uY29tIDIwIHRlc3R1c2VyMkBkb21haW4uY29tIDEgMCA0IHBhc3MgMSAwIDE2IHVzZXIxQGRvbWFpbi5jb20gMTYgdXNlcjFAZG9tYWluLmNvbQ==";
+ {
+ auto restoredChats = chatsDeserialise(serializedChats_BoostArchiveV10_ClassVersion_2);
+ if (archiveLibraryVersion == Swift::BoostArchiveSkipVersion) {
+ ASSERT_EQ(restoredChats.size(), 0);
+ }
+ else {
+ ASSERT_EQ(restoredChats.size(), 4);
+
+ EXPECT_FALSE(restoredChats[0].isMUC);
+ EXPECT_EQ(restoredChats[0].jid, "swift@rooms.swift.im");
+ EXPECT_EQ(restoredChats[0].chatName, "swift@rooms.swift.im");
+ EXPECT_EQ(restoredChats[0].activity, "Some text 0");
+ EXPECT_EQ(restoredChats[0].nick, "Nick Name");
+ EXPECT_EQ(restoredChats[0].impromptuJIDs.size(), 0);
+ EXPECT_EQ(restoredChats[0].password.get_value_or(""), "");
+ EXPECT_EQ(restoredChats[0].inviteesNames.size(), 0);
+
+ EXPECT_FALSE(restoredChats[1].isMUC);
+ EXPECT_EQ(restoredChats[1].jid, "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[1].chatName, "swift@rooms2.swift.im");
+ EXPECT_EQ(restoredChats[1].activity, "Some text 1");
+ EXPECT_EQ(restoredChats[1].nick, "Nick Name");
+ EXPECT_EQ(restoredChats[1].impromptuJIDs.size(), 0);
+ EXPECT_EQ(restoredChats[1].password.get_value_or(""), "pass");
+ EXPECT_EQ(restoredChats[1].inviteesNames.size(), 0);
+
+ EXPECT_TRUE(restoredChats[2].isMUC);
+ EXPECT_EQ(restoredChats[2].jid, "testuser2@domain.com");
+ EXPECT_EQ(restoredChats[2].chatName, "room 2");
+ EXPECT_EQ(restoredChats[2].activity, "Some text 2");
+ EXPECT_EQ(restoredChats[2].nick, "Nick Name");
+ ASSERT_EQ(restoredChats[2].impromptuJIDs.size(), 2);
+ EXPECT_EQ(restoredChats[2].impromptuJIDs["testuser1@domain.com"], "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[2].impromptuJIDs["testuser2@domain.com"], "testuser2@domain.com");
+ EXPECT_EQ(restoredChats[2].password.get_value_or(""), "");
+ ASSERT_EQ(restoredChats[2].inviteesNames.size(), 1);
+ EXPECT_EQ(restoredChats[2].inviteesNames["user1@domain.com"], "user1@domain.com");
+
+ EXPECT_TRUE(restoredChats[3].isMUC);
+ EXPECT_EQ(restoredChats[3].jid, "testuser3@domain.com");
+ EXPECT_EQ(restoredChats[3].chatName, "room 3");
+ EXPECT_EQ(restoredChats[3].activity, "Some text 2");
+ EXPECT_EQ(restoredChats[3].nick, "Nick Name");
+ ASSERT_EQ(restoredChats[3].impromptuJIDs.size(), 2);
+ EXPECT_EQ(restoredChats[3].impromptuJIDs["testuser1@domain.com"], "testuser1@domain.com");
+ EXPECT_EQ(restoredChats[3].impromptuJIDs["testuser2@domain.com"], "testuser2@domain.com");
+ EXPECT_EQ(restoredChats[3].password.get_value_or(""), "pass");
+ ASSERT_EQ(restoredChats[3].inviteesNames.size(), 1);
+ EXPECT_EQ(restoredChats[3].inviteesNames["user1@domain.com"], "user1@domain.com");
+ }
+ }
+}
+
diff --git a/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp
index 44d7834..163a38a 100644
--- a/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/ChatMessageParserTest.cpp
@@ -1,74 +1,292 @@
/*
- * Copyright (c) 2013 Kevin Smith
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2013-2017 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
-#include <cppunit/extensions/HelperMacros.h>
-#include <cppunit/extensions/TestFactoryRegistry.h>
-#include <hippomocks.h>
+#include <gtest/gtest.h>
#include <Swift/Controllers/Chat/ChatMessageParser.h>
+#include <Swift/Controllers/Highlighting/HighlightConfiguration.h>
+#include <Swift/Controllers/Highlighting/HighlightManager.h>
+#include <Swift/Controllers/Settings/DummySettingsProvider.h>
using namespace Swift;
-class ChatMessageParserTest : public CppUnit::TestFixture {
- CPPUNIT_TEST_SUITE(ChatMessageParserTest);
- CPPUNIT_TEST(testFullBody);
- CPPUNIT_TEST_SUITE_END();
-
-public:
- void setUp() {
- smile1_ = ":)";
- smile1Path_ = "/blah/smile1.png";
- smile2_ = ":(";
- smile2Path_ = "/blah/smile2.jpg";
- emoticons_[smile1_] = smile1Path_;
- emoticons_[smile2_] = smile2Path_;
- }
-
- void tearDown() {
- emoticons_.clear();
- }
-
- void assertText(const ChatWindow::ChatMessage& result, size_t index, const std::string& text) {
- boost::shared_ptr<ChatWindow::ChatTextMessagePart> part = boost::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(result.getParts()[index]);
- CPPUNIT_ASSERT_EQUAL(text, part->text);
- }
-
- void assertEmoticon(const ChatWindow::ChatMessage& result, size_t index, const std::string& text, const std::string& path) {
- boost::shared_ptr<ChatWindow::ChatEmoticonMessagePart> part = boost::dynamic_pointer_cast<ChatWindow::ChatEmoticonMessagePart>(result.getParts()[index]);
- CPPUNIT_ASSERT_EQUAL(text, part->alternativeText);
- CPPUNIT_ASSERT_EQUAL(path, part->imagePath);
- }
-
- void assertURL(const ChatWindow::ChatMessage& result, size_t index, const std::string& text) {
- boost::shared_ptr<ChatWindow::ChatURIMessagePart> part = boost::dynamic_pointer_cast<ChatWindow::ChatURIMessagePart>(result.getParts()[index]);
- CPPUNIT_ASSERT_EQUAL(text, part->target);
- }
-
- void testFullBody() {
- ChatMessageParser testling(emoticons_);
- ChatWindow::ChatMessage result = testling.parseMessageBody(":) shiny :( :) http://wonderland.lit/blah http://denmark.lit boom boom");
- assertEmoticon(result, 0, smile1_, smile1Path_);
- assertText(result, 1, " shiny ");
- assertEmoticon(result, 2, smile2_, smile2Path_);
- assertText(result, 3, " ");
- assertEmoticon(result, 4, smile1_, smile1Path_);
- assertText(result, 5, " ");
- assertURL(result, 6, "http://wonderland.lit/blah");
- assertText(result, 7, " ");
- assertURL(result, 8, "http://denmark.lit");
- assertText(result, 9, " boom boom");
- }
-
-private:
- std::map<std::string, std::string> emoticons_;
- std::string smile1_;
- std::string smile1Path_;
- std::string smile2_;
- std::string smile2Path_;
+// Common test state
+class ChatMessageParserTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
+ smile1_ = ":)";
+ smile1Path_ = "/blah/smile1.png";
+ smile2_ = ":(";
+ smile2Path_ = "/blah/smile2.jpg";
+ emoticons_[smile1_] = smile1Path_;
+ emoticons_[smile2_] = smile2Path_;
+ }
+
+ virtual void TearDown() {
+ emoticons_.clear();
+ }
+
+ static void assertText(const ChatWindow::ChatMessage& result, size_t index, const std::string& text) {
+ ASSERT_LT(index, result.getParts().size());
+ std::shared_ptr<ChatWindow::ChatTextMessagePart> part = std::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(result.getParts()[index]);
+ ASSERT_EQ(text, part->text);
+ }
+
+ static void assertEmoticon(const ChatWindow::ChatMessage& result, size_t index, const std::string& text, const std::string& path) {
+ ASSERT_LT(index, result.getParts().size());
+ std::shared_ptr<ChatWindow::ChatEmoticonMessagePart> part = std::dynamic_pointer_cast<ChatWindow::ChatEmoticonMessagePart>(result.getParts()[index]);
+ ASSERT_NE(nullptr, part);
+ ASSERT_EQ(text, part->alternativeText);
+ ASSERT_EQ(path, part->imagePath);
+ }
+
+ static void assertURL(const ChatWindow::ChatMessage& result, size_t index, const std::string& text) {
+ ASSERT_LT(index, result.getParts().size());
+ std::shared_ptr<ChatWindow::ChatURIMessagePart> part = std::dynamic_pointer_cast<ChatWindow::ChatURIMessagePart>(result.getParts()[index]);
+ ASSERT_EQ(text, part->target);
+ }
+
+ void assertHighlight(const ChatWindow::ChatMessage& result, size_t index, const std::string& text, const HighlightAction& action) {
+ ASSERT_LT(index, result.getParts().size());
+ std::shared_ptr<ChatWindow::ChatHighlightingMessagePart> part = std::dynamic_pointer_cast<ChatWindow::ChatHighlightingMessagePart>(result.getParts()[index]);
+ ASSERT_EQ(std::string(text), part->text);
+ ASSERT_EQ(action, part->action);
+ }
+
+ static const std::shared_ptr<HighlightConfiguration> highlightConfigFromKeyword(const std::string& keyword, bool matchCase) {
+ std::shared_ptr<HighlightConfiguration> config = std::make_shared<HighlightConfiguration>();
+ HighlightConfiguration::KeywordHightlight keywordHighlight;
+ keywordHighlight.keyword = keyword;
+ keywordHighlight.matchCaseSensitive = matchCase;
+ keywordHighlight.action.setFrontColor(std::string("#121212"));
+ config->keywordHighlights.push_back(keywordHighlight);
+ return config;
+ }
+
+ static const std::shared_ptr<HighlightConfiguration> mergeHighlightConfig(const std::shared_ptr<HighlightConfiguration>& configA, const std::shared_ptr<HighlightConfiguration>& configB) {
+ std::shared_ptr<HighlightConfiguration> config = std::make_shared<HighlightConfiguration>();
+ config->keywordHighlights.insert(config->keywordHighlights.end(), configA->keywordHighlights.begin(), configA->keywordHighlights.end());
+ config->keywordHighlights.insert(config->keywordHighlights.end(), configB->keywordHighlights.begin(), configB->keywordHighlights.end());
+ return config;
+ }
+
+ std::map<std::string, std::string> emoticons_;
+ std::string smile1_;
+ std::string smile1Path_;
+ std::string smile2_;
+ std::string smile2Path_;
};
-CPPUNIT_TEST_SUITE_REGISTRATION(ChatMessageParserTest);
+TEST_F(ChatMessageParserTest, testNoHighlightingWithEmtpyConfiguration) {
+ const std::string no_special_message = "a message with no special content";
+ ChatMessageParser testling(emoticons_, std::make_shared<HighlightConfiguration>());
+ auto result = testling.parseMessageBody(no_special_message);
+ assertText(result, 0, no_special_message);
+}
+
+TEST_F(ChatMessageParserTest, testSimpleHighlightAndEmojiAndUrlParsing) {
+ auto highlightConfig = highlightConfigFromKeyword("trigger", false);
+ auto testling = ChatMessageParser(emoticons_, highlightConfig);
+ auto result = testling.parseMessageBody(":) shiny :( trigger :) http://wonderland.lit/blah http://denmark.lit boom boom");
+ assertEmoticon(result, 0, smile1_, smile1Path_);
+ assertText(result, 1, " shiny ");
+ assertEmoticon(result, 2, smile2_, smile2Path_);
+ assertText(result, 3, " ");
+ assertHighlight(result, 4, "trigger", highlightConfig->keywordHighlights[0].action);
+ assertText(result, 5, " ");
+ assertEmoticon(result, 6, smile1_, smile1Path_);
+ assertText(result, 7, " ");
+ assertURL(result, 8, "http://wonderland.lit/blah");
+ assertText(result, 9, " ");
+ assertURL(result, 10, "http://denmark.lit");
+ assertText(result, 11, " boom boom");
+}
+
+TEST_F(ChatMessageParserTest, testNoKeywordHighlightAsPartOfLongerWords) {
+ auto testling = ChatMessageParser(emoticons_, highlightConfigFromKeyword("trigger", false));
+ auto result = testling.parseMessageBody("testtriggermessage");
+ assertText(result, 0, "testtriggermessage");
+}
+
+TEST_F(ChatMessageParserTest, testCaseInsensitiveKeyordHighlight) {
+ auto config = highlightConfigFromKeyword("trigger", true);
+ auto testling = ChatMessageParser(emoticons_, config);
+ auto result = testling.parseMessageBody("TrIgGeR");
+ assertText(result, 0, "TrIgGeR");
+
+ testling = ChatMessageParser(emoticons_, highlightConfigFromKeyword("trigger", false));
+ result = testling.parseMessageBody("TrIgGeR");
+ assertHighlight(result, 0, "TrIgGeR", config->keywordHighlights[0].action);
+}
+
+TEST_F(ChatMessageParserTest, testMultipleKeywordHighlights) {
+ auto config = mergeHighlightConfig(highlightConfigFromKeyword("one", false), highlightConfigFromKeyword("three", false));
+ auto testling = ChatMessageParser(emoticons_, config);
+ auto result = testling.parseMessageBody("zero one two three");
+ assertText(result, 0, "zero ");
+ assertHighlight(result, 1, "one", config->keywordHighlights[0].action);
+ assertText(result, 2, " two ");
+ assertHighlight(result, 3, "three", config->keywordHighlights[0].action);
+}
+
+TEST_F(ChatMessageParserTest, testMultipleCaseInsensitiveKeywordHighlights) {
+ auto config = mergeHighlightConfig(highlightConfigFromKeyword("one", false), highlightConfigFromKeyword("three", false));
+ auto testling = ChatMessageParser(emoticons_, config);
+ auto result = testling.parseMessageBody("zero oNe two tHrEe");
+ assertText(result, 0, "zero ");
+ assertHighlight(result, 1, "oNe", config->keywordHighlights[0].action);
+ assertText(result, 2, " two ");
+ assertHighlight(result, 3, "tHrEe", config->keywordHighlights[0].action);
+}
+
+TEST_F(ChatMessageParserTest, testMultipleCaseSensitiveKeywordHighlights) {
+ auto config = mergeHighlightConfig(highlightConfigFromKeyword("one", false), highlightConfigFromKeyword("three", true));
+ auto testling = ChatMessageParser(emoticons_, config);
+ auto result = testling.parseMessageBody("zero oNe two tHrEe");
+ assertText(result, 0, "zero ");
+ assertHighlight(result, 1, "oNe", config->keywordHighlights[0].action);
+ assertText(result, 2, " two tHrEe");
+
+ config = mergeHighlightConfig(highlightConfigFromKeyword("one", true), highlightConfigFromKeyword("three", false));
+ testling = ChatMessageParser(emoticons_, config);
+ result = testling.parseMessageBody("zero oNe two tHrEe");
+ assertText(result, 0, "zero oNe two ");
+ assertHighlight(result, 1, "tHrEe", config->keywordHighlights[0].action);
+}
+
+TEST_F(ChatMessageParserTest, testOneEmoticon) {
+ auto testling = ChatMessageParser(emoticons_, std::make_shared<HighlightConfiguration>());
+ auto result = testling.parseMessageBody(" :) ");
+ assertText(result, 0, " ");
+ assertEmoticon(result, 1, smile1_, smile1Path_);
+ assertText(result, 2, " ");
+}
+
+TEST_F(ChatMessageParserTest, testBareEmoticon) {
+ auto testling = ChatMessageParser(emoticons_, std::make_shared<HighlightConfiguration>());
+ auto result = testling.parseMessageBody(":)");
+ assertEmoticon(result, 0, smile1_, smile1Path_);
+}
+
+TEST_F(ChatMessageParserTest, testHiddenEmoticon) {
+ auto testling = ChatMessageParser(emoticons_, std::make_shared<HighlightConfiguration>());
+ auto result = testling.parseMessageBody("b:)a");
+ assertText(result, 0, "b:)a");
+}
+
+TEST_F(ChatMessageParserTest, testEndlineEmoticon) {
+ auto testling = ChatMessageParser(emoticons_, std::make_shared<HighlightConfiguration>());
+ auto result = testling.parseMessageBody("Lazy:)");
+ assertText(result, 0, "Lazy");
+ assertEmoticon(result, 1, smile1_, smile1Path_);
+}
+
+TEST_F(ChatMessageParserTest, testBoundedEmoticons) {
+ auto testling = ChatMessageParser(emoticons_, std::make_shared<HighlightConfiguration>());
+ auto result = testling.parseMessageBody(":)Lazy:(");
+ assertEmoticon(result, 0, smile1_, smile1Path_);
+ assertText(result, 1, "Lazy");
+ assertEmoticon(result, 2, smile2_, smile2Path_);
+}
+
+TEST_F(ChatMessageParserTest, testEmoticonParenthesis) {
+ auto testling = ChatMessageParser(emoticons_, std::make_shared<HighlightConfiguration>());
+ auto result = testling.parseMessageBody("(Like this :))");
+ assertText(result, 0, "(Like this ");
+ assertEmoticon(result, 1, smile1_, smile1Path_);
+ assertText(result, 2, ")");
+}
+
+TEST_F(ChatMessageParserTest, testSenderAndKeywordHighlighting) {
+ auto config = std::make_shared<HighlightConfiguration>();
+ auto contactHighlight = HighlightConfiguration::ContactHighlight();
+ contactHighlight.action.setFrontColor(std::string("#f0f0f0"));
+ contactHighlight.action.setBackColor(std::string("#0f0f0f"));
+ contactHighlight.name = "Romeo";
+ config->contactHighlights.push_back(contactHighlight);
+ auto keywordHighlight = HighlightConfiguration::KeywordHightlight();
+ keywordHighlight.action.setFrontColor(std::string("#abcdef"));
+ keywordHighlight.action.setBackColor(std::string("#fedcba"));
+ keywordHighlight.keyword = "XMPP";
+ config->keywordHighlights.push_back(keywordHighlight);
+ auto testling = ChatMessageParser(emoticons_, config);
+ auto result = testling.parseMessageBody("Heard any news about xmpp recently?", "Romeo");
+ assertText(result, 0, "Heard any news about ");
+ assertHighlight(result, 1, "xmpp", keywordHighlight.action);
+ assertText(result, 2, " recently?");
+ ASSERT_EQ(contactHighlight.action, result.getHighlightActionSender());
+ ASSERT_EQ(HighlightAction(), result.getHighlightActionOwnMention());
+}
+
+TEST_F(ChatMessageParserTest, testKeywordWithEmptyActionIsIgnored) {
+ auto config = std::make_shared<HighlightConfiguration>();
+ auto keywordHighlight = HighlightConfiguration::KeywordHightlight();
+ keywordHighlight.keyword = "XMPP";
+ config->keywordHighlights.push_back(keywordHighlight);
+ auto testling = ChatMessageParser(emoticons_, config);
+ auto result = testling.parseMessageBody("Heard any news about xmpp recently?", "Romeo");
+ assertText(result, 0, "Heard any news about xmpp recently?");
+ ASSERT_EQ(HighlightAction(), result.getHighlightActionOwnMention());
+}
+
+TEST_F(ChatMessageParserTest, testMeMessageAndOwnMention) {
+ auto config = std::make_shared<HighlightConfiguration>();
+ config->ownMentionAction.setFrontColor(std::string("#f0f0f0"));
+ config->ownMentionAction.setBackColor(std::string("#0f0f0f"));
+ config->ownMentionAction.setSoundFilePath(std::string("someSoundFile.wav"));
+ auto ownMentionActionForPart = config->ownMentionAction;
+ ownMentionActionForPart.setSoundFilePath(boost::optional<std::string>());
+ auto testling = ChatMessageParser(emoticons_, config);
+ testling.setNick("Juliet");
+ auto result = testling.parseMessageBody("/me wonders when Juliet is coming?", "Romeo");
+ assertText(result, 0, "wonders when ");
+ assertHighlight(result, 1, "Juliet", ownMentionActionForPart);
+ assertText(result, 2, " is coming?");
+ ASSERT_EQ(true, result.isMeCommand());
+ ASSERT_EQ(config->ownMentionAction, result.getHighlightActionOwnMention());
+}
+
+TEST_F(ChatMessageParserTest, testSoundAndNotificationOnDirectMessage) {
+ auto defaultConfiguration = std::make_shared<HighlightConfiguration>();
+ defaultConfiguration->playSoundOnIncomingDirectMessages = true;
+ defaultConfiguration->showNotificationOnIncomingDirectMessages = true;
+ defaultConfiguration->ownMentionAction.setFrontColor(std::string("black"));
+ defaultConfiguration->ownMentionAction.setBackColor(std::string("yellow"));
+ defaultConfiguration->ownMentionAction.setSoundFilePath(std::string(""));
+ defaultConfiguration->ownMentionAction.setSystemNotificationEnabled(true);
+
+ auto testling = ChatMessageParser(emoticons_, defaultConfiguration, ChatMessageParser::Mode::Chat);
+ auto result = testling.parseMessageBody("I wonder when Juliet is coming?", "Romeo");
+
+ ASSERT_EQ(std::string(""), result.getHighlightActionDirectMessage().getSoundFilePath().get_value_or(std::string("somethingElse")));
+ ASSERT_EQ(true, result.getHighlightActionDirectMessage().isSystemNotificationEnabled());
+ ASSERT_EQ(HighlightAction(), result.getHighlightActionOwnMention());
+}
+
+TEST_F(ChatMessageParserTest, testWithDefaultConfiguration) {
+ DummySettingsProvider settings;
+ HighlightManager manager(&settings);
+ manager.resetToDefaultConfiguration();
+ auto testling = ChatMessageParser(emoticons_, manager.getConfiguration(), ChatMessageParser::Mode::GroupChat);
+ testling.setNick("Juliet");
+ auto result = testling.parseMessageBody("Hello, how is it going?", "Romeo");
+ assertText(result, 0, "Hello, how is it going?");
+ ASSERT_EQ(HighlightAction(), result.getHighlightActionOwnMention());
+ ASSERT_EQ(HighlightAction(), result.getHighlightActionDirectMessage());
+ ASSERT_EQ(HighlightAction(), result.getHighlightActionGroupMessage());
+ ASSERT_EQ(HighlightAction(), result.getHighlightActionSender());
+ result = testling.parseMessageBody("Juliet, seen the new interface design?", "Romeo");
+ auto mentionKeywordAction = manager.getConfiguration()->ownMentionAction;
+ mentionKeywordAction.setSoundFilePath(boost::optional<std::string>());
+ mentionKeywordAction.setSystemNotificationEnabled(false);
+ assertHighlight(result, 0, "Juliet", mentionKeywordAction);
+ assertText(result, 1, ", seen the new interface design?");
+ ASSERT_EQ(manager.getConfiguration()->ownMentionAction, result.getHighlightActionOwnMention());
+ ASSERT_EQ(HighlightAction(), result.getHighlightActionDirectMessage());
+ ASSERT_EQ(HighlightAction(), result.getHighlightActionGroupMessage());
+ ASSERT_EQ(HighlightAction(), result.getHighlightActionSender());
+}
diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
index f5a3003..954dd2f 100644
--- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
@@ -1,495 +1,1904 @@
/*
- * Copyright (c) 2010-2012 Kevin Smith
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010-2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
+#include <map>
+#include <set>
+
+#include <boost/bind.hpp>
+
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <hippomocks.h>
-#include <boost/bind.hpp>
+#include <Swiften/Avatars/AvatarMemoryStorage.h>
+#include <Swiften/Avatars/NullAvatarManager.h>
+#include <Swiften/Base/Algorithm.h>
+#include <Swiften/Base/Log.h>
+#include <Swiften/Base/LogSerializers.h>
+#include <Swiften/Client/Client.h>
+#include <Swiften/Client/ClientBlockListManager.h>
+#include <Swiften/Client/DummyStanzaChannel.h>
+#include <Swiften/Client/NickResolver.h>
+#include <Swiften/Crypto/CryptoProvider.h>
+#include <Swiften/Crypto/PlatformCryptoProvider.h>
+#include <Swiften/Disco/DummyEntityCapsProvider.h>
+#include <Swiften/Elements/CarbonsReceived.h>
+#include <Swiften/Elements/CarbonsSent.h>
+#include <Swiften/Elements/DeliveryReceipt.h>
+#include <Swiften/Elements/DeliveryReceiptRequest.h>
+#include <Swiften/Elements/Forwarded.h>
+#include <Swiften/Elements/MUCInvitationPayload.h>
+#include <Swiften/Elements/MUCUserPayload.h>
+#include <Swiften/Elements/PrivateStorage.h>
+#include <Swiften/Elements/Storage.h>
+#include <Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h>
+#include <Swiften/Jingle/JingleSessionManager.h>
+#include <Swiften/MUC/MUCManager.h>
+#include <Swiften/MUC/UnitTest/MockMUC.h>
+#include <Swiften/MUC/MUCBookmarkManager.h>
+#include <Swiften/Network/DummyTimerFactory.h>
+#include <Swiften/Presence/DirectedPresenceSender.h>
+#include <Swiften/Presence/PresenceOracle.h>
+#include <Swiften/Presence/StanzaChannelPresenceSender.h>
+#include <Swiften/Queries/DummyIQChannel.h>
+#include <Swiften/Roster/XMPPRosterImpl.h>
+#include <Swiften/VCards/VCardManager.h>
+#include <Swiften/VCards/VCardMemoryStorage.h>
+#include <Swiften/Whiteboard/WhiteboardSessionManager.h>
+#include <Swift/Controllers/Chat/ChatController.h>
#include <Swift/Controllers/Chat/ChatsManager.h>
-
+#include <Swift/Controllers/Chat/Chattables.h>
+#include <Swift/Controllers/Chat/MUCController.h>
#include <Swift/Controllers/Chat/UnitTest/MockChatListWindow.h>
-#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
+#include <Swift/Controllers/EventNotifier.h>
+#include <Swift/Controllers/FileTransfer/FileTransferOverview.h>
+#include <Swift/Controllers/ProfileSettingsProvider.h>
+#include <Swift/Controllers/SettingConstants.h>
#include <Swift/Controllers/Settings/DummySettingsProvider.h>
-#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
+#include <Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h>
+#include <Swift/Controllers/UIEvents/CreateImpromptuMUCUIEvent.h>
+#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIInterfaces/ChatListWindowFactory.h>
-#include <Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h>
-#include <Swiften/Client/Client.h>
-#include <Swiften/Disco/EntityCapsManager.h>
-#include <Swiften/Disco/CapsProvider.h>
-#include <Swiften/MUC/MUCManager.h>
-#include <Swift/Controllers/Chat/ChatController.h>
-#include <Swift/Controllers/XMPPEvents/EventController.h>
-#include <Swift/Controllers/Chat/MUCController.h>
-#include <Swiften/Presence/StanzaChannelPresenceSender.h>
-#include <Swiften/Avatars/NullAvatarManager.h>
-#include <Swiften/Avatars/AvatarMemoryStorage.h>
-#include <Swiften/VCards/VCardManager.h>
-#include <Swiften/VCards/VCardMemoryStorage.h>
-#include <Swiften/Client/NickResolver.h>
-#include <Swiften/Presence/DirectedPresenceSender.h>
-#include <Swiften/Roster/XMPPRosterImpl.h>
+#include <Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h>
#include <Swift/Controllers/UnitTest/MockChatWindow.h>
-#include <Swiften/Client/DummyStanzaChannel.h>
-#include <Swiften/Queries/DummyIQChannel.h>
-#include <Swiften/Presence/PresenceOracle.h>
-#include <Swiften/Jingle/JingleSessionManager.h>
-#include <Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h>
-#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
-#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
-#include <Swift/Controllers/UIEvents/UIEventStream.h>
-#include <Swift/Controllers/ProfileSettingsProvider.h>
-#include <Swift/Controllers/FileTransfer/FileTransferOverview.h>
-#include <Swiften/Elements/DeliveryReceiptRequest.h>
-#include <Swiften/Elements/DeliveryReceipt.h>
-#include <Swiften/Base/Algorithm.h>
-#include <Swift/Controllers/SettingConstants.h>
#include <Swift/Controllers/WhiteboardManager.h>
-#include <Swiften/Whiteboard/WhiteboardSessionManager.h>
-#include <Swiften/Client/ClientBlockListManager.h>
+#include <Swift/Controllers/XMPPEvents/EventController.h>
+
+#include <SwifTools/Notifier/Notifier.h>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
using namespace Swift;
-class DummyCapsProvider : public CapsProvider {
- DiscoInfo::ref getCaps(const std::string&) const {return DiscoInfo::ref(new DiscoInfo());}
+class DummyNotifier : public Notifier {
+ public:
+ virtual void showMessage(
+ Type type,
+ const std::string& subject,
+ const std::string& description,
+ const boost::filesystem::path& picture,
+ boost::function<void()> callback) {
+ notifications.push_back({type, subject, description, picture, callback});
+ }
+
+ /** Remove any pending callbacks. */
+ virtual void purgeCallbacks() {
+
+ }
+
+ public:
+ struct Notification {
+ Type type;
+ std::string subject;
+ std::string description;
+ boost::filesystem::path picture;
+ boost::function<void()> callback;
+ };
+
+ public:
+ std::vector<Notification> notifications;
+};
+
+class ExtendedChatsManager : public ChatsManager {
+public:
+ ExtendedChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, JoinMUCWindowFactory* joinMUCWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, ProfileSettingsProvider* profileSettings, FileTransferOverview* ftOverview, XMPPRoster* roster, bool eagleMode, SettingsProvider* settings, HistoryController* historyController_, WhiteboardManager* whiteboardManager, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, const std::map<std::string, std::string>& emoticons, VCardManager* vcardManager, Chattables& chattables) :
+ ChatsManager(jid, stanzaChannel, iqRouter, eventController, chatWindowFactory, joinMUCWindowFactory, nickResolver, presenceOracle, presenceSender, uiEventStream, chatListWindowFactory, useDelayForLatency, timerFactory, mucRegistry, entityCapsProvider, mucManager, mucSearchWindowFactory, profileSettings, ftOverview, roster, eagleMode, settings, historyController_, whiteboardManager, highlightManager, clientBlockListManager, emoticons, vcardManager, chattables) {
+ }
+ MUCBookmarkManager* getBookmarkManager() {
+ return mucBookmarkManager_;
+ }
};
+
class ChatsManagerTest : public CppUnit::TestFixture {
- CPPUNIT_TEST_SUITE(ChatsManagerTest);
- CPPUNIT_TEST(testFirstOpenWindowIncoming);
- CPPUNIT_TEST(testSecondOpenWindowIncoming);
- CPPUNIT_TEST(testFirstOpenWindowOutgoing);
- CPPUNIT_TEST(testFirstOpenWindowBareToFull);
- CPPUNIT_TEST(testSecondWindow);
- CPPUNIT_TEST(testUnbindRebind);
- CPPUNIT_TEST(testNoDuplicateUnbind);
- CPPUNIT_TEST(testThreeMUCWindows);
- CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnRemoveFromRoster);
- CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnAddToRoster);
- CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnSubscriptionChangeToBoth);
- CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnSubscriptionChangeToFrom);
- CPPUNIT_TEST_SUITE_END();
-
+ CPPUNIT_TEST_SUITE(ChatsManagerTest);
+ CPPUNIT_TEST(testFirstOpenWindowIncoming);
+ CPPUNIT_TEST(testSecondOpenWindowIncoming);
+ CPPUNIT_TEST(testFirstOpenWindowOutgoing);
+ CPPUNIT_TEST(testFirstOpenWindowBareToFull);
+ CPPUNIT_TEST(testSecondWindow);
+ CPPUNIT_TEST(testUnbindRebind);
+ CPPUNIT_TEST(testNoDuplicateUnbind);
+ CPPUNIT_TEST(testThreeMUCWindows);
+ CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnRemoveFromRoster);
+ CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnAddToRoster);
+ CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnSubscriptionChangeToBoth);
+ CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnSubscriptionChangeToFrom);
+ CPPUNIT_TEST(testChatControllerFullJIDBindingOnMessageAndNotReceipt);
+ CPPUNIT_TEST(testChatControllerFullJIDBindingOnTypingAndNotActive);
+ CPPUNIT_TEST(testLocalMUCServiceDiscoveryResetOnDisconnect);
+ CPPUNIT_TEST(testPresenceChangeDoesNotReplaceMUCInvite);
+ CPPUNIT_TEST(testNotSplittingMUCPresenceJoinLeaveLinesOnChatStateNotifications);
+
+ // MUC PM Tests
+ CPPUNIT_TEST(testChatControllerPMPresenceHandling);
+ CPPUNIT_TEST(testChatControllerMucPmUnavailableErrorHandling);
+
+ // Highlighting tests
+ CPPUNIT_TEST(testChatControllerHighlightingNotificationTesting);
+ CPPUNIT_TEST(testChatControllerHighlightingNotificationDeduplicateSounds);
+ CPPUNIT_TEST(testChatControllerHighlightingNotificationKeyword);
+
+ CPPUNIT_TEST(testChatControllerMeMessageHandling);
+ CPPUNIT_TEST(testRestartingMUCComponentCrash);
+ CPPUNIT_TEST(testChatControllerMeMessageHandlingInMUC);
+
+ // Carbons tests
+ CPPUNIT_TEST(testCarbonsForwardedIncomingMessageToSecondResource);
+ CPPUNIT_TEST(testCarbonsForwardedOutgoingMessageFromSecondResource);
+ CPPUNIT_TEST(testCarbonsForwardedIncomingDuplicates);
+
+ // Message correction tests
+ CPPUNIT_TEST(testChatControllerMessageCorrectionCorrectReplaceID);
+ CPPUNIT_TEST(testChatControllerMessageCorrectionIncorrectReplaceID);
+ CPPUNIT_TEST(testChatControllerMessageCorrectionReplaceBySameResource);
+ CPPUNIT_TEST(testChatControllerMessageCorrectionReplaceByOtherResource);
+ CPPUNIT_TEST(testMUCControllerMessageCorrectionNoIDMatchRequired);
+
+ // Chat window title tests
+ CPPUNIT_TEST(testImpromptuChatTitle);
+ CPPUNIT_TEST(testImpromptuChatWindowTitle);
+ CPPUNIT_TEST(testStandardMUCChatWindowTitle);
+
+ // Bookmark tests
+ CPPUNIT_TEST(testReceivingBookmarksWithDomainJID);
+ CPPUNIT_TEST(testReceivingBookmarksWithBareJID);
+ CPPUNIT_TEST(testReceivingBookmarksWithFullJID);
+ CPPUNIT_TEST(testAutoJoinBookmarksAndChattables);
+ CPPUNIT_TEST(testJoinNoAutojoinBookmark);
+ CPPUNIT_TEST(testJoinAndBookmarkMUC);
+ CPPUNIT_TEST(testReceivingNoBookmarks);
+ CPPUNIT_TEST(testReceivingNullBookmarks);
+ CPPUNIT_TEST(testReceivingBookmarksError);
+
+ CPPUNIT_TEST_SUITE_END();
+
public:
- void setUp() {
- mocks_ = new MockRepository();
- jid_ = JID("test@test.com/resource");
- stanzaChannel_ = new DummyStanzaChannel();
- iqChannel_ = new DummyIQChannel();
- iqRouter_ = new IQRouter(iqChannel_);
- capsProvider_ = new DummyCapsProvider();
- eventController_ = new EventController();
- chatWindowFactory_ = mocks_->InterfaceMock<ChatWindowFactory>();
- joinMUCWindowFactory_ = mocks_->InterfaceMock<JoinMUCWindowFactory>();
- xmppRoster_ = new XMPPRosterImpl();
- mucRegistry_ = new MUCRegistry();
- nickResolver_ = new NickResolver(jid_.toBare(), xmppRoster_, NULL, mucRegistry_);
- presenceOracle_ = new PresenceOracle(stanzaChannel_);
- serverDiscoInfo_ = boost::make_shared<DiscoInfo>();
- presenceSender_ = new StanzaChannelPresenceSender(stanzaChannel_);
- directedPresenceSender_ = new DirectedPresenceSender(presenceSender_);
- mucManager_ = new MUCManager(stanzaChannel_, iqRouter_, directedPresenceSender_, mucRegistry_);
- uiEventStream_ = new UIEventStream();
- entityCapsManager_ = new EntityCapsManager(capsProvider_, stanzaChannel_);
- chatListWindowFactory_ = mocks_->InterfaceMock<ChatListWindowFactory>();
- mucSearchWindowFactory_ = mocks_->InterfaceMock<MUCSearchWindowFactory>();
- settings_ = new DummySettingsProvider();
- profileSettings_ = new ProfileSettingsProvider("a", settings_);
- chatListWindow_ = new MockChatListWindow();
- ftManager_ = new DummyFileTransferManager();
- ftOverview_ = new FileTransferOverview(ftManager_);
- avatarManager_ = new NullAvatarManager();
- wbSessionManager_ = new WhiteboardSessionManager(iqRouter_, stanzaChannel_, presenceOracle_, entityCapsManager_);
- wbManager_ = new WhiteboardManager(whiteboardWindowFactory_, uiEventStream_, nickResolver_, wbSessionManager_);
- highlightManager_ = new HighlightManager(settings_);
-
- mocks_->ExpectCall(chatListWindowFactory_, ChatListWindowFactory::createChatListWindow).With(uiEventStream_).Return(chatListWindow_);
- clientBlockListManager_ = new ClientBlockListManager(iqRouter_);
- manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsManager_, mucManager_, mucSearchWindowFactory_, profileSettings_, ftOverview_, xmppRoster_, false, settings_, NULL, wbManager_, highlightManager_, clientBlockListManager_, emoticons_, NULL);
-
- manager_->setAvatarManager(avatarManager_);
- }
-
- void tearDown() {
- delete highlightManager_;
- //delete chatListWindowFactory
- delete profileSettings_;
- delete avatarManager_;
- delete manager_;
- delete clientBlockListManager_;
- delete ftOverview_;
- delete ftManager_;
- delete wbSessionManager_;
- delete wbManager_;
- delete directedPresenceSender_;
- delete presenceSender_;
- delete presenceOracle_;
- delete nickResolver_;
- delete mucRegistry_;
- delete stanzaChannel_;
- delete eventController_;
- delete iqRouter_;
- delete iqChannel_;
- delete uiEventStream_;
- delete mucManager_;
- delete xmppRoster_;
- delete entityCapsManager_;
- delete capsProvider_;
- delete chatListWindow_;
- delete mocks_;
- delete settings_;
- }
-
- void testFirstOpenWindowIncoming() {
- JID messageJID("testling@test.com/resource1");
-
- MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
- mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
-
- boost::shared_ptr<Message> message(new Message());
- message->setFrom(messageJID);
- std::string body("This is a legible message. >HEH@)oeueu");
- message->setBody(body);
- manager_->handleIncomingMessage(message);
- CPPUNIT_ASSERT_EQUAL(body, window->lastMessageBody_);
- }
-
- void testSecondOpenWindowIncoming() {
- JID messageJID1("testling@test.com/resource1");
-
- MockChatWindow* window1 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
- mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID1, uiEventStream_).Return(window1);
-
- boost::shared_ptr<Message> message1(new Message());
- message1->setFrom(messageJID1);
- std::string body1("This is a legible message. >HEH@)oeueu");
- message1->setBody(body1);
- manager_->handleIncomingMessage(message1);
- CPPUNIT_ASSERT_EQUAL(body1, window1->lastMessageBody_);
-
- JID messageJID2("testling@test.com/resource2");
-
- //MockChatWindow* window2 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
- //mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID2, uiEventStream_).Return(window2);
-
- boost::shared_ptr<Message> message2(new Message());
- message2->setFrom(messageJID2);
- std::string body2("This is a legible message. .cmaulm.chul");
- message2->setBody(body2);
- manager_->handleIncomingMessage(message2);
- CPPUNIT_ASSERT_EQUAL(body2, window1->lastMessageBody_);
- }
-
- void testFirstOpenWindowOutgoing() {
- std::string messageJIDString("testling@test.com");
-
- ChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
- mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString), uiEventStream_).Return(window);
-
- uiEventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(JID(messageJIDString))));
- }
-
-
- void testFirstOpenWindowBareToFull() {
- std::string bareJIDString("testling@test.com");
- std::string fullJIDString("testling@test.com/resource1");
-
- MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
- mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(bareJIDString), uiEventStream_).Return(window);
- uiEventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(JID(bareJIDString))));
-
- boost::shared_ptr<Message> message(new Message());
- message->setFrom(JID(fullJIDString));
- std::string body("This is a legible message. mjuga3089gm8G(*>M)@*(");
- message->setBody(body);
- manager_->handleIncomingMessage(message);
- CPPUNIT_ASSERT_EQUAL(body, window->lastMessageBody_);
- }
-
- void testSecondWindow() {
- std::string messageJIDString1("testling1@test.com");
- ChatWindow* window1 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
- mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString1), uiEventStream_).Return(window1);
- uiEventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(JID(messageJIDString1))));
-
- std::string messageJIDString2("testling2@test.com");
- ChatWindow* window2 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
- mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString2), uiEventStream_).Return(window2);
-
- uiEventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(JID(messageJIDString2))));
- }
-
- /** Complete cycle.
- Create unbound window.
- Bind it.
- Unbind it.
- Rebind it.
- */
- void testUnbindRebind() {
- std::string bareJIDString("testling@test.com");
- std::string fullJIDString1("testling@test.com/resource1");
- std::string fullJIDString2("testling@test.com/resource2");
-
- MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
- mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(bareJIDString), uiEventStream_).Return(window);
- uiEventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(JID(bareJIDString))));
-
- boost::shared_ptr<Message> message1(new Message());
- message1->setFrom(JID(fullJIDString1));
- std::string messageBody1("This is a legible message.");
- message1->setBody(messageBody1);
- manager_->handleIncomingMessage(message1);
- CPPUNIT_ASSERT_EQUAL(messageBody1, window->lastMessageBody_);
-
- boost::shared_ptr<Presence> jid1Online(new Presence());
- jid1Online->setFrom(JID(fullJIDString1));
- boost::shared_ptr<Presence> jid1Offline(new Presence());
- jid1Offline->setFrom(JID(fullJIDString1));
- jid1Offline->setType(Presence::Unavailable);
- presenceOracle_->onPresenceChange(jid1Offline);
-
- boost::shared_ptr<Message> message2(new Message());
- message2->setFrom(JID(fullJIDString2));
- std::string messageBody2("This is another legible message.");
- message2->setBody(messageBody2);
- manager_->handleIncomingMessage(message2);
- CPPUNIT_ASSERT_EQUAL(messageBody2, window->lastMessageBody_);
- }
-
- /**
- * Test that MUC PMs get opened in the right windows
- */
- void testThreeMUCWindows() {
- JID muc("testling@test.com");
- ChatWindow* mucWindow = new MockChatWindow();
- mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(muc, uiEventStream_).Return(mucWindow);
- uiEventStream_->send(boost::make_shared<JoinMUCUIEvent>(muc, std::string("nick")));
-
-
- std::string messageJIDString1("testling@test.com/1");
- ChatWindow* window1 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
- mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString1), uiEventStream_).Return(window1);
- uiEventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(JID(messageJIDString1))));
-
- std::string messageJIDString2("testling@test.com/2");
- ChatWindow* window2 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
- mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString2), uiEventStream_).Return(window2);
-
- uiEventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(JID(messageJIDString2))));
-
- std::string messageJIDString3("testling@test.com/3");
- ChatWindow* window3 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
- mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString3), uiEventStream_).Return(window3);
-
- uiEventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(JID(messageJIDString3))));
-
- /* Refetch an earlier window */
- /* We do not expect a new window to be created */
- uiEventStream_->send(boost::shared_ptr<UIEvent>(new RequestChatUIEvent(JID(messageJIDString1))));
-
- }
-
- /**
- Test that a second window isn't unbound where there's already an unbound one.
- Bind 1
- Bind 2
- Unbind 1
- Unbind 2 (but it doesn't)
- Sent to bound 2
- Rebind 1
- */
- void testNoDuplicateUnbind() {
- JID messageJID1("testling@test.com/resource1");
-
- MockChatWindow* window1 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
- mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID1, uiEventStream_).Return(window1);
-
- boost::shared_ptr<Message> message1(new Message());
- message1->setFrom(messageJID1);
- message1->setBody("This is a legible message1.");
- manager_->handleIncomingMessage(message1);
-
- JID messageJID2("testling@test.com/resource2");
-
- //MockChatWindow* window2 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
- //mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID2, uiEventStream_).Return(window2);
-
- boost::shared_ptr<Message> message2(new Message());
- message2->setFrom(messageJID2);
- message2->setBody("This is a legible message2.");
- manager_->handleIncomingMessage(message2);
-
- boost::shared_ptr<Presence> jid1Online(new Presence());
- jid1Online->setFrom(JID(messageJID1));
- boost::shared_ptr<Presence> jid1Offline(new Presence());
- jid1Offline->setFrom(JID(messageJID1));
- jid1Offline->setType(Presence::Unavailable);
- presenceOracle_->onPresenceChange(jid1Offline);
-
- boost::shared_ptr<Presence> jid2Online(new Presence());
- jid2Online->setFrom(JID(messageJID2));
- boost::shared_ptr<Presence> jid2Offline(new Presence());
- jid2Offline->setFrom(JID(messageJID2));
- jid2Offline->setType(Presence::Unavailable);
- presenceOracle_->onPresenceChange(jid2Offline);
-
- JID messageJID3("testling@test.com/resource3");
-
- boost::shared_ptr<Message> message3(new Message());
- message3->setFrom(messageJID3);
- std::string body3("This is a legible message3.");
- message3->setBody(body3);
- manager_->handleIncomingMessage(message3);
- CPPUNIT_ASSERT_EQUAL(body3, window1->lastMessageBody_);
-
- boost::shared_ptr<Message> message2b(new Message());
- message2b->setFrom(messageJID2);
- std::string body2b("This is a legible message2b.");
- message2b->setBody(body2b);
- manager_->handleIncomingMessage(message2b);
- CPPUNIT_ASSERT_EQUAL(body2b, window1->lastMessageBody_);
- }
-
- /**
- * Test that ChatController doesn't send receipts anymore after removal of the contact from the roster.
- */
- void testChatControllerPresenceAccessUpdatedOnRemoveFromRoster() {
- JID messageJID("testling@test.com/resource1");
- xmppRoster_->addContact(messageJID, "foo", std::vector<std::string>(), RosterItemPayload::Both);
-
- MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
- mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
- settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, true);
-
- boost::shared_ptr<Message> message = makeDeliveryReceiptTestMessage(messageJID, "1");
- manager_->handleIncomingMessage(message);
- Stanza::ref stanzaContactOnRoster = stanzaChannel_->getStanzaAtIndex<Stanza>(0);
- CPPUNIT_ASSERT_EQUAL(st(1), stanzaChannel_->sentStanzas.size());
- CPPUNIT_ASSERT(stanzaContactOnRoster->getPayload<DeliveryReceipt>() != 0);
-
- xmppRoster_->removeContact(messageJID);
-
- message->setID("2");
- manager_->handleIncomingMessage(message);
- CPPUNIT_ASSERT_EQUAL(st(1), stanzaChannel_->sentStanzas.size());
- }
-
- /**
- * Test that ChatController sends receipts after the contact has been added to the roster.
- */
- void testChatControllerPresenceAccessUpdatedOnAddToRoster() {
- JID messageJID("testling@test.com/resource1");
-
- MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
- mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
- settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, true);
-
- boost::shared_ptr<Message> message = makeDeliveryReceiptTestMessage(messageJID, "1");
- manager_->handleIncomingMessage(message);
-
- CPPUNIT_ASSERT_EQUAL(st(0), stanzaChannel_->sentStanzas.size());
-
- xmppRoster_->addContact(messageJID, "foo", std::vector<std::string>(), RosterItemPayload::Both);
- message->setID("2");
- manager_->handleIncomingMessage(message);
-
- CPPUNIT_ASSERT_EQUAL(st(1), stanzaChannel_->sentStanzas.size());
- Stanza::ref stanzaContactOnRoster = stanzaChannel_->getStanzaAtIndex<Stanza>(0);
- CPPUNIT_ASSERT(stanzaContactOnRoster->getPayload<DeliveryReceipt>() != 0);
- }
-
- /**
- * Test that ChatController sends receipts if requested after change from subscription state To to subscription state Both.
- */
- void testChatControllerPresenceAccessUpdatedOnSubscriptionChangeToBoth() {
- testhelperChatControllerPresenceAccessUpdatedOnSubscriptionChangeReceiptsAllowed(RosterItemPayload::To, RosterItemPayload::Both);
- }
-
- /**
- * Test that ChatController sends receipts if requested after change from subscription state To to subscription state From.
- */
- void testChatControllerPresenceAccessUpdatedOnSubscriptionChangeToFrom() {
- testhelperChatControllerPresenceAccessUpdatedOnSubscriptionChangeReceiptsAllowed(RosterItemPayload::To, RosterItemPayload::From);
- }
-
- void testhelperChatControllerPresenceAccessUpdatedOnSubscriptionChangeReceiptsAllowed(RosterItemPayload::Subscription from, RosterItemPayload::Subscription to) {
- JID messageJID("testling@test.com/resource1");
- xmppRoster_->addContact(messageJID, "foo", std::vector<std::string>(), from);
-
- MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
- mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
- settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, true);
-
- boost::shared_ptr<Message> message = makeDeliveryReceiptTestMessage(messageJID, "1");
- manager_->handleIncomingMessage(message);
-
- CPPUNIT_ASSERT_EQUAL(st(0), stanzaChannel_->sentStanzas.size());
-
- xmppRoster_->addContact(messageJID, "foo", std::vector<std::string>(), to);
- message->setID("2");
- manager_->handleIncomingMessage(message);
-
- CPPUNIT_ASSERT_EQUAL(st(1), stanzaChannel_->sentStanzas.size());
- Stanza::ref stanzaContactOnRoster = stanzaChannel_->getStanzaAtIndex<Stanza>(0);
- CPPUNIT_ASSERT(stanzaContactOnRoster->getPayload<DeliveryReceipt>() != 0);
- }
+ void setUp() {
+ mocks_ = new MockRepository();
+ notifier_ = std::make_unique<DummyNotifier>();
+ jid_ = JID("test@test.com/resource");
+ stanzaChannel_ = new DummyStanzaChannel();
+ iqRouter_ = new IQRouter(stanzaChannel_);
+ eventController_ = new EventController();
+ chatWindowFactory_ = mocks_->InterfaceMock<ChatWindowFactory>();
+ joinMUCWindowFactory_ = mocks_->InterfaceMock<JoinMUCWindowFactory>();
+ xmppRoster_ = new XMPPRosterImpl();
+ mucRegistry_ = new MUCRegistry();
+ nickResolver_ = new NickResolver(jid_.toBare(), xmppRoster_, nullptr, mucRegistry_);
+ presenceOracle_ = new PresenceOracle(stanzaChannel_, xmppRoster_);
+ serverDiscoInfo_ = std::make_shared<DiscoInfo>();
+ presenceSender_ = new StanzaChannelPresenceSender(stanzaChannel_);
+ directedPresenceSender_ = new DirectedPresenceSender(presenceSender_);
+ mucManager_ = new MUCManager(stanzaChannel_, iqRouter_, directedPresenceSender_, mucRegistry_);
+ uiEventStream_ = new UIEventStream();
+ entityCapsProvider_ = new DummyEntityCapsProvider();
+ chatListWindowFactory_ = mocks_->InterfaceMock<ChatListWindowFactory>();
+ mucSearchWindowFactory_ = mocks_->InterfaceMock<MUCSearchWindowFactory>();
+ settings_ = new DummySettingsProvider();
+ profileSettings_ = new ProfileSettingsProvider("a", settings_);
+ chatListWindow_ = new MockChatListWindow();
+ ftManager_ = new DummyFileTransferManager();
+ ftOverview_ = new FileTransferOverview(ftManager_);
+ avatarManager_ = new NullAvatarManager();
+ eventNotifier_ = new EventNotifier(eventController_, notifier_.get(), avatarManager_, nickResolver_);
+ wbSessionManager_ = new WhiteboardSessionManager(iqRouter_, stanzaChannel_, presenceOracle_, entityCapsProvider_);
+ wbManager_ = new WhiteboardManager(whiteboardWindowFactory_, uiEventStream_, nickResolver_, wbSessionManager_);
+ highlightManager_ = new HighlightManager(settings_);
+ highlightManager_->resetToDefaultConfiguration();
+ handledHighlightActions_ = 0;
+ soundsPlayed_.clear();
+ highlightManager_->onHighlight.connect(boost::bind(&ChatsManagerTest::handleHighlightAction, this, _1));
+
+ crypto_ = PlatformCryptoProvider::create();
+ vcardStorage_ = new VCardMemoryStorage(crypto_);
+ vcardManager_ = new VCardManager(jid_, iqRouter_, vcardStorage_);
+ mocks_->ExpectCall(chatListWindowFactory_, ChatListWindowFactory::createChatListWindow).With(uiEventStream_).Return(chatListWindow_);
+ clientBlockListManager_ = new ClientBlockListManager(iqRouter_);
+ timerFactory_ = new DummyTimerFactory();
+ chattables_ = std::make_unique<Chattables>();
+ manager_ = new ExtendedChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, timerFactory_, mucRegistry_, entityCapsProvider_, mucManager_, mucSearchWindowFactory_, profileSettings_, ftOverview_, xmppRoster_, false, settings_, nullptr, wbManager_, highlightManager_, clientBlockListManager_, emoticons_, vcardManager_, *chattables_);
+
+ manager_->setAvatarManager(avatarManager_);
+ }
+
+ void tearDown() {
+ delete highlightManager_;
+ delete profileSettings_;
+ delete eventNotifier_;
+ delete avatarManager_;
+ delete manager_;
+ delete timerFactory_;
+ delete clientBlockListManager_;
+ delete vcardManager_;
+ delete vcardStorage_;
+ delete crypto_;
+ delete ftOverview_;
+ delete ftManager_;
+ delete wbSessionManager_;
+ delete wbManager_;
+ delete directedPresenceSender_;
+ delete presenceSender_;
+ delete presenceOracle_;
+ delete nickResolver_;
+ delete mucRegistry_;
+ delete iqRouter_;
+ delete stanzaChannel_;
+ delete eventController_;
+ delete uiEventStream_;
+ delete mucManager_;
+ delete xmppRoster_;
+ delete entityCapsProvider_;
+ delete chatListWindow_;
+ delete mocks_;
+ delete settings_;
+ }
+
+ void testFirstOpenWindowIncoming() {
+ JID messageJID("testling@test.com/resource1");
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
+
+ std::shared_ptr<Message> message(new Message());
+ message->setFrom(messageJID);
+ std::string body("This is a legible message. >HEH@)oeueu");
+ message->setBody(body);
+ manager_->handleIncomingMessage(message);
+ CPPUNIT_ASSERT_EQUAL(body, MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+ }
+
+ void testSecondOpenWindowIncoming() {
+ JID messageJID1("testling@test.com/resource1");
+
+ MockChatWindow* window1 = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID1, uiEventStream_).Return(window1);
+
+ std::shared_ptr<Message> message1(new Message());
+ message1->setFrom(messageJID1);
+ std::string body1("This is a legible message. >HEH@)oeueu");
+ message1->setBody(body1);
+ manager_->handleIncomingMessage(message1);
+ CPPUNIT_ASSERT_EQUAL(body1, MockChatWindow::bodyFromMessage(window1->lastAddedMessage_));
+
+ JID messageJID2("testling@test.com/resource2");
+
+ std::shared_ptr<Message> message2(new Message());
+ message2->setFrom(messageJID2);
+ std::string body2("This is a legible message. .cmaulm.chul");
+ message2->setBody(body2);
+ manager_->handleIncomingMessage(message2);
+ CPPUNIT_ASSERT_EQUAL(body2, MockChatWindow::bodyFromMessage(window1->lastAddedMessage_));
+ }
+
+ void testFirstOpenWindowOutgoing() {
+ std::string messageJIDString("testling@test.com");
+
+ ChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString), uiEventStream_).Return(window);
+
+ uiEventStream_->send(std::make_shared<RequestChatUIEvent>(JID(messageJIDString)));
+ }
+
+
+ void testFirstOpenWindowBareToFull() {
+ std::string bareJIDString("testling@test.com");
+ std::string fullJIDString("testling@test.com/resource1");
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(bareJIDString), uiEventStream_).Return(window);
+ uiEventStream_->send(std::make_shared<RequestChatUIEvent>(JID(bareJIDString)));
+
+ std::shared_ptr<Message> message(new Message());
+ message->setFrom(JID(fullJIDString));
+ std::string body("This is a legible message. mjuga3089gm8G(*>M)@*(");
+ message->setBody(body);
+ manager_->handleIncomingMessage(message);
+ CPPUNIT_ASSERT_EQUAL(body, MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+ }
+
+ void testSecondWindow() {
+ std::string messageJIDString1("testling1@test.com");
+ ChatWindow* window1 = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString1), uiEventStream_).Return(window1);
+ uiEventStream_->send(std::make_shared<RequestChatUIEvent>(JID(messageJIDString1)));
+
+ std::string messageJIDString2("testling2@test.com");
+ ChatWindow* window2 = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString2), uiEventStream_).Return(window2);
+
+ uiEventStream_->send(std::make_shared<RequestChatUIEvent>(JID(messageJIDString2)));
+ }
+
+ /** Complete cycle.
+ Create unbound window.
+ Bind it.
+ Unbind it.
+ Rebind it.
+ */
+ void testUnbindRebind() {
+ std::string bareJIDString("testling@test.com");
+ std::string fullJIDString1("testling@test.com/resource1");
+ std::string fullJIDString2("testling@test.com/resource2");
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(bareJIDString), uiEventStream_).Return(window);
+ uiEventStream_->send(std::make_shared<RequestChatUIEvent>(JID(bareJIDString)));
+
+ std::shared_ptr<Message> message1(new Message());
+ message1->setFrom(JID(fullJIDString1));
+ std::string messageBody1("This is a legible message.");
+ message1->setBody(messageBody1);
+ manager_->handleIncomingMessage(message1);
+ CPPUNIT_ASSERT_EQUAL(messageBody1, MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+
+ std::shared_ptr<Presence> jid1Online(new Presence());
+ jid1Online->setFrom(JID(fullJIDString1));
+ std::shared_ptr<Presence> jid1Offline(new Presence());
+ jid1Offline->setFrom(JID(fullJIDString1));
+ jid1Offline->setType(Presence::Unavailable);
+ presenceOracle_->onPresenceChange(jid1Offline);
+
+ std::shared_ptr<Message> message2(new Message());
+ message2->setFrom(JID(fullJIDString2));
+ std::string messageBody2("This is another legible message.");
+ message2->setBody(messageBody2);
+ manager_->handleIncomingMessage(message2);
+ CPPUNIT_ASSERT_EQUAL(messageBody2, MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+ }
+
+ /**
+ * Test that MUC PMs get opened in the right windows
+ */
+ void testThreeMUCWindows() {
+ JID muc("testling@test.com");
+ ChatWindow* mucWindow = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(muc, uiEventStream_).Return(mucWindow);
+ uiEventStream_->send(std::make_shared<JoinMUCUIEvent>(muc, std::string("nick")));
+
+
+ std::string messageJIDString1("testling@test.com/1");
+ ChatWindow* window1 = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString1), uiEventStream_).Return(window1);
+ uiEventStream_->send(std::make_shared<RequestChatUIEvent>(JID(messageJIDString1)));
+
+ std::string messageJIDString2("testling@test.com/2");
+ ChatWindow* window2 = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString2), uiEventStream_).Return(window2);
+
+ uiEventStream_->send(std::make_shared<RequestChatUIEvent>(JID(messageJIDString2)));
+
+ std::string messageJIDString3("testling@test.com/3");
+ ChatWindow* window3 = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString3), uiEventStream_).Return(window3);
+
+ uiEventStream_->send(std::make_shared<RequestChatUIEvent>(JID(messageJIDString3)));
+
+ /* Refetch an earlier window */
+ /* We do not expect a new window to be created */
+ uiEventStream_->send(std::make_shared<RequestChatUIEvent>(JID(messageJIDString1)));
+
+ }
+
+ /**
+ Test that a second window isn't unbound where there's already an unbound one.
+ Bind 1
+ Bind 2
+ Unbind 1
+ Unbind 2 (but it doesn't)
+ Sent to bound 2
+ Rebind 1
+ */
+ void testNoDuplicateUnbind() {
+ JID messageJID1("testling@test.com/resource1");
+
+ MockChatWindow* window1 = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID1, uiEventStream_).Return(window1);
+
+ std::shared_ptr<Message> message1(new Message());
+ message1->setFrom(messageJID1);
+ message1->setBody("This is a legible message1.");
+ manager_->handleIncomingMessage(message1);
+
+ JID messageJID2("testling@test.com/resource2");
+
+ std::shared_ptr<Message> message2(new Message());
+ message2->setFrom(messageJID2);
+ message2->setBody("This is a legible message2.");
+ manager_->handleIncomingMessage(message2);
+
+ std::shared_ptr<Presence> jid1Online(new Presence());
+ jid1Online->setFrom(JID(messageJID1));
+ std::shared_ptr<Presence> jid1Offline(new Presence());
+ jid1Offline->setFrom(JID(messageJID1));
+ jid1Offline->setType(Presence::Unavailable);
+ presenceOracle_->onPresenceChange(jid1Offline);
+
+ std::shared_ptr<Presence> jid2Online(new Presence());
+ jid2Online->setFrom(JID(messageJID2));
+ std::shared_ptr<Presence> jid2Offline(new Presence());
+ jid2Offline->setFrom(JID(messageJID2));
+ jid2Offline->setType(Presence::Unavailable);
+ presenceOracle_->onPresenceChange(jid2Offline);
+
+ JID messageJID3("testling@test.com/resource3");
+
+ std::shared_ptr<Message> message3(new Message());
+ message3->setFrom(messageJID3);
+ std::string body3("This is a legible message3.");
+ message3->setBody(body3);
+ manager_->handleIncomingMessage(message3);
+ CPPUNIT_ASSERT_EQUAL(body3, MockChatWindow::bodyFromMessage(window1->lastAddedMessage_));
+
+ std::shared_ptr<Message> message2b(new Message());
+ message2b->setFrom(messageJID2);
+ std::string body2b("This is a legible message2b.");
+ message2b->setBody(body2b);
+ manager_->handleIncomingMessage(message2b);
+ CPPUNIT_ASSERT_EQUAL(body2b, MockChatWindow::bodyFromMessage(window1->lastAddedMessage_));
+ }
+
+ /**
+ * Test that ChatController doesn't send receipts anymore after removal of the contact from the roster.
+ */
+ void testChatControllerPresenceAccessUpdatedOnRemoveFromRoster() {
+ JID messageJID("testling@test.com/resource1");
+ xmppRoster_->addContact(messageJID, "foo", std::vector<std::string>(), RosterItemPayload::Both);
+
+ MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
+ settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, true);
+
+ std::shared_ptr<Message> message = makeDeliveryReceiptTestMessage(messageJID, "1");
+ manager_->handleIncomingMessage(message);
+ Stanza::ref stanzaContactOnRoster = stanzaChannel_->getStanzaAtIndex<Stanza>(1);
+ CPPUNIT_ASSERT_EQUAL(st(1), stanzaChannel_->countSentStanzaOfType<Message>());
+ CPPUNIT_ASSERT(stanzaContactOnRoster->getPayload<DeliveryReceipt>() != nullptr);
+
+ xmppRoster_->removeContact(messageJID);
+
+ message->setID("2");
+ manager_->handleIncomingMessage(message);
+ CPPUNIT_ASSERT_EQUAL(st(1), stanzaChannel_->countSentStanzaOfType<Message>());
+ }
+
+ /**
+ * Test that ChatController sends receipts after the contact has been added to the roster.
+ */
+ void testChatControllerPresenceAccessUpdatedOnAddToRoster() {
+ JID messageJID("testling@test.com/resource1");
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
+ settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, true);
+
+ std::shared_ptr<Message> message = makeDeliveryReceiptTestMessage(messageJID, "1");
+ manager_->handleIncomingMessage(message);
+
+ CPPUNIT_ASSERT_EQUAL(st(0), stanzaChannel_->countSentStanzaOfType<Message>());
+
+ xmppRoster_->addContact(messageJID, "foo", std::vector<std::string>(), RosterItemPayload::Both);
+ message->setID("2");
+ manager_->handleIncomingMessage(message);
+
+ CPPUNIT_ASSERT_EQUAL(st(1), stanzaChannel_->countSentStanzaOfType<Message>());
+ Stanza::ref stanzaContactOnRoster = stanzaChannel_->getStanzaAtIndex<Stanza>(1);
+ CPPUNIT_ASSERT(stanzaContactOnRoster->getPayload<DeliveryReceipt>() != nullptr);
+ }
+
+ /**
+ * Test that ChatController sends receipts if requested after change from subscription state To to subscription state Both.
+ */
+ void testChatControllerPresenceAccessUpdatedOnSubscriptionChangeToBoth() {
+ testhelperChatControllerPresenceAccessUpdatedOnSubscriptionChangeReceiptsAllowed(RosterItemPayload::To, RosterItemPayload::Both);
+ }
+
+ /**
+ * Test that ChatController sends receipts if requested after change from subscription state To to subscription state From.
+ */
+ void testChatControllerPresenceAccessUpdatedOnSubscriptionChangeToFrom() {
+ testhelperChatControllerPresenceAccessUpdatedOnSubscriptionChangeReceiptsAllowed(RosterItemPayload::To, RosterItemPayload::From);
+ }
+
+ void testChatControllerFullJIDBindingOnMessageAndNotReceipt() {
+ JID ownJID("test@test.com/resource");
+ JID sender("foo@test.com");
+ std::vector<JID> senderResource;
+ senderResource.push_back(sender.withResource("resourceA"));
+ senderResource.push_back(sender.withResource("resourceB"));
+
+ // We support delivery receipts.
+ settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, true);
+
+ // Open chat window to a sender.
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(sender, uiEventStream_).Return(window);
+
+ uiEventStream_->send(std::make_shared<RequestChatUIEvent>(sender));
+
+ for (const auto& senderJID : senderResource) {
+ // The sender supports delivery receipts.
+ DiscoInfo::ref disco = std::make_shared<DiscoInfo>();
+ disco->addFeature(DiscoInfo::MessageDeliveryReceiptsFeature);
+ entityCapsProvider_->caps[senderJID] = disco;
+
+ // The sender is online.
+ Presence::ref senderPresence = std::make_shared<Presence>();
+ senderPresence->setFrom(senderJID);
+ senderPresence->setTo(ownJID);
+ stanzaChannel_->onPresenceReceived(senderPresence);
+
+ entityCapsProvider_->onCapsChanged(senderJID);
+ }
+
+ // Send first message.
+ window->onSendMessageRequest("hello there", false);
+
+ // A bare message is send because no resources is bound.
+ CPPUNIT_ASSERT_EQUAL(sender, stanzaChannel_->getStanzaAtIndex<Message>(1)->getTo());
+ CPPUNIT_ASSERT(stanzaChannel_->getStanzaAtIndex<Message>(1)->getPayload<DeliveryReceiptRequest>());
+
+ // Two resources respond with message receipts.
+ for (const auto& senderJID : senderResource) {
+ Message::ref receiptReply = std::make_shared<Message>();
+ receiptReply->setFrom(senderJID);
+ receiptReply->setTo(ownJID);
+
+ std::shared_ptr<DeliveryReceipt> receipt = std::make_shared<DeliveryReceipt>();
+ receipt->setReceivedID(stanzaChannel_->getStanzaAtIndex<Message>(1)->getID());
+ receiptReply->addPayload(receipt);
+ manager_->handleIncomingMessage(receiptReply);
+ }
+
+ // Send second message.
+ window->onSendMessageRequest("how are you?", false);
+
+ // A bare message is send because no resources is bound.
+ CPPUNIT_ASSERT_EQUAL(sender, stanzaChannel_->getStanzaAtIndex<Message>(1)->getTo());
+ CPPUNIT_ASSERT(stanzaChannel_->getStanzaAtIndex<Message>(1)->getPayload<DeliveryReceiptRequest>());
+
+ // Two resources respond with message receipts.
+ for (const auto& senderJID : senderResource) {
+ Message::ref receiptReply = std::make_shared<Message>();
+ receiptReply->setFrom(senderJID);
+ receiptReply->setTo(ownJID);
+
+ std::shared_ptr<DeliveryReceipt> receipt = std::make_shared<DeliveryReceipt>();
+ receipt->setReceivedID(stanzaChannel_->getStanzaAtIndex<Message>(1)->getID());
+ receiptReply->addPayload(receipt);
+ manager_->handleIncomingMessage(receiptReply);
+ }
+
+ // Reply with a message including a body text.
+ Message::ref reply = std::make_shared<Message>();
+ reply->setFrom(senderResource[0]);
+ reply->setTo(ownJID);
+ reply->setBody("fine.");
+ manager_->handleIncomingMessage(reply);
+
+ // Send third message.
+ window->onSendMessageRequest("great to hear.", false);
+
+ // The chat session is bound to the full JID of the first resource.
+ CPPUNIT_ASSERT_EQUAL(senderResource[0], stanzaChannel_->getStanzaAtIndex<Message>(3)->getTo());
+ CPPUNIT_ASSERT(stanzaChannel_->getStanzaAtIndex<Message>(2)->getPayload<DeliveryReceiptRequest>());
+
+ // Receive random receipt from second sender resource.
+ reply = std::make_shared<Message>();
+ reply->setFrom(senderResource[1]);
+ reply->setTo(ownJID);
+
+ std::shared_ptr<DeliveryReceipt> receipt = std::make_shared<DeliveryReceipt>();
+ receipt->setReceivedID(stanzaChannel_->getStanzaAtIndex<Message>(2)->getID());
+ reply->addPayload(receipt);
+ manager_->handleIncomingMessage(reply);
+
+ // Send forth message.
+ window->onSendMessageRequest("what else is new?", false);
+
+ // The chat session is bound to the full JID of the first resource.
+ CPPUNIT_ASSERT_EQUAL(senderResource[0], stanzaChannel_->getStanzaAtIndex<Message>(3)->getTo());
+ CPPUNIT_ASSERT(stanzaChannel_->getStanzaAtIndex<Message>(3)->getPayload<DeliveryReceiptRequest>());
+
+ // Reply with a message including a body text from second resource.
+ reply = std::make_shared<Message>();
+ reply->setFrom(senderResource[1]);
+ reply->setTo(ownJID);
+ reply->setBody("nothing.");
+ manager_->handleIncomingMessage(reply);
+
+ // Send fifth message.
+ window->onSendMessageRequest("okay", false);
+
+ // The chat session is now bound to the full JID of the second resource.
+ CPPUNIT_ASSERT_EQUAL(senderResource[1], stanzaChannel_->getStanzaAtIndex<Message>(5)->getTo());
+ CPPUNIT_ASSERT(stanzaChannel_->getStanzaAtIndex<Message>(5)->getPayload<DeliveryReceiptRequest>());
+ }
+
+ void testChatControllerFullJIDBindingOnTypingAndNotActive() {
+ JID ownJID("test@test.com/resource");
+ JID sender("foo@test.com");
+ std::vector<JID> senderResource;
+ senderResource.push_back(sender.withResource("resourceA"));
+ senderResource.push_back(sender.withResource("resourceB"));
+
+ // We support delivery receipts.
+ settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, true);
+
+ // Open chat window to a sender.
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(sender, uiEventStream_).Return(window);
+
+ uiEventStream_->send(std::make_shared<RequestChatUIEvent>(sender));
+
+ for (const auto& senderJID : senderResource) {
+ // The sender supports delivery receipts.
+ DiscoInfo::ref disco = std::make_shared<DiscoInfo>();
+ disco->addFeature(DiscoInfo::MessageDeliveryReceiptsFeature);
+ entityCapsProvider_->caps[senderJID] = disco;
+
+ // The sender is online.
+ Presence::ref senderPresence = std::make_shared<Presence>();
+ senderPresence->setFrom(senderJID);
+ senderPresence->setTo(ownJID);
+ stanzaChannel_->onPresenceReceived(senderPresence);
+
+ entityCapsProvider_->onCapsChanged(senderJID);
+ }
+
+ // Send first message.
+ window->onSendMessageRequest("hello there", false);
+
+ // A bare message is send because no resources is bound.
+ CPPUNIT_ASSERT_EQUAL(sender, stanzaChannel_->getStanzaAtIndex<Message>(1)->getTo());
+ CPPUNIT_ASSERT(stanzaChannel_->getStanzaAtIndex<Message>(1)->getPayload<DeliveryReceiptRequest>());
+
+ // Two resources respond with message receipts.
+ for (const auto& senderJID : senderResource) {
+ Message::ref reply = std::make_shared<Message>();
+ reply->setFrom(senderJID);
+ reply->setTo(ownJID);
+
+ std::shared_ptr<ChatState> csn = std::make_shared<ChatState>();
+ csn->setChatState(ChatState::Active);
+ reply->addPayload(csn);
+ manager_->handleIncomingMessage(reply);
+ }
+
+ // Send second message.
+ window->onSendMessageRequest("how are you?", false);
+
+ // A bare message is send because no resources is bound.
+ CPPUNIT_ASSERT_EQUAL(sender, stanzaChannel_->getStanzaAtIndex<Message>(1)->getTo());
+ CPPUNIT_ASSERT(stanzaChannel_->getStanzaAtIndex<Message>(1)->getPayload<DeliveryReceiptRequest>());
+
+ // Two resources respond with message receipts.
+ for (const auto& senderJID : senderResource) {
+ Message::ref receiptReply = std::make_shared<Message>();
+ receiptReply->setFrom(senderJID);
+ receiptReply->setTo(ownJID);
+
+ std::shared_ptr<DeliveryReceipt> receipt = std::make_shared<DeliveryReceipt>();
+ receipt->setReceivedID(stanzaChannel_->getStanzaAtIndex<Message>(1)->getID());
+ receiptReply->addPayload(receipt);
+ manager_->handleIncomingMessage(receiptReply);
+ }
+
+ // Reply with a message including a CSN.
+ Message::ref reply = std::make_shared<Message>();
+ reply->setFrom(senderResource[0]);
+ reply->setTo(ownJID);
+
+ std::shared_ptr<ChatState> csn = std::make_shared<ChatState>();
+ csn->setChatState(ChatState::Composing);
+ reply->addPayload(csn);
+ manager_->handleIncomingMessage(reply);
+
+ // Send third message.
+ window->onSendMessageRequest("great to hear.", false);
+
+ // The chat session is now bound to the full JID of the first resource due to its recent composing message.
+ CPPUNIT_ASSERT_EQUAL(senderResource[0], stanzaChannel_->getStanzaAtIndex<Message>(3)->getTo());
+ CPPUNIT_ASSERT(stanzaChannel_->getStanzaAtIndex<Message>(3)->getPayload<DeliveryReceiptRequest>());
+
+ // Reply with a message including a CSN from the other resource.
+ reply = std::make_shared<Message>();
+ reply->setFrom(senderResource[1]);
+ reply->setTo(ownJID);
+
+ csn = std::make_shared<ChatState>();
+ csn->setChatState(ChatState::Composing);
+ reply->addPayload(csn);
+ manager_->handleIncomingMessage(reply);
+
+ // Send third message.
+ window->onSendMessageRequest("ping.", false);
+
+ // The chat session is now bound to the full JID of the second resource due to its recent composing message.
+ CPPUNIT_ASSERT_EQUAL(senderResource[1], stanzaChannel_->getStanzaAtIndex<Message>(4)->getTo());
+ CPPUNIT_ASSERT(stanzaChannel_->getStanzaAtIndex<Message>(4)->getPayload<DeliveryReceiptRequest>());
+ }
+
+ void testChatControllerPMPresenceHandling() {
+ JID participantA = JID("test@rooms.test.com/participantA");
+ JID participantB = JID("test@rooms.test.com/participantB");
+
+ mucRegistry_->addMUC("test@rooms.test.com");
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(participantA, uiEventStream_).Return(window);
+
+ uiEventStream_->send(std::make_shared<RequestChatUIEvent>(JID(participantA)));
+
+ Presence::ref presence = Presence::create();
+ presence->setFrom(participantA);
+ presence->setShow(StatusShow::Online);
+ stanzaChannel_->onPresenceReceived(presence);
+ CPPUNIT_ASSERT_EQUAL(std::string("participantA has become available."), MockChatWindow::bodyFromMessage(window->lastAddedPresence_));
+
+ presence = Presence::create();
+ presence->setFrom(participantB);
+ presence->setShow(StatusShow::Away);
+ stanzaChannel_->onPresenceReceived(presence);
+
+ presence = Presence::create();
+ presence->setFrom(participantA);
+ presence->setShow(StatusShow::None);
+ presence->setType(Presence::Unavailable);
+ stanzaChannel_->onPresenceReceived(presence);
+ CPPUNIT_ASSERT_EQUAL(std::string("participantA has gone offline."), MockChatWindow::bodyFromMessage(window->lastReplacedLastMessage_));
+ }
+
+ void testChatControllerMucPmUnavailableErrorHandling() {
+ auto mucJID = JID("test@rooms.test.com");
+ auto participantA = mucJID.withResource("participantA");
+ auto participantB = mucJID.withResource("participantB");
+
+ auto mucWindow = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(mucJID, uiEventStream_).Return(mucWindow);
+ uiEventStream_->send(std::make_shared<JoinMUCUIEvent>(mucJID, participantB.getResource()));
+ CPPUNIT_ASSERT_EQUAL(true, mucWindow->mucType_.is_initialized());
+
+ auto window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(participantA, uiEventStream_).Return(window);
+ uiEventStream_->send(std::make_shared<RequestChatUIEvent>(participantA));
+ CPPUNIT_ASSERT_EQUAL(false, window->mucType_.is_initialized());
+
+ Presence::ref presence = Presence::create();
+ presence->setFrom(participantA);
+ presence->setShow(StatusShow::Online);
+ stanzaChannel_->onPresenceReceived(presence);
+ CPPUNIT_ASSERT_EQUAL(std::string("participantA has become available."), MockChatWindow::bodyFromMessage(window->lastAddedPresence_));
+
+ // send message to participantA
+ auto messageBody = std::string("message body to send");
+ window->onSendMessageRequest(messageBody, false);
+ auto sendMessageStanza = stanzaChannel_->getStanzaAtIndex<Message>(3);
+ CPPUNIT_ASSERT_EQUAL(messageBody, *sendMessageStanza->getBody());
+
+ // receive reply with error
+ auto messageErrorReply = std::make_shared<Message>();
+ messageErrorReply->setID(stanzaChannel_->getNewIQID());
+ messageErrorReply->setType(Message::Error);
+ messageErrorReply->setFrom(participantA);
+ messageErrorReply->setTo(jid_);
+ messageErrorReply->addPayload(std::make_shared<ErrorPayload>(ErrorPayload::ItemNotFound, ErrorPayload::Cancel, "Recipient not in room"));
+
+ auto lastMUCWindowErrorMessageBeforeError = MockChatWindow::bodyFromMessage(mucWindow->lastAddedErrorMessage_);
+ manager_->handleIncomingMessage(messageErrorReply);
+
+ // assert that error is not routed to MUC window
+ CPPUNIT_ASSERT_EQUAL(lastMUCWindowErrorMessageBeforeError, MockChatWindow::bodyFromMessage(mucWindow->lastAddedErrorMessage_));
+ // assert that error is routed to PM
+ CPPUNIT_ASSERT_EQUAL(std::string("This user could not be found in the room."), MockChatWindow::bodyFromMessage(window->lastAddedErrorMessage_));
+ }
+
+ void testLocalMUCServiceDiscoveryResetOnDisconnect() {
+ JID ownJID("test@test.com/resource");
+ JID sender("foo@test.com");
+
+ manager_->setOnline(true);
+
+ // Open chat window to a sender.
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(sender, uiEventStream_).Return(window);
+
+ uiEventStream_->send(std::make_shared<RequestChatUIEvent>(sender));
+
+ CPPUNIT_ASSERT_EQUAL(false, window->impromptuMUCSupported_);
+
+ std::shared_ptr<IQ> infoRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[1]);
+ std::shared_ptr<IQ> infoResponse = IQ::createResult(infoRequest->getFrom(), infoRequest->getTo(), infoRequest->getID());
+
+ DiscoInfo info;
+ info.addIdentity(DiscoInfo::Identity("Shakespearean Chat Service", "conference", "text"));
+ info.addFeature("http://jabber.org/protocol/muc");
+ infoResponse->addPayload(std::make_shared<DiscoInfo>(info));
+ stanzaChannel_->onIQReceived(infoResponse);
+
+ CPPUNIT_ASSERT_EQUAL(true, window->impromptuMUCSupported_);
+ manager_->setOnline(false);
+ CPPUNIT_ASSERT_EQUAL(false, window->impromptuMUCSupported_);
+ }
+
+ void testhelperChatControllerPresenceAccessUpdatedOnSubscriptionChangeReceiptsAllowed(RosterItemPayload::Subscription from, RosterItemPayload::Subscription to) {
+ JID messageJID("testling@test.com/resource1");
+ xmppRoster_->addContact(messageJID, "foo", std::vector<std::string>(), from);
+
+ MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
+ settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, true);
+
+ std::shared_ptr<Message> message = makeDeliveryReceiptTestMessage(messageJID, "1");
+ manager_->handleIncomingMessage(message);
+
+ CPPUNIT_ASSERT_EQUAL(st(0), stanzaChannel_->countSentStanzaOfType<Message>());
+
+ xmppRoster_->addContact(messageJID, "foo", std::vector<std::string>(), to);
+ message->setID("2");
+ manager_->handleIncomingMessage(message);
+
+ CPPUNIT_ASSERT_EQUAL(st(1), stanzaChannel_->countSentStanzaOfType<Message>());
+ Stanza::ref stanzaContactOnRoster = stanzaChannel_->getStanzaAtIndex<Stanza>(1);
+ CPPUNIT_ASSERT(stanzaContactOnRoster->getPayload<DeliveryReceipt>() != nullptr);
+ }
+
+ void testChatControllerHighlightingNotificationTesting() {
+ HighlightConfiguration::KeywordHightlight keywordRuleA;
+ keywordRuleA.keyword = "Romeo";
+ keywordRuleA.action.setFrontColor(boost::optional<std::string>("yellow"));
+ keywordRuleA.action.setSoundFilePath(boost::optional<std::string>(""));
+ highlightManager_->getConfiguration()->keywordHighlights.push_back(keywordRuleA);
+
+ HighlightConfiguration::KeywordHightlight keywordRuleB;
+ keywordRuleB.keyword = "Juliet";
+ keywordRuleB.action.setFrontColor(boost::optional<std::string>("green"));
+ keywordRuleB.action.setSoundFilePath(boost::optional<std::string>("/tmp/someotherfile.wav"));
+ highlightManager_->getConfiguration()->keywordHighlights.push_back(keywordRuleB);
+
+ JID messageJID = JID("testling@test.com");
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
+
+ std::shared_ptr<Message> message(new Message());
+ message->setFrom(messageJID);
+ std::string body("This message should cause two sounds: Juliet and Romeo.");
+ message->setBody(body);
+ manager_->handleIncomingMessage(message);
+
+ CPPUNIT_ASSERT_EQUAL(2, handledHighlightActions_);
+ CPPUNIT_ASSERT(soundsPlayed_.find(keywordRuleA.action.getSoundFilePath().get_value_or("")) != soundsPlayed_.end());
+ CPPUNIT_ASSERT(soundsPlayed_.find(keywordRuleB.action.getSoundFilePath().get_value_or("")) != soundsPlayed_.end());
+ CPPUNIT_ASSERT_EQUAL(size_t(1), notifier_->notifications.size());
+ }
+
+ void testChatControllerHighlightingNotificationDeduplicateSounds() {
+ auto keywordRuleA = HighlightConfiguration::KeywordHightlight();
+ keywordRuleA.keyword = "Romeo";
+ keywordRuleA.action.setFrontColor(boost::optional<std::string>("yellow"));
+ keywordRuleA.action.setSoundFilePath(boost::optional<std::string>(""));
+ highlightManager_->getConfiguration()->keywordHighlights.push_back(keywordRuleA);
+
+ auto keywordRuleB = HighlightConfiguration::KeywordHightlight();
+ keywordRuleB.keyword = "Juliet";
+ keywordRuleB.action.setFrontColor(boost::optional<std::string>("green"));
+ keywordRuleB.action.setSoundFilePath(boost::optional<std::string>(""));
+ highlightManager_->getConfiguration()->keywordHighlights.push_back(keywordRuleB);
+
+ JID messageJID = JID("testling@test.com");
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
+
+ std::shared_ptr<Message> message(new Message());
+ message->setFrom(messageJID);
+ std::string body("This message should cause one sound, because both actions have the same sound: Juliet and Romeo.");
+ message->setBody(body);
+ manager_->handleIncomingMessage(message);
+
+ CPPUNIT_ASSERT_EQUAL(1, handledHighlightActions_);
+ CPPUNIT_ASSERT(soundsPlayed_.find(keywordRuleA.action.getSoundFilePath().get_value_or("")) != soundsPlayed_.end());
+ CPPUNIT_ASSERT(soundsPlayed_.find(keywordRuleB.action.getSoundFilePath().get_value_or("")) != soundsPlayed_.end());
+ CPPUNIT_ASSERT_EQUAL(size_t(1), notifier_->notifications.size());
+ }
+
+ void testChatControllerHighlightingNotificationKeyword() {
+ auto keywordRuleA = HighlightConfiguration::KeywordHightlight();
+ keywordRuleA.keyword = "Swift";
+ keywordRuleA.action.setFrontColor(boost::optional<std::string>("yellow"));
+ keywordRuleA.action.setSoundFilePath(boost::optional<std::string>(""));
+ keywordRuleA.action.setSystemNotificationEnabled(true);
+ highlightManager_->getConfiguration()->keywordHighlights.push_back(keywordRuleA);
+
+ JID messageJID = JID("testling@test.com");
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
+
+ std::shared_ptr<Message> message(new Message());
+ message->setFrom(messageJID);
+ std::string body("Let's see if the Swift highlight kicks off a system notification.");
+ message->setBody(body);
+ manager_->handleIncomingMessage(message);
+
+ CPPUNIT_ASSERT_EQUAL(size_t(2), notifier_->notifications.size());
+ }
+
+ void testChatControllerMeMessageHandling() {
+ JID messageJID("testling@test.com/resource1");
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
+
+ std::shared_ptr<Message> message(new Message());
+ message->setFrom(messageJID);
+ std::string body("/me is feeling delighted.");
+ message->setBody(body);
+ manager_->handleIncomingMessage(message);
+ CPPUNIT_ASSERT_EQUAL(std::string("is feeling delighted."), window->bodyFromMessage(window->lastAddedAction_));
+ }
+
+ void testRestartingMUCComponentCrash() {
+ JID mucJID = JID("teaparty@rooms.wonderland.lit");
+ JID self = JID("girl@wonderland.lit/rabbithole");
+ std::string nick = "aLiCe";
+
+ MockChatWindow* window;
+
+ auto genRemoteMUCPresence = [=]() {
+ auto presence = Presence::create();
+ presence->setFrom(mucJID.withResource(nick));
+ presence->setTo(self);
+ return presence;
+ };
+
+ // User rejoins.
+ window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(mucJID, uiEventStream_).Return(window);
+
+ // Join room
+ {
+ auto joinRoomEvent = std::make_shared<JoinMUCUIEvent>(mucJID, boost::optional<std::string>(), nick);
+ uiEventStream_->send(joinRoomEvent);
+ }
+
+ {
+ auto firstPresence = genRemoteMUCPresence();
+ firstPresence->setType(Presence::Unavailable);
+ auto userPayload = std::make_shared<MUCUserPayload>();
+ userPayload->addItem(MUCItem(MUCOccupant::Owner, MUCOccupant::NoRole));
+ firstPresence->addPayload(userPayload);
+ stanzaChannel_->onPresenceReceived(firstPresence);
+ }
+ CPPUNIT_ASSERT_EQUAL(std::string("Couldn't enter room: Unable to enter this room."), MockChatWindow::bodyFromMessage(window->lastAddedErrorMessage_));
+
+ {
+ auto presence = genRemoteMUCPresence();
+ presence->setType(Presence::Unavailable);
+ auto userPayload = std::make_shared<MUCUserPayload>();
+ userPayload->addStatusCode(303);
+ auto item = MUCItem(MUCOccupant::Owner, self, MUCOccupant::Moderator);
+ item.nick = nick;
+ userPayload->addItem(item);
+ userPayload->addStatusCode(110);
+ presence->addPayload(userPayload);
+ stanzaChannel_->onPresenceReceived(presence);
+ }
+ }
+
+ void testChatControllerMeMessageHandlingInMUC() {
+ JID mucJID("mucroom@rooms.test.com");
+ std::string nickname = "toodles";
+
+ //highlightManager_->resetToDefaultConfiguration();
+
+ // add highlight rule for 'foo'
+ HighlightConfiguration::KeywordHightlight keywordHighlight;
+ keywordHighlight.keyword = "foo";
+ keywordHighlight.action.setBackColor(boost::optional<std::string>("green"));
+ highlightManager_->getConfiguration()->keywordHighlights.push_back(keywordHighlight);
+
+ HighlightConfiguration::KeywordHightlight keywordHighlightNotification;
+ keywordHighlightNotification.keyword = "Swift";
+ keywordHighlightNotification.action.setBackColor(boost::optional<std::string>("green"));
+ keywordHighlightNotification.action.setSystemNotificationEnabled(true);
+ highlightManager_->getConfiguration()->keywordHighlights.push_back(keywordHighlightNotification);
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(mucJID, uiEventStream_).Return(window);
+
+ uiEventStream_->send(std::make_shared<JoinMUCUIEvent>(mucJID, boost::optional<std::string>(), nickname));
+
+ auto genRemoteMUCPresence = [=]() {
+ auto presence = Presence::create();
+ presence->setFrom(mucJID.withResource(nickname));
+ presence->setTo(jid_);
+ return presence;
+ };
+
+ {
+ auto presence = genRemoteMUCPresence();
+ auto userPayload = std::make_shared<MUCUserPayload>();
+ userPayload->addStatusCode(110);
+ userPayload->addItem(MUCItem(MUCOccupant::Owner, jid_, MUCOccupant::Moderator));
+ presence->addPayload(userPayload);
+ stanzaChannel_->onPresenceReceived(presence);
+ }
+
+ {
+ auto presence = genRemoteMUCPresence();
+ presence->setFrom(mucJID.withResource("someDifferentNickname"));
+ auto userPayload = std::make_shared<MUCUserPayload>();
+ userPayload->addItem(MUCItem(MUCOccupant::Member, JID("foo@bar.com"), MUCOccupant::Moderator));
+ presence->addPayload(userPayload);
+ stanzaChannel_->onPresenceReceived(presence);
+ }
+
+ window->onSendMessageRequest("/me sends a test message with foo", false);
+
+ window->resetLastMessages();
+ {
+ Message::ref mucMirrored = std::make_shared<Message>();
+ mucMirrored->setFrom(mucJID.withResource(nickname));
+ mucMirrored->setTo(jid_);
+ mucMirrored->setType(Message::Groupchat);
+ mucMirrored->setBody("/me sends a test message with foo");
+ manager_->handleIncomingMessage(mucMirrored);
+ }
+ CPPUNIT_ASSERT_EQUAL(std::string("sends a test message with foo"), window->bodyFromMessage(window->lastAddedAction_));
+
+ window->resetLastMessages();
+ {
+ Message::ref mucMirrored = std::make_shared<Message>();
+ mucMirrored->setFrom(mucJID.withResource("someDifferentNickname"));
+ mucMirrored->setTo(jid_);
+ mucMirrored->setType(Message::Groupchat);
+ mucMirrored->setBody("/me says hello with a test message with foo and foo");
+ manager_->handleIncomingMessage(mucMirrored);
+ }
+ CPPUNIT_ASSERT_EQUAL(std::string("says hello with a test message with foo and foo"), window->bodyFromMessage(window->lastAddedAction_));
+
+ window->resetLastMessages();
+ {
+ Message::ref keywordMessage = std::make_shared<Message>();
+ keywordMessage->setFrom(mucJID.withResource("someOtherDifferentNickname"));
+ keywordMessage->setTo(jid_);
+ keywordMessage->setType(Message::Groupchat);
+ keywordMessage->setBody("Let's mention Swift and see what happens.");
+ manager_->handleIncomingMessage(keywordMessage);
+ }
+ CPPUNIT_ASSERT_EQUAL(std::string("Let's mention Swift and see what happens."), window->bodyFromMessage(window->lastAddedMessage_));
+ CPPUNIT_ASSERT_EQUAL(size_t(1), notifier_->notifications.size());
+ }
+
+ void testPresenceChangeDoesNotReplaceMUCInvite() {
+ JID messageJID("testling@test.com/resource1");
+
+ auto generateIncomingPresence = [=](Presence::Type type) {
+ auto presence = std::make_shared<Presence>();
+ presence->setType(type);
+ presence->setFrom(messageJID);
+ presence->setTo(jid_);
+ return presence;
+ };
+
+ stanzaChannel_->onPresenceReceived(generateIncomingPresence(Presence::Available));
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
+
+ std::shared_ptr<Message> message(new Message());
+ message->setFrom(messageJID);
+ std::string body("This is a legible message. >HEH@)oeueu");
+ message->setBody(body);
+ manager_->handleIncomingMessage(message);
+ CPPUNIT_ASSERT_EQUAL(body, MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+
+ auto incomingMUCInvite = std::make_shared<Message>();
+ incomingMUCInvite->setFrom(messageJID);
+
+ auto invitePayload = std::make_shared<MUCInvitationPayload>();
+ invitePayload->setJID("room@muc.service.com");
+ incomingMUCInvite->addPayload(invitePayload);
+
+ stanzaChannel_->onPresenceReceived(generateIncomingPresence(Presence::Unavailable));
+ stanzaChannel_->onPresenceReceived(generateIncomingPresence(Presence::Available));
+
+ window->resetLastMessages();
+
+ manager_->handleIncomingMessage(incomingMUCInvite);
+ CPPUNIT_ASSERT_EQUAL(JID("room@muc.service.com"), window->lastMUCInvitationJID_);
+
+ stanzaChannel_->onPresenceReceived(generateIncomingPresence(Presence::Unavailable));
+ CPPUNIT_ASSERT_EQUAL(std::string(""), MockChatWindow::bodyFromMessage(window->lastReplacedLastMessage_));
+ CPPUNIT_ASSERT_EQUAL(std::string("testling@test.com has gone offline."), MockChatWindow::bodyFromMessage(window->lastAddedPresence_));
+ }
+
+ void testNotSplittingMUCPresenceJoinLeaveLinesOnChatStateNotifications() {
+ JID mucJID("mucroom@rooms.test.com");
+ std::string nickname = "toodles";
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(mucJID, uiEventStream_).Return(window);
+
+ uiEventStream_->send(std::make_shared<JoinMUCUIEvent>(mucJID, boost::optional<std::string>(), nickname));
+
+ auto genRemoteMUCPresence = [=]() {
+ auto presence = Presence::create();
+ presence->setFrom(mucJID.withResource(nickname));
+ presence->setTo(jid_);
+ return presence;
+ };
+
+ {
+ auto presence = genRemoteMUCPresence();
+ auto userPayload = std::make_shared<MUCUserPayload>();
+ userPayload->addStatusCode(110);
+ userPayload->addItem(MUCItem(MUCOccupant::Owner, jid_, MUCOccupant::Moderator));
+ presence->addPayload(userPayload);
+ stanzaChannel_->onPresenceReceived(presence);
+ }
+
+ {
+ auto presence = genRemoteMUCPresence();
+ presence->setFrom(mucJID.withResource("someDifferentNickname"));
+ auto userPayload = std::make_shared<MUCUserPayload>();
+ presence->addPayload(userPayload);
+ stanzaChannel_->onPresenceReceived(presence);
+ }
+ CPPUNIT_ASSERT_EQUAL(std::string("someDifferentNickname has entered the room."), window->bodyFromMessage(window->lastAddedPresence_));
+ CPPUNIT_ASSERT_EQUAL(std::string(), window->bodyFromMessage(window->lastReplacedLastMessage_));
+ window->resetLastMessages();
+
+ {
+ auto presence = genRemoteMUCPresence();
+ presence->setFrom(mucJID.withResource("Romeo"));
+ auto userPayload = std::make_shared<MUCUserPayload>();
+ presence->addPayload(userPayload);
+ stanzaChannel_->onPresenceReceived(presence);
+ }
+ CPPUNIT_ASSERT_EQUAL(std::string(), window->bodyFromMessage(window->lastAddedPresence_));
+ CPPUNIT_ASSERT_EQUAL(std::string("someDifferentNickname and Romeo have entered the room"), window->bodyFromMessage(window->lastReplacedLastMessage_));
+ window->resetLastMessages();
+
+ {
+ auto message = std::make_shared<Message>();
+ message->setFrom(mucJID.withResource("Romeo"));
+ message->setTo(mucJID);
+ message->setType(Message::Groupchat);
+ message->addPayload(std::make_shared<ChatState>(ChatState::Composing));
+ manager_->handleIncomingMessage(message);
+ }
+
+ {
+ auto presence = genRemoteMUCPresence();
+ presence->setFrom(mucJID.withResource("Juliet"));
+ auto userPayload = std::make_shared<MUCUserPayload>();
+ presence->addPayload(userPayload);
+ stanzaChannel_->onPresenceReceived(presence);
+ }
+ CPPUNIT_ASSERT_EQUAL(std::string(), window->bodyFromMessage(window->lastAddedPresence_));
+ CPPUNIT_ASSERT_EQUAL(std::string("someDifferentNickname, Romeo and Juliet have entered the room"), window->bodyFromMessage(window->lastReplacedLastMessage_));
+ }
+
+ template <typename CarbonsType>
+ Message::ref createCarbonsMessage(std::shared_ptr<CarbonsType> carbons, std::shared_ptr<Message> forwardedMessage) {
+ auto messageWrapper = std::make_shared<Message>();
+ messageWrapper->setFrom(jid_.toBare());
+ messageWrapper->setTo(jid_);
+ messageWrapper->setType(Message::Chat);
+
+ messageWrapper->addPayload(carbons);
+ auto forwarded = std::make_shared<Forwarded>();
+ carbons->setForwarded(forwarded);
+ forwarded->setStanza(forwardedMessage);
+ return messageWrapper;
+ }
+
+ void testCarbonsForwardedIncomingMessageToSecondResource() {
+ JID messageJID("testling@test.com/resource1");
+ JID jid2 = jid_.toBare().withResource("someOtherResource");
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
+
+ std::shared_ptr<Message> message(new Message());
+ message->setFrom(messageJID);
+ std::string body("This is a legible message. >HEH@)oeueu");
+ message->setBody(body);
+ manager_->handleIncomingMessage(message);
+ CPPUNIT_ASSERT_EQUAL(body, MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+
+ // incoming carbons message from another resource
+ {
+ auto originalMessage = std::make_shared<Message>();
+ originalMessage->setFrom(messageJID);
+ originalMessage->setTo(jid2);
+ originalMessage->setType(Message::Chat);
+ std::string forwardedBody = "Some further text.";
+ originalMessage->setBody(forwardedBody);
+
+ auto messageWrapper = createCarbonsMessage(std::make_shared<CarbonsReceived>(), originalMessage);
+
+ manager_->handleIncomingMessage(messageWrapper);
+
+ CPPUNIT_ASSERT_EQUAL(forwardedBody, MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+ CPPUNIT_ASSERT_EQUAL(false, window->lastAddedMessageSenderIsSelf_);
+
+ auto recentChats = manager_->getRecentChats();
+ CPPUNIT_ASSERT_EQUAL(recentChats.size(), size_t(1));
+ CPPUNIT_ASSERT_EQUAL(recentChats[0].jid, originalMessage->getFrom().toBare());
+ CPPUNIT_ASSERT_EQUAL(recentChats[0].activity, std::string("Some further text."));
+ }
+ }
+
+ void testCarbonsForwardedOutgoingMessageFromSecondResource() {
+ JID messageJID("testling@test.com/resource1");
+ JID jid2 = jid_.toBare().withResource("someOtherResource");
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
+
+ std::shared_ptr<Message> message(new Message());
+ message->setFrom(messageJID);
+ std::string body("This is a legible message. >HEH@)oeueu");
+ message->setBody(body);
+ manager_->handleIncomingMessage(message);
+ CPPUNIT_ASSERT_EQUAL(body, MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+
+ // incoming carbons message from another resource
+ {
+ auto originalMessage = std::make_shared<Message>();
+ originalMessage->setFrom(jid2);
+ originalMessage->setTo(messageJID);
+ originalMessage->setType(Message::Chat);
+ originalMessage->setID("abcdefg123456");
+ std::string forwardedBody = "Some text my other resource sent.";
+ originalMessage->setBody(forwardedBody);
+ originalMessage->addPayload(std::make_shared<DeliveryReceiptRequest>());
+
+ auto messageWrapper = createCarbonsMessage(std::make_shared<CarbonsSent>(), originalMessage);
+
+ manager_->handleIncomingMessage(messageWrapper);
+
+ CPPUNIT_ASSERT_EQUAL(forwardedBody, MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+ CPPUNIT_ASSERT_EQUAL(true, window->lastAddedMessageSenderIsSelf_);
+ CPPUNIT_ASSERT_EQUAL(size_t(1), window->receiptChanges_.size());
+ CPPUNIT_ASSERT_EQUAL(ChatWindow::ReceiptRequested, window->receiptChanges_[0].second);
+
+ auto recentChats = manager_->getRecentChats();
+ CPPUNIT_ASSERT_EQUAL(recentChats.size(), size_t(1));
+ CPPUNIT_ASSERT_EQUAL(recentChats[0].jid, originalMessage->getTo().toBare());
+ CPPUNIT_ASSERT_EQUAL(recentChats[0].activity, std::string("Some text my other resource sent."));
+ }
+
+ // incoming carbons message for the received delivery receipt to the other resource
+ {
+ auto originalMessage = std::make_shared<Message>();
+ originalMessage->setFrom(messageJID);
+ originalMessage->setTo(jid2);
+ originalMessage->setType(Message::Chat);
+ originalMessage->addPayload(std::make_shared<DeliveryReceipt>("abcdefg123456"));
+
+ auto messageWrapper = createCarbonsMessage(std::make_shared<CarbonsReceived>(), originalMessage);
+
+ manager_->handleIncomingMessage(messageWrapper);
+
+ CPPUNIT_ASSERT_EQUAL(size_t(2), window->receiptChanges_.size());
+ CPPUNIT_ASSERT_EQUAL(ChatWindow::ReceiptReceived, window->receiptChanges_[1].second);
+
+ //Delivery receipt should not change the latest recent entry. Checking for the original message.
+ auto recentChats = manager_->getRecentChats();
+ CPPUNIT_ASSERT_EQUAL(recentChats.size(), size_t(1));
+ CPPUNIT_ASSERT_EQUAL(recentChats[0].jid, messageJID.toBare());
+ CPPUNIT_ASSERT_EQUAL(recentChats[0].activity, std::string("Some text my other resource sent."));
+ }
+ }
+
+ void testCarbonsForwardedIncomingDuplicates() {
+ JID messageJID("testling@test.com/resource1");
+ JID jid2 = jid_.toBare().withResource("someOtherResource");
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
+
+ std::shared_ptr<Message> message(new Message());
+ message->setFrom(messageJID);
+ std::string body("This is a legible message. >HEH@)oeueu");
+ message->setBody(body);
+ manager_->handleIncomingMessage(message);
+ CPPUNIT_ASSERT_EQUAL(body, MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+
+ // incoming carbons message from another resource and duplicate of it
+ {
+ auto originalMessage = std::make_shared<Message>();
+ originalMessage->setFrom(messageJID);
+ originalMessage->setTo(jid2);
+ originalMessage->setID("BDD82F0B-2523-48BF-B8CA-17B23A314BC2");
+ originalMessage->setType(Message::Chat);
+ std::string forwardedBody = "Some further text.";
+ originalMessage->setBody(forwardedBody);
+
+ auto messageWrapper = createCarbonsMessage(std::make_shared<CarbonsReceived>(), originalMessage);
+
+ manager_->handleIncomingMessage(messageWrapper);
+
+ CPPUNIT_ASSERT_EQUAL(forwardedBody, MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+ CPPUNIT_ASSERT_EQUAL(false, window->lastAddedMessageSenderIsSelf_);
+ window->resetLastMessages();
+
+ messageWrapper = createCarbonsMessage(std::make_shared<CarbonsReceived>(), originalMessage);
+ manager_->handleIncomingMessage(messageWrapper);
+ CPPUNIT_ASSERT_EQUAL(std::string(), MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+ CPPUNIT_ASSERT_EQUAL(false, window->lastAddedMessageSenderIsSelf_);
+
+ auto recentChats = manager_->getRecentChats();
+ CPPUNIT_ASSERT_EQUAL(recentChats.size(), size_t(1));
+ CPPUNIT_ASSERT_EQUAL(recentChats[0].jid, originalMessage->getFrom().toBare());
+ CPPUNIT_ASSERT_EQUAL(recentChats[0].activity, std::string("Some further text."));
+ }
+ }
+
+ /**
+ * This test case ensures correct handling of the ideal case where the replace
+ * message refers to a message with a known ID. This results in the last
+ * message being replaced.
+ */
+ void testChatControllerMessageCorrectionCorrectReplaceID() {
+ JID messageJID("testling@test.com/resource1");
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
+
+ auto message = std::make_shared<Message>();
+ message->setFrom(messageJID);
+ message->setTo(jid_);
+ message->setType(Message::Chat);
+ message->setBody("text before edit");
+ message->setID("someID");
+ manager_->handleIncomingMessage(message);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("text before edit"), MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+
+ message = std::make_shared<Message>();
+ message->setFrom(messageJID);
+ message->setTo(jid_);
+ message->setType(Message::Chat);
+ message->setBody("text after edit");
+ message->addPayload(std::make_shared<Replace>("someID"));
+ manager_->handleIncomingMessage(message);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("text before edit"), MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+ CPPUNIT_ASSERT_EQUAL(std::string("text after edit"), MockChatWindow::bodyFromMessage(window->lastReplacedMessage_));
+ }
+
+ /**
+ * This test case ensures correct handling of the case where the replace
+ * message refers to a message with a unknown ID. The replace message should
+ * be treated like a non-repalce message in this case, with no replacement
+ * occuring.
+ */
+ void testChatControllerMessageCorrectionIncorrectReplaceID() {
+ JID messageJID("testling@test.com/resource1");
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
+
+ auto message = std::make_shared<Message>();
+ message->setFrom(messageJID);
+ message->setTo(jid_);
+ message->setType(Message::Chat);
+ message->setBody("text before edit");
+ message->setID("someID");
+ manager_->handleIncomingMessage(message);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("text before edit"), MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+
+ message = std::make_shared<Message>();
+ message->setFrom(messageJID);
+ message->setTo(jid_);
+ message->setType(Message::Chat);
+ message->setBody("text after failed edit");
+ message->addPayload(std::make_shared<Replace>("wrongID"));
+ manager_->handleIncomingMessage(message);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("text after failed edit"), MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+ CPPUNIT_ASSERT_EQUAL(std::string(""), MockChatWindow::bodyFromMessage(window->lastReplacedMessage_));
+ }
+
+ void testChatControllerMessageCorrectionReplaceBySameResource() {
+ JID messageJID("testling@test.com/resource1");
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
+
+ auto message = std::make_shared<Message>();
+ message->setFrom(messageJID);
+ message->setTo(jid_);
+ message->setType(Message::Chat);
+ message->setBody("text before edit");
+ message->setID("someID");
+ manager_->handleIncomingMessage(message);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("text before edit"), MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+
+ message = std::make_shared<Message>();
+ message->setFrom(messageJID);
+ message->setTo(jid_);
+ message->setType(Message::Chat);
+ message->setBody("text after edit");
+ message->addPayload(std::make_shared<Replace>("someID"));
+ manager_->handleIncomingMessage(message);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("text after edit"), MockChatWindow::bodyFromMessage(window->lastReplacedMessage_));
+ }
+
+ void testChatControllerMessageCorrectionReplaceByOtherResource() {
+ JID messageJID("testling@test.com/resource1");
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
+
+ auto message = std::make_shared<Message>();
+ message->setFrom(messageJID);
+ message->setTo(jid_);
+ message->setType(Message::Chat);
+ message->setBody("text before edit");
+ message->setID("someID");
+ manager_->handleIncomingMessage(message);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("text before edit"), MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+
+ message = std::make_shared<Message>();
+ message->setFrom(messageJID.toBare().withResource("resource2"));
+ message->setTo(jid_);
+ message->setType(Message::Chat);
+ message->setBody("text after edit");
+ message->addPayload(std::make_shared<Replace>("someID"));
+ manager_->handleIncomingMessage(message);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("text after edit"), MockChatWindow::bodyFromMessage(window->lastReplacedMessage_));
+ }
+
+ void testMUCControllerMessageCorrectionNoIDMatchRequired() {
+ JID mucJID("SomeMUCRoom@test.com");
+ manager_->setOnline(true);
+
+ // Open chat window to a sender.
+ MockChatWindow* window = new MockChatWindow();
+
+ std::vector<JID> jids;
+ jids.emplace_back("foo@test.com");
+ jids.emplace_back("bar@test.com");
+
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(mucJID, uiEventStream_).Return(window);
+
+ auto nickname = std::string("SomeNickName");
+ // Join room
+ {
+ auto joinRoomEvent = std::make_shared<JoinMUCUIEvent>(mucJID, boost::optional<std::string>(), nickname);
+ uiEventStream_->send(joinRoomEvent);
+ }
+
+ auto genRemoteMUCPresence = [=]() {
+ auto presence = Presence::create();
+ presence->setFrom(mucJID.withResource(nickname));
+ presence->setTo(jid_);
+ return presence;
+ };
+
+ {
+ auto presence = genRemoteMUCPresence();
+ auto userPayload = std::make_shared<MUCUserPayload>();
+ userPayload->addStatusCode(110);
+ userPayload->addItem(MUCItem(MUCOccupant::Owner, jid_, MUCOccupant::Moderator));
+ presence->addPayload(userPayload);
+ stanzaChannel_->onPresenceReceived(presence);
+ }
+
+ {
+ auto presence = genRemoteMUCPresence();
+ presence->setFrom(mucJID.withResource("someDifferentNickname"));
+ auto userPayload = std::make_shared<MUCUserPayload>();
+ userPayload->addItem(MUCItem(MUCOccupant::Member, JID("foo@bar.com"), MUCOccupant::Moderator));
+ presence->addPayload(userPayload);
+ stanzaChannel_->onPresenceReceived(presence);
+ }
+
+ {
+ Message::ref mucMirrored = std::make_shared<Message>();
+ mucMirrored->setFrom(mucJID.withResource(nickname));
+ mucMirrored->setTo(jid_);
+ mucMirrored->setType(Message::Groupchat);
+ mucMirrored->setID("fooBlaID_1");
+ mucMirrored->setBody("Some misssssspelled message.");
+ manager_->handleIncomingMessage(mucMirrored);
+ }
+ CPPUNIT_ASSERT_EQUAL(std::string("Some misssssspelled message."), window->bodyFromMessage(window->lastAddedMessage_));
+
+ // Replace message with non-matching ID
+ {
+ Message::ref mucMirrored = std::make_shared<Message>();
+ mucMirrored->setFrom(mucJID.withResource(nickname));
+ mucMirrored->setTo(jid_);
+ mucMirrored->setType(Message::Groupchat);
+ mucMirrored->setID("fooBlaID_3");
+ mucMirrored->setBody("Some correctly spelled message.");
+ mucMirrored->addPayload(std::make_shared<Replace>("fooBlaID_2"));
+ manager_->handleIncomingMessage(mucMirrored);
+ }
+ CPPUNIT_ASSERT_EQUAL(std::string("Some correctly spelled message."), window->bodyFromMessage(window->lastReplacedMessage_));
+ }
+
+ void impromptuChatSetup(MockChatWindow* window) {
+ stanzaChannel_->uniqueIDs_ = true;
+ JID mucJID("795B7BBE-9099-4A0D-81BA-C816F78E275C@test.com");
+ manager_->setOnline(true);
+
+ std::shared_ptr<IQ> infoRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[1]);
+ CPPUNIT_ASSERT(infoRequest);
+
+ std::shared_ptr<IQ> infoResponse = IQ::createResult(infoRequest->getFrom(), infoRequest->getTo(), infoRequest->getID());
+
+ DiscoInfo info;
+ info.addIdentity(DiscoInfo::Identity("Shakespearean Chat Service", "conference", "text"));
+ info.addFeature("http://jabber.org/protocol/muc");
+ infoResponse->addPayload(std::make_shared<DiscoInfo>(info));
+ stanzaChannel_->onIQReceived(infoResponse);
+
+ std::vector<JID> jids;
+ jids.emplace_back("foo@test.com");
+ jids.emplace_back("bar@test.com");
+
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(mucJID, uiEventStream_).Return(window);
+ uiEventStream_->send(std::make_shared<CreateImpromptuMUCUIEvent>(jids, mucJID, ""));
+ CPPUNIT_ASSERT_EQUAL(std::string("bar@test.com, foo@test.com"), manager_->getRecentChats()[0].getTitle());
+
+ // Check the MUC security marking request
+ auto mucInfoRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[2]);
+ CPPUNIT_ASSERT(mucInfoRequest);
+
+ auto mucJoinPresence = std::dynamic_pointer_cast<Presence>(stanzaChannel_->sentStanzas[3]);
+ CPPUNIT_ASSERT(mucJoinPresence);
+
+ // MUC presence reply
+ auto mucResponse = Presence::create();
+ mucResponse->setTo(jid_);
+ mucResponse->setFrom(mucJoinPresence->getTo());
+ mucResponse->addPayload([]() {
+ auto mucUser = std::make_shared<MUCUserPayload>();
+ mucUser->addItem(MUCItem(MUCOccupant::Member, MUCOccupant::Participant));
+ mucUser->addStatusCode(MUCUserPayload::StatusCode(110));
+ mucUser->addStatusCode(MUCUserPayload::StatusCode(210));
+ return mucUser;
+ }());
+ stanzaChannel_->onPresenceReceived(mucResponse);
+
+ // Before people join the impromptu room, the title is based on names coming from Roster
+ CPPUNIT_ASSERT_EQUAL(std::string("bar@test.com, foo@test.com"), manager_->getRecentChats()[0].getTitle());
+
+ auto mucParticipantJoined = [&](const JID& jid) {
+ auto participantJoinedPresence = Presence::create();
+ participantJoinedPresence->setTo(jid_);
+ participantJoinedPresence->setFrom(mucJID.withResource(jid.toString()));
+ auto mucUser = std::make_shared<MUCUserPayload>();
+ mucUser->addItem(MUCItem(MUCOccupant::Member, MUCOccupant::Participant));
+ participantJoinedPresence->addPayload(mucUser);
+ return participantJoinedPresence;
+ };
+
+ for (const auto& participantJID : jids) {
+ stanzaChannel_->onPresenceReceived(mucParticipantJoined(participantJID));
+ }
+ }
+
+ void testImpromptuChatTitle() {
+ // Open a new chat window to a sender.
+ MockChatWindow* window = new MockChatWindow();
+ impromptuChatSetup(window);
+ // After people joined, the title is the list of participant nicknames or names coming from Roster (if nicknames are unavailable)
+ CPPUNIT_ASSERT_EQUAL(std::string("bar@test.com, foo@test.com"), manager_->getRecentChats()[0].getTitle());
+ }
+
+ void testImpromptuChatWindowTitle() {
+ // Open a new chat window to a sender.
+ MockChatWindow* window = new MockChatWindow();
+ impromptuChatSetup(window);
+ // After people joined, the title of chat window is combined of participant nicknames or names coming from Roster (if nicknames are unavailable)
+ CPPUNIT_ASSERT_EQUAL(std::string("bar@test.com, foo@test.com"), window->name_);
+ }
+
+ void testStandardMUCChatWindowTitle() {
+ JID mucJID("mucroom@rooms.test.com");
+ std::string nickname = "toodles";
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(mucJID, uiEventStream_).Return(window);
+
+ uiEventStream_->send(std::make_shared<JoinMUCUIEvent>(mucJID, boost::optional<std::string>(), nickname));
+ CPPUNIT_ASSERT_EQUAL(std::string("mucroom"), window->name_);
+ }
+
+ std::shared_ptr<Storage> createBookmarkStorageWithJID(std::shared_ptr<IQ> bookmarkRequest, const JID& jid, const bool autojoin) {
+ CPPUNIT_ASSERT(bookmarkRequest);
+ CPPUNIT_ASSERT_EQUAL(IQ::Get, bookmarkRequest->getType());
+
+ auto privateStorage = bookmarkRequest->getPayload<PrivateStorage>();
+ CPPUNIT_ASSERT(privateStorage);
+
+ auto storage = std::dynamic_pointer_cast<Storage>(privateStorage->getPayload());
+ CPPUNIT_ASSERT(storage);
+
+ auto roomsStorage = std::make_shared<Storage>();
+ if (jid.isValid()) {
+ auto room = Storage::Room();
+ room.jid = jid;
+ room.autoJoin = autojoin;
+ roomsStorage->addRoom(room);
+ }
+ return roomsStorage;
+ }
+
+ void testReceivingBookmarksWithDomainJID() {
+ auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ auto response = IQ::createResult(
+ bookmarkRequest->getFrom(),
+ bookmarkRequest->getTo(),
+ bookmarkRequest->getID(),
+ std::make_shared<PrivateStorage>(createBookmarkStorageWithJID(bookmarkRequest, "montague.lit", true))
+ );
+ stanzaChannel_->onIQReceived(response);
+ }
+
+ void testReceivingBookmarksWithBareJID() {
+ auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID("example@montague.lit"), uiEventStream_).Return(window);
+ auto response = IQ::createResult(
+ bookmarkRequest->getFrom(),
+ bookmarkRequest->getTo(),
+ bookmarkRequest->getID(),
+ std::make_shared<PrivateStorage>(createBookmarkStorageWithJID(bookmarkRequest, "example@montague.lit", true))
+ );
+ stanzaChannel_->onIQReceived(response);
+ }
+
+ void testReceivingNoBookmarks() {
+ auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ auto response = IQ::createResult(
+ bookmarkRequest->getFrom(),
+ bookmarkRequest->getTo(),
+ bookmarkRequest->getID(),
+ std::make_shared<PrivateStorage>()
+ );
+ stanzaChannel_->onIQReceived(response);
+ }
+
+ void testReceivingNullBookmarks() {
+ auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ auto response = IQ::createResult(
+ bookmarkRequest->getFrom(),
+ bookmarkRequest->getTo(),
+ bookmarkRequest->getID(),
+ nullptr
+ );
+ stanzaChannel_->onIQReceived(response);
+ }
+
+ void testReceivingBookmarksError() {
+ auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ auto response = IQ::createError(
+ bookmarkRequest->getFrom(),
+ bookmarkRequest->getTo(),
+ bookmarkRequest->getID(),
+ ErrorPayload::Condition::ServiceUnavailable,
+ ErrorPayload::Type::Cancel,
+ nullptr
+ );
+ stanzaChannel_->onIQReceived(response);
+ }
+
+ void testReceivingBookmarksWithFullJID() {
+ auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ auto response = IQ::createResult(
+ bookmarkRequest->getFrom(),
+ bookmarkRequest->getTo(),
+ bookmarkRequest->getID(),
+ std::make_shared<PrivateStorage>(createBookmarkStorageWithJID(bookmarkRequest, "example@montague.lit/someresource", true))
+ );
+ stanzaChannel_->onIQReceived(response);
+ }
+
+ void testAutoJoinBookmarksAndChattables() {
+
+ auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ auto roomsStorage = createBookmarkStorageWithJID(bookmarkRequest, "autojoin@bookmark.lit", true);
+ auto room = Storage::Room();
+ room.jid = "noAutojoin@bookmark.lit";
+ roomsStorage->addRoom(room);
+
+ //Only autojoin@bookmark.lit window should open.
+ MockChatWindow* autojoinBookmarkWindow = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID("autojoin@bookmark.lit"), uiEventStream_).Return(autojoinBookmarkWindow);
+
+ auto response = IQ::createResult(
+ bookmarkRequest->getFrom(),
+ bookmarkRequest->getTo(),
+ bookmarkRequest->getID(),
+ std::make_shared<PrivateStorage>(roomsStorage)
+ );
+ stanzaChannel_->onIQReceived(response);
+ //Both bookmarks should be added to the chattables.
+ CPPUNIT_ASSERT_EQUAL(size_t(2), chattables_->get().size());
+ auto autoJoinState = chattables_->getState("autojoin@bookmark.lit");
+ CPPUNIT_ASSERT(autoJoinState.type == Chattables::State::Type::Room);
+ CPPUNIT_ASSERT_EQUAL(autoJoinState.status, StatusShow::Online);
+ auto noAutoJoinState = chattables_->getState("noAutojoin@bookmark.lit");
+ CPPUNIT_ASSERT(noAutoJoinState.type == Chattables::State::Type::Room);
+ CPPUNIT_ASSERT_EQUAL(noAutoJoinState.status, StatusShow::None);
+ }
+
+ void testJoinNoAutojoinBookmark() {
+
+ auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ auto roomsStorage = createBookmarkStorageWithJID(bookmarkRequest, "example@montague.lit", false);
+
+ auto response = IQ::createResult(
+ bookmarkRequest->getFrom(),
+ bookmarkRequest->getTo(),
+ bookmarkRequest->getID(),
+ std::make_shared<PrivateStorage>(roomsStorage)
+ );
+ stanzaChannel_->onIQReceived(response);
+
+ //Join previous bookmarked room, expecting no increase in chattables and change of autojoin in bookmark to true
+ MockChatWindow* newExampleChatWindow = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID("example@montague.lit"), uiEventStream_).Return(newExampleChatWindow);
+ uiEventStream_->send(std::make_shared<JoinMUCUIEvent>("example@montague.lit", boost::optional<std::string>(), boost::optional<std::string>()));
+ CPPUNIT_ASSERT_EQUAL(size_t(1), chattables_->get().size());
+ auto state = chattables_->getState("example@montague.lit");
+ CPPUNIT_ASSERT(state.type == Chattables::State::Type::Room);
+ CPPUNIT_ASSERT_EQUAL(state.status, StatusShow::Online);
+
+ auto bookmarks = manager_->getBookmarkManager()->getBookmarks();
+ CPPUNIT_ASSERT_EQUAL(bookmarks.size(), size_t(1));
+ CPPUNIT_ASSERT(bookmarks[0].getRoom() == JID("example@montague.lit"));
+ CPPUNIT_ASSERT(bookmarks[0].getAutojoin());
+ }
+
+ void testJoinAndBookmarkMUC() {
+ auto bookmarkRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[0]);
+ auto roomsStorage = createBookmarkStorageWithJID(bookmarkRequest, "", true);
+ auto response = IQ::createResult(
+ bookmarkRequest->getFrom(),
+ bookmarkRequest->getTo(),
+ bookmarkRequest->getID(),
+ std::make_shared<PrivateStorage>(roomsStorage)
+ );
+ stanzaChannel_->onIQReceived(response);
+
+ //Join non-bookmarked room expecting for the room to get bookmarked with autojoin to true
+ MockChatWindow* exampleChatWindow = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With("example@montague.lit", uiEventStream_).Return(exampleChatWindow);
+ uiEventStream_->send(std::make_shared<JoinMUCUIEvent>("example@montague.lit", boost::optional<std::string>(), boost::optional<std::string>()));
+ {
+ CPPUNIT_ASSERT_EQUAL(size_t(1), chattables_->get().size());
+ auto state = chattables_->getState("example@montague.lit");
+ CPPUNIT_ASSERT(state.type == Chattables::State::Type::Room);
+ CPPUNIT_ASSERT_EQUAL(state.status, StatusShow::Online);
+
+ auto bookmarks = manager_->getBookmarkManager()->getBookmarks();
+ CPPUNIT_ASSERT_EQUAL(bookmarks.size(), size_t(1));
+ CPPUNIT_ASSERT(bookmarks[0].getRoom() == JID("example@montague.lit"));
+ CPPUNIT_ASSERT(bookmarks[0].getAutojoin());
+
+ }
+ //Exiting room that is bookmarked, expecting chattable to stay but bookmark autojoin change to false.
+ exampleChatWindow->onClosed();
+ {
+ CPPUNIT_ASSERT_EQUAL(size_t(1), chattables_->get().size());
+ auto bookmarks = manager_->getBookmarkManager()->getBookmarks();
+ CPPUNIT_ASSERT_EQUAL(bookmarks.size(), size_t(1));
+ CPPUNIT_ASSERT(bookmarks[0].getRoom() == JID("example@montague.lit"));
+ CPPUNIT_ASSERT(!bookmarks[0].getAutojoin());
+ }
+ }
private:
- boost::shared_ptr<Message> makeDeliveryReceiptTestMessage(const JID& from, const std::string& id) {
- boost::shared_ptr<Message> message = boost::make_shared<Message>();
- message->setFrom(from);
- message->setID(id);
- message->setBody("This will cause the window to open");
- message->addPayload(boost::make_shared<DeliveryReceiptRequest>());
- return message;
- }
-
- size_t st(int i) {
- return static_cast<size_t>(i);
- }
+ std::shared_ptr<Message> makeDeliveryReceiptTestMessage(const JID& from, const std::string& id) {
+ std::shared_ptr<Message> message = std::make_shared<Message>();
+ message->setFrom(from);
+ message->setID(id);
+ message->setBody("This will cause the window to open");
+ message->addPayload(std::make_shared<DeliveryReceiptRequest>());
+ return message;
+ }
+
+ size_t st(int i) {
+ return static_cast<size_t>(i);
+ }
+
+ void handleHighlightAction(const HighlightAction& action) {
+ handledHighlightActions_++;
+ if (action.getSoundFilePath()) {
+ soundsPlayed_.insert(action.getSoundFilePath().get_value_or(""));
+ }
+ }
private:
- JID jid_;
- ChatsManager* manager_;
- DummyStanzaChannel* stanzaChannel_;
- IQChannel* iqChannel_;
- IQRouter* iqRouter_;
- EventController* eventController_;
- ChatWindowFactory* chatWindowFactory_;
- JoinMUCWindowFactory* joinMUCWindowFactory_;
- NickResolver* nickResolver_;
- PresenceOracle* presenceOracle_;
- AvatarManager* avatarManager_;
- boost::shared_ptr<DiscoInfo> serverDiscoInfo_;
- XMPPRosterImpl* xmppRoster_;
- PresenceSender* presenceSender_;
- MockRepository* mocks_;
- UIEventStream* uiEventStream_;
- ChatListWindowFactory* chatListWindowFactory_;
- WhiteboardWindowFactory* whiteboardWindowFactory_;
- MUCSearchWindowFactory* mucSearchWindowFactory_;
- MUCRegistry* mucRegistry_;
- DirectedPresenceSender* directedPresenceSender_;
- EntityCapsManager* entityCapsManager_;
- CapsProvider* capsProvider_;
- MUCManager* mucManager_;
- DummySettingsProvider* settings_;
- ProfileSettingsProvider* profileSettings_;
- ChatListWindow* chatListWindow_;
- FileTransferOverview* ftOverview_;
- FileTransferManager* ftManager_;
- WhiteboardSessionManager* wbSessionManager_;
- WhiteboardManager* wbManager_;
- HighlightManager* highlightManager_;
- ClientBlockListManager* clientBlockListManager_;
- std::map<std::string, std::string> emoticons_;
+ JID jid_;
+ std::unique_ptr<DummyNotifier> notifier_;
+ ExtendedChatsManager* manager_;
+ DummyStanzaChannel* stanzaChannel_;
+ IQRouter* iqRouter_;
+ EventController* eventController_;
+ ChatWindowFactory* chatWindowFactory_;
+ JoinMUCWindowFactory* joinMUCWindowFactory_;
+ NickResolver* nickResolver_;
+ PresenceOracle* presenceOracle_;
+ AvatarManager* avatarManager_;
+ EventNotifier* eventNotifier_;
+ std::shared_ptr<DiscoInfo> serverDiscoInfo_;
+ XMPPRosterImpl* xmppRoster_;
+ PresenceSender* presenceSender_;
+ MockRepository* mocks_;
+ UIEventStream* uiEventStream_;
+ ChatListWindowFactory* chatListWindowFactory_;
+ WhiteboardWindowFactory* whiteboardWindowFactory_;
+ MUCSearchWindowFactory* mucSearchWindowFactory_;
+ MUCRegistry* mucRegistry_;
+ DirectedPresenceSender* directedPresenceSender_;
+ DummyEntityCapsProvider* entityCapsProvider_;
+ MUCManager* mucManager_;
+ DummySettingsProvider* settings_;
+ ProfileSettingsProvider* profileSettings_;
+ ChatListWindow* chatListWindow_;
+ FileTransferOverview* ftOverview_;
+ FileTransferManager* ftManager_;
+ WhiteboardSessionManager* wbSessionManager_;
+ WhiteboardManager* wbManager_;
+ HighlightManager* highlightManager_;
+ ClientBlockListManager* clientBlockListManager_;
+ VCardManager* vcardManager_;
+ CryptoProvider* crypto_;
+ VCardStorage* vcardStorage_;
+ std::map<std::string, std::string> emoticons_;
+ int handledHighlightActions_;
+ std::set<std::string> soundsPlayed_;
+ DummyTimerFactory* timerFactory_;
+ std::unique_ptr<Chattables> chattables_;
+
};
CPPUNIT_TEST_SUITE_REGISTRATION(ChatsManagerTest);
-
diff --git a/Swift/Controllers/Chat/UnitTest/ChattablesTest.cpp b/Swift/Controllers/Chat/UnitTest/ChattablesTest.cpp
new file mode 100644
index 0000000..f30e3fd
--- /dev/null
+++ b/Swift/Controllers/Chat/UnitTest/ChattablesTest.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <gtest/gtest.h>
+#include <hippomocks.h>
+
+#include <Swift/Controllers/Chat/Chattables.h>
+
+// Clang wrongly things that tests for 0 are using 0 as null.
+#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
+
+using namespace Swift;
+
+class ChattablesTest : public ::testing::Test {
+ protected:
+ void SetUp() {
+ beginListSize_ = 0;
+ endListSize_ = 0;
+ callsToBegin_ = 0;
+ callsToEnd_ = 0;
+ }
+
+ void TearDown() {
+ }
+
+ void updateBeginListSize(int listSize);
+ void updateEndListSize();
+
+ Chattables chattables_;
+ int beginListSize_;
+ int endListSize_;
+ int callsToBegin_;
+ int callsToEnd_;
+};
+
+void ChattablesTest::updateBeginListSize(int listSize) {
+ beginListSize_ = listSize;
+ callsToBegin_++;
+}
+
+void ChattablesTest::updateEndListSize() {
+ endListSize_ = chattables_.get().size();
+ callsToEnd_++;
+}
+
+TEST_F(ChattablesTest, testAddJID) {
+ chattables_.onBeginAdd.connect([this](int listSize){ updateBeginListSize(listSize); });
+ chattables_.onAdded.connect([this](){ updateEndListSize(); });
+ JID jid("user@swift.jid");
+
+ chattables_.addJID(jid, Chattables::State::Type::Person);
+ ASSERT_EQ(0, beginListSize_);
+ ASSERT_EQ(1, endListSize_);
+ ASSERT_EQ(1, callsToBegin_);
+ ASSERT_EQ(1, callsToEnd_);
+
+ ASSERT_EQ(jid, chattables_.get()[0]);
+ Chattables::State state = chattables_.getState(jid);
+ ASSERT_EQ(jid, state.jid);
+ ASSERT_EQ(Chattables::State::Type::Person, state.type);
+}
+
+TEST_F(ChattablesTest, testAddMultipleJIDs) {
+ chattables_.onBeginAdd.connect([this](int listSize){ updateBeginListSize(listSize); });
+ chattables_.onAdded.connect([this](){ updateEndListSize(); });
+ JID jid0("user0@swift.jid");
+ JID jid1("user1@swift.jid");
+ JID jid2("user2@swift.jid");
+
+ chattables_.addJID(jid0, Chattables::State::Type::Person);
+ ASSERT_EQ(0, beginListSize_);
+ ASSERT_EQ(1, endListSize_);
+ ASSERT_EQ(1, callsToBegin_);
+ ASSERT_EQ(1, callsToEnd_);
+ chattables_.addJID(jid1, Chattables::State::Type::Person);
+ ASSERT_EQ(1, beginListSize_);
+ ASSERT_EQ(2, endListSize_);
+ ASSERT_EQ(2, callsToBegin_);
+ ASSERT_EQ(2, callsToEnd_);
+ chattables_.addJID(jid2, Chattables::State::Type::Person);
+ ASSERT_EQ(2, beginListSize_);
+ ASSERT_EQ(3, endListSize_);
+ ASSERT_EQ(3, callsToBegin_);
+ ASSERT_EQ(3, callsToEnd_);
+}
+
+TEST_F(ChattablesTest, testAddRoomJID) {
+ chattables_.onBeginAdd.connect([this](int listSize){ updateBeginListSize(listSize); });
+ chattables_.onAdded.connect([this](){ updateEndListSize(); });
+ JID jid("room@swift.jid");
+
+ chattables_.addJID(jid, Chattables::State::Type::Room);
+ ASSERT_EQ(0, beginListSize_);
+ ASSERT_EQ(1, endListSize_);
+ ASSERT_EQ(1, callsToBegin_);
+ ASSERT_EQ(1, callsToEnd_);
+
+ ASSERT_EQ(jid, chattables_.get()[0]);
+ Chattables::State state = chattables_.getState(jid);
+ ASSERT_EQ(jid, state.jid);
+ ASSERT_EQ(Chattables::State::Type::Room, state.type);
+}
+
+TEST_F(ChattablesTest, testSetState) {
+ JID jid("user@swift.jid");
+ chattables_.addJID(jid, Chattables::State::Type::Person);
+ ASSERT_EQ(1, chattables_.get().size());
+ ASSERT_EQ(jid, chattables_.get()[0]);
+ ASSERT_EQ(Chattables::State::Type::Person, chattables_.getState(jid).type);
+ ASSERT_EQ(StatusShow::None, chattables_.getState(jid).status);
+
+ JID returnedJID;
+ int returnedIndex;
+ int callsToChanged = 0;
+ chattables_.onChanged.connect([&returnedJID, &returnedIndex, &callsToChanged](const JID& jid, int index){
+ returnedJID = jid;
+ returnedIndex = index;
+ callsToChanged++;
+ });
+
+ Chattables::State newState;
+ newState.jid = jid;
+ newState.type = Chattables::State::Type::Room;
+ newState.status = StatusShow::Online;
+ chattables_.setState(jid, newState);
+
+ auto storedState = chattables_.getState(jid);
+
+ ASSERT_EQ(1, chattables_.get().size());
+ ASSERT_EQ(jid, chattables_.get()[0]);
+ ASSERT_EQ(jid, returnedJID);
+ ASSERT_EQ(0, returnedIndex);
+ ASSERT_EQ(1, callsToChanged);
+ ASSERT_EQ(jid, storedState.jid);
+ ASSERT_EQ(Chattables::State::Type::Room, storedState.type);
+ ASSERT_EQ(StatusShow::Online, storedState.status);
+}
diff --git a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
index 5ca0687..5339c7b 100644
--- a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
@@ -1,371 +1,964 @@
/*
- * Copyright (c) 2010-2013 Kevin Smith
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010-2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
-#include <cppunit/extensions/HelperMacros.h>
-#include <cppunit/extensions/TestFactoryRegistry.h>
#include <boost/algorithm/string.hpp>
+
+#include <memory>
+
+#include <gtest/gtest.h>
#include <hippomocks.h>
-#include "Swift/Controllers/XMPPEvents/EventController.h"
-#include "Swiften/Presence/DirectedPresenceSender.h"
-#include "Swiften/Presence/StanzaChannelPresenceSender.h"
-#include "Swiften/Avatars/NullAvatarManager.h"
-#include "Swift/Controllers/Chat/MUCController.h"
-#include "Swift/Controllers/UIInterfaces/ChatWindow.h"
-#include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h"
-#include "Swiften/Client/NickResolver.h"
-#include "Swiften/Roster/XMPPRoster.h"
-#include "Swift/Controllers/UIEvents/UIEventStream.h"
-#include "Swift/Controllers/UnitTest/MockChatWindow.h"
-#include "Swiften/Client/DummyStanzaChannel.h"
-#include "Swiften/Queries/DummyIQChannel.h"
-#include "Swiften/Presence/PresenceOracle.h"
-#include "Swiften/Network/TimerFactory.h"
-#include "Swiften/Elements/MUCUserPayload.h"
-#include "Swiften/Disco/DummyEntityCapsProvider.h"
-#include <Swiften/VCards/VCardMemoryStorage.h>
+#include <Swiften/Avatars/NullAvatarManager.h>
+#include <Swiften/Client/ClientBlockListManager.h>
+#include <Swiften/Client/DummyStanzaChannel.h>
+#include <Swiften/Client/NickResolver.h>
+#include <Swiften/Crypto/CryptoProvider.h>
#include <Swiften/Crypto/PlatformCryptoProvider.h>
+#include <Swiften/Disco/DummyEntityCapsProvider.h>
+#include <Swiften/Elements/MUCUserPayload.h>
+#include <Swiften/Elements/Thread.h>
+#include <Swiften/MUC/MUCBookmarkManager.h>
+#include <Swiften/MUC/UnitTest/MockMUC.h>
+#include <Swiften/Network/TimerFactory.h>
+#include <Swiften/Presence/DirectedPresenceSender.h>
+#include <Swiften/Presence/PresenceOracle.h>
+#include <Swiften/Presence/StanzaChannelPresenceSender.h>
+#include <Swiften/Queries/DummyIQChannel.h>
+#include <Swiften/Roster/XMPPRoster.h>
+#include <Swiften/Roster/XMPPRosterImpl.h>
#include <Swiften/VCards/VCardManager.h>
-#include <Swift/Controllers/Settings/DummySettingsProvider.h>
+#include <Swiften/VCards/VCardMemoryStorage.h>
+
#include <Swift/Controllers/Chat/ChatMessageParser.h>
+#include <Swift/Controllers/Chat/Chattables.h>
+#include <Swift/Controllers/Chat/MUCController.h>
#include <Swift/Controllers/Chat/UserSearchController.h>
+#include <Swift/Controllers/Roster/GroupRosterItem.h>
+#include <Swift/Controllers/Roster/Roster.h>
+#include <Swift/Controllers/SettingConstants.h>
+#include <Swift/Controllers/Settings/DummySettingsProvider.h>
+#include <Swift/Controllers/UIEvents/UIEventStream.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
+#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/UserSearchWindowFactory.h>
-#include <Swiften/Crypto/CryptoProvider.h>
+#include <Swift/Controllers/UnitTest/MockChatWindow.h>
+#include <Swift/Controllers/XMPPEvents/EventController.h>
+
+// Clang wrongly things that tests for 0 are using 0 as null.
+#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
using namespace Swift;
-class MUCControllerTest : public CppUnit::TestFixture {
- CPPUNIT_TEST_SUITE(MUCControllerTest);
- CPPUNIT_TEST(testJoinPartStringContructionSimple);
- CPPUNIT_TEST(testJoinPartStringContructionMixed);
- CPPUNIT_TEST(testAppendToJoinParts);
- CPPUNIT_TEST(testAddressedToSelf);
- CPPUNIT_TEST(testNotAddressedToSelf);
- CPPUNIT_TEST(testAddressedToSelfBySelf);
- CPPUNIT_TEST(testMessageWithEmptyLabelItem);
- CPPUNIT_TEST(testMessageWithLabelItem);
- CPPUNIT_TEST(testCorrectMessageWithLabelItem);
- CPPUNIT_TEST_SUITE_END();
-
-public:
- void setUp() {
- crypto_ = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create());
- self_ = JID("girl@wonderland.lit/rabbithole");
- nick_ = "aLiCe";
- mucJID_ = JID("teaparty@rooms.wonderland.lit");
- mocks_ = new MockRepository();
- stanzaChannel_ = new DummyStanzaChannel();
- iqChannel_ = new DummyIQChannel();
- iqRouter_ = new IQRouter(iqChannel_);
- eventController_ = new EventController();
- chatWindowFactory_ = mocks_->InterfaceMock<ChatWindowFactory>();
- userSearchWindowFactory_ = mocks_->InterfaceMock<UserSearchWindowFactory>();
- presenceOracle_ = new PresenceOracle(stanzaChannel_);
- presenceSender_ = new StanzaChannelPresenceSender(stanzaChannel_);
- directedPresenceSender_ = new DirectedPresenceSender(presenceSender_);
- uiEventStream_ = new UIEventStream();
- avatarManager_ = new NullAvatarManager();
- TimerFactory* timerFactory = NULL;
- window_ = new MockChatWindow();
- mucRegistry_ = new MUCRegistry();
- entityCapsProvider_ = new DummyEntityCapsProvider();
- settings_ = new DummySettingsProvider();
- highlightManager_ = new HighlightManager(settings_);
- muc_ = boost::make_shared<MUC>(stanzaChannel_, iqRouter_, directedPresenceSender_, mucJID_, mucRegistry_);
- mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(muc_->getJID(), uiEventStream_).Return(window_);
- chatMessageParser_ = new ChatMessageParser(std::map<std::string, std::string>());
- vcardStorage_ = new VCardMemoryStorage(crypto_.get());
- vcardManager_ = new VCardManager(self_, iqRouter_, vcardStorage_);
- controller_ = new MUCController (self_, muc_, boost::optional<std::string>(), nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_, NULL, NULL, mucRegistry_, highlightManager_, chatMessageParser_, false, NULL);
- }
-
- void tearDown() {
- delete vcardManager_;
- delete vcardStorage_;
- delete highlightManager_;
- delete settings_;
- delete entityCapsProvider_;
- delete controller_;
- delete eventController_;
- delete presenceOracle_;
- delete mocks_;
- delete uiEventStream_;
- delete stanzaChannel_;
- delete presenceSender_;
- delete directedPresenceSender_;
- delete iqRouter_;
- delete iqChannel_;
- delete mucRegistry_;
- delete avatarManager_;
- delete chatMessageParser_;
- }
-
- void finishJoin() {
- Presence::ref presence(new Presence());
- presence->setFrom(JID(muc_->getJID().toString() + "/" + nick_));
- MUCUserPayload::ref status(new MUCUserPayload());
- MUCUserPayload::StatusCode code;
- code.code = 110;
- status->addStatusCode(code);
- presence->addPayload(status);
- stanzaChannel_->onPresenceReceived(presence);
- }
-
- void testAddressedToSelf() {
- finishJoin();
- Message::ref message(new Message());
-
- message = Message::ref(new Message());
- message->setFrom(JID(muc_->getJID().toString() + "/otherperson"));
- message->setBody("basic " + nick_ + " test.");
- message->setType(Message::Groupchat);
- controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
- CPPUNIT_ASSERT_EQUAL((size_t)1, eventController_->getEvents().size());
-
- message = Message::ref(new Message());
- message->setFrom(JID(muc_->getJID().toString() + "/otherperson"));
- message->setBody(nick_ + ": hi there");
- message->setType(Message::Groupchat);
- controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
- CPPUNIT_ASSERT_EQUAL((size_t)2, eventController_->getEvents().size());
-
- message->setFrom(JID(muc_->getJID().toString() + "/other"));
- message->setBody("Hi there " + nick_);
- message->setType(Message::Groupchat);
- controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
- CPPUNIT_ASSERT_EQUAL((size_t)3, eventController_->getEvents().size());
-
- message = Message::ref(new Message());
- message->setFrom(JID(muc_->getJID().toString() + "/other2"));
- message->setBody("Hi " + boost::to_lower_copy(nick_) + ".");
- message->setType(Message::Groupchat);
- controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
- CPPUNIT_ASSERT_EQUAL((size_t)4, eventController_->getEvents().size());
-
- message = Message::ref(new Message());
- message->setFrom(JID(muc_->getJID().toString() + "/other3"));
- message->setBody("Hi bert.");
- message->setType(Message::Groupchat);
- controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
- CPPUNIT_ASSERT_EQUAL((size_t)4, eventController_->getEvents().size());
-
- message = Message::ref(new Message());
- message->setFrom(JID(muc_->getJID().toString() + "/other2"));
- message->setBody("Hi " + boost::to_lower_copy(nick_) + "ie.");
- message->setType(Message::Groupchat);
- controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
- CPPUNIT_ASSERT_EQUAL((size_t)4, eventController_->getEvents().size());
- }
-
- void testNotAddressedToSelf() {
- finishJoin();
- Message::ref message(new Message());
- message->setFrom(JID(muc_->getJID().toString() + "/other3"));
- message->setBody("Hi there Hatter");
- message->setType(Message::Groupchat);
- controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
- CPPUNIT_ASSERT_EQUAL((size_t)0, eventController_->getEvents().size());
- }
-
- void testAddressedToSelfBySelf() {
- finishJoin();
- Message::ref message(new Message());
- message->setFrom(JID(muc_->getJID().toString() + "/" + nick_));
- message->setBody("Hi there " + nick_);
- message->setType(Message::Groupchat);
- controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
- CPPUNIT_ASSERT_EQUAL((size_t)0, eventController_->getEvents().size());
- }
-
- void testMessageWithEmptyLabelItem() {
- SecurityLabelsCatalog::Item label;
- label.setSelector("Bob");
- window_->label_ = label;
- boost::shared_ptr<DiscoInfo> features = boost::make_shared<DiscoInfo>();
- features->addFeature(DiscoInfo::SecurityLabelsCatalogFeature);
- controller_->setAvailableServerFeatures(features);
- IQ::ref iq = iqChannel_->iqs_[iqChannel_->iqs_.size() - 1];
- SecurityLabelsCatalog::ref labelPayload = boost::make_shared<SecurityLabelsCatalog>();
- labelPayload->addItem(label);
- IQ::ref result = IQ::createResult(self_, iq->getID(), labelPayload);
- iqChannel_->onIQReceived(result);
- std::string messageBody("agamemnon");
- window_->onSendMessageRequest(messageBody, false);
- boost::shared_ptr<Stanza> rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
- Message::ref message = boost::dynamic_pointer_cast<Message>(rawStanza);
- CPPUNIT_ASSERT_EQUAL(iq->getTo(), result->getFrom());
- CPPUNIT_ASSERT(window_->labelsEnabled_);
- CPPUNIT_ASSERT(stanzaChannel_->isAvailable()); /* Otherwise will prevent sends. */
- CPPUNIT_ASSERT(message);
- CPPUNIT_ASSERT_EQUAL(messageBody, message->getBody());
- CPPUNIT_ASSERT(!message->getPayload<SecurityLabel>());
- }
-
- void testMessageWithLabelItem() {
- SecurityLabel::ref label = boost::make_shared<SecurityLabel>();
- label->setLabel("a");
- SecurityLabelsCatalog::Item labelItem;
- labelItem.setSelector("Bob");
- labelItem.setLabel(label);
- window_->label_ = labelItem;
- boost::shared_ptr<DiscoInfo> features = boost::make_shared<DiscoInfo>();
- features->addFeature(DiscoInfo::SecurityLabelsCatalogFeature);
- controller_->setAvailableServerFeatures(features);
- IQ::ref iq = iqChannel_->iqs_[iqChannel_->iqs_.size() - 1];
- SecurityLabelsCatalog::ref labelPayload = boost::make_shared<SecurityLabelsCatalog>();
- labelPayload->addItem(labelItem);
- IQ::ref result = IQ::createResult(self_, iq->getID(), labelPayload);
- iqChannel_->onIQReceived(result);
- std::string messageBody("agamemnon");
- window_->onSendMessageRequest(messageBody, false);
- boost::shared_ptr<Stanza> rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
- Message::ref message = boost::dynamic_pointer_cast<Message>(rawStanza);
- CPPUNIT_ASSERT_EQUAL(iq->getTo(), result->getFrom());
- CPPUNIT_ASSERT(window_->labelsEnabled_);
- CPPUNIT_ASSERT(stanzaChannel_->isAvailable()); /* Otherwise will prevent sends. */
- CPPUNIT_ASSERT(message);
- CPPUNIT_ASSERT_EQUAL(messageBody, message->getBody());
- CPPUNIT_ASSERT_EQUAL(label, message->getPayload<SecurityLabel>());
- }
-
- void testCorrectMessageWithLabelItem() {
- SecurityLabel::ref label = boost::make_shared<SecurityLabel>();
- label->setLabel("a");
- SecurityLabelsCatalog::Item labelItem;
- labelItem.setSelector("Bob");
- labelItem.setLabel(label);
- SecurityLabel::ref label2 = boost::make_shared<SecurityLabel>();
- label->setLabel("b");
- SecurityLabelsCatalog::Item labelItem2;
- labelItem2.setSelector("Charlie");
- labelItem2.setLabel(label2);
- window_->label_ = labelItem;
- boost::shared_ptr<DiscoInfo> features = boost::make_shared<DiscoInfo>();
- features->addFeature(DiscoInfo::SecurityLabelsCatalogFeature);
- controller_->setAvailableServerFeatures(features);
- IQ::ref iq = iqChannel_->iqs_[iqChannel_->iqs_.size() - 1];
- SecurityLabelsCatalog::ref labelPayload = boost::make_shared<SecurityLabelsCatalog>();
- labelPayload->addItem(labelItem);
- IQ::ref result = IQ::createResult(self_, iq->getID(), labelPayload);
- iqChannel_->onIQReceived(result);
- std::string messageBody("agamemnon");
- window_->onSendMessageRequest(messageBody, false);
- boost::shared_ptr<Stanza> rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
- Message::ref message = boost::dynamic_pointer_cast<Message>(rawStanza);
- CPPUNIT_ASSERT_EQUAL(iq->getTo(), result->getFrom());
- CPPUNIT_ASSERT(window_->labelsEnabled_);
- CPPUNIT_ASSERT(stanzaChannel_->isAvailable()); /* Otherwise will prevent sends. */
- CPPUNIT_ASSERT(message);
- CPPUNIT_ASSERT_EQUAL(messageBody, message->getBody());
- CPPUNIT_ASSERT_EQUAL(label, message->getPayload<SecurityLabel>());
- window_->label_ = labelItem2;
- window_->onSendMessageRequest(messageBody, true);
- rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
- message = boost::dynamic_pointer_cast<Message>(rawStanza);
- CPPUNIT_ASSERT_EQUAL(messageBody, message->getBody());
- CPPUNIT_ASSERT_EQUAL(label, message->getPayload<SecurityLabel>());
- }
-
- void checkEqual(const std::vector<NickJoinPart>& expected, const std::vector<NickJoinPart>& actual) {
- CPPUNIT_ASSERT_EQUAL(expected.size(), actual.size());
- for (size_t i = 0; i < expected.size(); i++) {
- CPPUNIT_ASSERT_EQUAL(expected[i].nick, actual[i].nick);
- CPPUNIT_ASSERT_EQUAL(expected[i].type, actual[i].type);
- }
- }
-
- void testAppendToJoinParts() {
- std::vector<NickJoinPart> list;
- std::vector<NickJoinPart> gold;
- MUCController::appendToJoinParts(list, NickJoinPart("Kev", Join));
- gold.push_back(NickJoinPart("Kev", Join));
- checkEqual(gold, list);
- MUCController::appendToJoinParts(list, NickJoinPart("Remko", Join));
- gold.push_back(NickJoinPart("Remko", Join));
- checkEqual(gold, list);
- MUCController::appendToJoinParts(list, NickJoinPart("Bert", Join));
- gold.push_back(NickJoinPart("Bert", Join));
- checkEqual(gold, list);
- MUCController::appendToJoinParts(list, NickJoinPart("Bert", Part));
- gold[2].type = JoinThenPart;
- checkEqual(gold, list);
- MUCController::appendToJoinParts(list, NickJoinPart("Kev", Part));
- gold[0].type = JoinThenPart;
- checkEqual(gold, list);
- MUCController::appendToJoinParts(list, NickJoinPart("Remko", Part));
- gold[1].type = JoinThenPart;
- checkEqual(gold, list);
- MUCController::appendToJoinParts(list, NickJoinPart("Ernie", Part));
- gold.push_back(NickJoinPart("Ernie", Part));
- checkEqual(gold, list);
- MUCController::appendToJoinParts(list, NickJoinPart("Ernie", Join));
- gold[3].type = PartThenJoin;
- checkEqual(gold, list);
- MUCController::appendToJoinParts(list, NickJoinPart("Kev", Join));
- gold[0].type = Join;
- checkEqual(gold, list);
- MUCController::appendToJoinParts(list, NickJoinPart("Ernie", Part));
- gold[3].type = Part;
- checkEqual(gold, list);
-
- }
-
- void testJoinPartStringContructionSimple() {
- std::vector<NickJoinPart> list;
- list.push_back(NickJoinPart("Kev", Join));
- CPPUNIT_ASSERT_EQUAL(std::string("Kev has entered the room"), MUCController::generateJoinPartString(list, false));
- list.push_back(NickJoinPart("Remko", Part));
- CPPUNIT_ASSERT_EQUAL(std::string("Kev has entered the room and Remko has left the room"), MUCController::generateJoinPartString(list, false));
- list.push_back(NickJoinPart("Bert", Join));
- CPPUNIT_ASSERT_EQUAL(std::string("Kev and Bert have entered the room and Remko has left the room"), MUCController::generateJoinPartString(list, false));
- list.push_back(NickJoinPart("Ernie", Join));
- CPPUNIT_ASSERT_EQUAL(std::string("Kev, Bert and Ernie have entered the room and Remko has left the room"), MUCController::generateJoinPartString(list, false));
- }
-
- void testJoinPartStringContructionMixed() {
- std::vector<NickJoinPart> list;
- list.push_back(NickJoinPart("Kev", JoinThenPart));
- CPPUNIT_ASSERT_EQUAL(std::string("Kev has entered then left the room"), MUCController::generateJoinPartString(list, false));
- list.push_back(NickJoinPart("Remko", Part));
- CPPUNIT_ASSERT_EQUAL(std::string("Remko has left the room and Kev has entered then left the room"), MUCController::generateJoinPartString(list, false));
- list.push_back(NickJoinPart("Bert", PartThenJoin));
- CPPUNIT_ASSERT_EQUAL(std::string("Remko has left the room, Kev has entered then left the room and Bert has left then returned to the room"), MUCController::generateJoinPartString(list, false));
- list.push_back(NickJoinPart("Ernie", JoinThenPart));
- CPPUNIT_ASSERT_EQUAL(std::string("Remko has left the room, Kev and Ernie have entered then left the room and Bert has left then returned to the room"), MUCController::generateJoinPartString(list, false));
- }
-
-private:
- JID self_;
- JID mucJID_;
- MUC::ref muc_;
- std::string nick_;
- DummyStanzaChannel* stanzaChannel_;
- DummyIQChannel* iqChannel_;
- IQRouter* iqRouter_;
- EventController* eventController_;
- ChatWindowFactory* chatWindowFactory_;
- UserSearchWindowFactory* userSearchWindowFactory_;
- MUCController* controller_;
-// NickResolver* nickResolver_;
- PresenceOracle* presenceOracle_;
- AvatarManager* avatarManager_;
- StanzaChannelPresenceSender* presenceSender_;
- DirectedPresenceSender* directedPresenceSender_;
- MockRepository* mocks_;
- UIEventStream* uiEventStream_;
- MockChatWindow* window_;
- MUCRegistry* mucRegistry_;
- DummyEntityCapsProvider* entityCapsProvider_;
- DummySettingsProvider* settings_;
- HighlightManager* highlightManager_;
- ChatMessageParser* chatMessageParser_;
- boost::shared_ptr<CryptoProvider> crypto_;
- VCardManager* vcardManager_;
- VCardMemoryStorage* vcardStorage_;
+class MUCControllerTest : public ::testing::Test {
+
+ protected:
+ void SetUp() {
+ crypto_ = std::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create());
+ self_ = JID("girl@wonderland.lit/rabbithole");
+ nick_ = "aLiCe";
+ mucJID_ = JID("teaparty@rooms.wonderland.lit");
+ mocks_ = new MockRepository();
+ stanzaChannel_ = new DummyStanzaChannel();
+ iqChannel_ = new DummyIQChannel();
+ iqRouter_ = new IQRouter(iqChannel_);
+ eventController_ = new EventController();
+ chatWindowFactory_ = mocks_->InterfaceMock<ChatWindowFactory>();
+ userSearchWindowFactory_ = mocks_->InterfaceMock<UserSearchWindowFactory>();
+ xmppRoster_ = new XMPPRosterImpl();
+ presenceOracle_ = new PresenceOracle(stanzaChannel_, xmppRoster_);
+ presenceSender_ = new StanzaChannelPresenceSender(stanzaChannel_);
+ directedPresenceSender_ = new DirectedPresenceSender(presenceSender_);
+ uiEventStream_ = new UIEventStream();
+ avatarManager_ = new NullAvatarManager();
+ TimerFactory* timerFactory = nullptr;
+ window_ = new MockChatWindow();
+ mucRegistry_ = new MUCRegistry();
+ entityCapsProvider_ = new DummyEntityCapsProvider();
+ settings_ = new DummySettingsProvider();
+ highlightManager_ = new HighlightManager(settings_);
+ highlightManager_->resetToDefaultConfiguration();
+ muc_ = std::make_shared<MockMUC>(mucJID_);
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(muc_->getJID(), uiEventStream_).Return(window_);
+ chatMessageParser_ = std::make_shared<ChatMessageParser>(std::map<std::string, std::string>(), highlightManager_->getConfiguration(), ChatMessageParser::Mode::GroupChat);
+ vcardStorage_ = new VCardMemoryStorage(crypto_.get());
+ vcardManager_ = new VCardManager(self_, iqRouter_, vcardStorage_);
+ nickResolver_ = new NickResolver(self_, xmppRoster_, vcardManager_, mucRegistry_);
+ clientBlockListManager_ = new ClientBlockListManager(iqRouter_);
+ mucBookmarkManager_ = new MUCBookmarkManager(iqRouter_);
+ chattables_ = std::make_unique<Chattables>();
+ controller_ = new MUCController (self_, muc_, boost::optional<std::string>(), nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, nickResolver_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_, nullptr, nullptr, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser_, false, nullptr, vcardManager_, mucBookmarkManager_, settings_, *chattables_);
+ }
+
+ void TearDown() {
+ delete controller_;
+ delete mucBookmarkManager_;
+ delete clientBlockListManager_;
+ delete nickResolver_;
+ delete vcardManager_;
+ delete vcardStorage_;
+ delete highlightManager_;
+ delete settings_;
+ delete entityCapsProvider_;
+ delete eventController_;
+ delete presenceOracle_;
+ delete xmppRoster_;
+ delete mocks_;
+ delete uiEventStream_;
+ delete stanzaChannel_;
+ delete presenceSender_;
+ delete directedPresenceSender_;
+ delete iqRouter_;
+ delete iqChannel_;
+ delete mucRegistry_;
+ delete avatarManager_;
+ }
+
+ void finishJoin() {
+ Presence::ref presence(new Presence());
+ presence->setFrom(JID(muc_->getJID().toString() + "/" + nick_));
+ MUCUserPayload::ref status(new MUCUserPayload());
+ MUCUserPayload::StatusCode code;
+ code.code = 110;
+ status->addStatusCode(code);
+ presence->addPayload(status);
+ stanzaChannel_->onPresenceReceived(presence);
+ }
+
+ void joinCompleted() {
+ std::string messageBody("test message");
+ window_->onSendMessageRequest(messageBody, false);
+ std::shared_ptr<Stanza> rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
+ Message::ref message = std::dynamic_pointer_cast<Message>(rawStanza);
+ ASSERT_TRUE(stanzaChannel_->isAvailable()); /* Otherwise will prevent sends. */
+ ASSERT_TRUE(message);
+ ASSERT_EQ(messageBody, message->getBody().get_value_or(""));
+
+ {
+ Message::ref message = std::make_shared<Message>();
+ message->setType(Message::Groupchat);
+ message->setTo(self_);
+ message->setFrom(mucJID_.withResource("SomeNickname"));
+ message->setID(iqChannel_->getNewIQID());
+ message->setSubject("Initial");
+
+ controller_->handleIncomingMessage(std::make_shared<MessageEvent>(message));
+ }
+ }
+
+ void checkEqual(const std::vector<NickJoinPart>& expected, const std::vector<NickJoinPart>& actual) {
+ ASSERT_EQ(expected.size(), actual.size());
+ for (size_t i = 0; i < expected.size(); i++) {
+ ASSERT_EQ(expected[i].nick, actual[i].nick);
+ ASSERT_EQ(expected[i].type, actual[i].type);
+ }
+ }
+
+ JID jidFromOccupant(const MUCOccupant& occupant) {
+ return JID(mucJID_.toString()+"/"+occupant.getNick());
+ }
+
+ void testRoleAffiliationStatesVerify(const std::map<std::string, MUCOccupant> &occupants) {
+ /* verify that the roster is in sync */
+ GroupRosterItem* group = window_->getRosterModel()->getRoot();
+ for (auto rosterItem : group->getChildren()) {
+ GroupRosterItem* child = dynamic_cast<GroupRosterItem*>(rosterItem);
+ ASSERT_TRUE(child);
+ for (auto childItem : child->getChildren()) {
+ ContactRosterItem* item = dynamic_cast<ContactRosterItem*>(childItem);
+ ASSERT_TRUE(item);
+ std::map<std::string, MUCOccupant>::const_iterator occupant = occupants.find(item->getJID().getResource());
+ ASSERT_TRUE(occupant != occupants.end());
+ ASSERT_TRUE(item->getMUCRole() == occupant->second.getRole());
+ ASSERT_TRUE(item->getMUCAffiliation() == occupant->second.getAffiliation());
+ }
+ }
+ }
+
+ void setMUCSecurityMarking(const std::string& markingValue, const std::string& markingForegroundColorValue, const std::string& markingBackgroundColorValue, const bool includeFormTypeField = true) {
+ auto form = std::make_shared<Form>(Form::Type::ResultType);
+
+ if (includeFormTypeField) {
+ std::shared_ptr<FormField> formTypeField = std::make_shared<FormField>(FormField::Type::HiddenType, "http://jabber.org/protocol/muc#roominfo");
+ formTypeField->setName("FORM_TYPE");
+ form->addField(formTypeField);
+ }
+
+ auto markingField = std::make_shared<FormField>(FormField::Type::TextSingleType, markingValue);
+ auto markingForegroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, markingForegroundColorValue);
+ auto markingBackgroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, markingBackgroundColorValue);
+
+ markingField->setName("x-isode#roominfo_marking");
+ markingForegroundColorField->setName("x-isode#roominfo_marking_fg_color");
+ markingBackgroundColorField->setName("x-isode#roominfo_marking_bg_color");
+
+ form->addField(markingField);
+ form->addField(markingForegroundColorField);
+ form->addField(markingBackgroundColorField);
+
+ auto discoInfoRef = std::make_shared<DiscoInfo>();
+ discoInfoRef->addExtension(form);
+
+ auto infoResponse = IQ::createResult(self_, mucJID_, "test-id", discoInfoRef);
+ iqChannel_->onIQReceived(infoResponse);
+ }
+
+ Message::ref createTestMessageWithoutSecurityLabel() {
+ auto message = std::make_shared<Message>();
+ message->setType(Message::Type::Groupchat);
+ message->setID("test-id");
+ message->setTo(self_);
+ message->setFrom(mucJID_.withResource("TestNickname"));
+ message->setBody("Do Not Read This Message");
+ return message;
+ }
+
+ JID self_;
+ JID mucJID_;
+ MockMUC::ref muc_;
+ std::string nick_;
+ DummyStanzaChannel* stanzaChannel_;
+ DummyIQChannel* iqChannel_;
+ IQRouter* iqRouter_;
+ EventController* eventController_;
+ ChatWindowFactory* chatWindowFactory_;
+ UserSearchWindowFactory* userSearchWindowFactory_;
+ MUCController* controller_;
+ NickResolver* nickResolver_;
+ PresenceOracle* presenceOracle_;
+ AvatarManager* avatarManager_;
+ StanzaChannelPresenceSender* presenceSender_;
+ DirectedPresenceSender* directedPresenceSender_;
+ MockRepository* mocks_;
+ UIEventStream* uiEventStream_;
+ MockChatWindow* window_;
+ MUCRegistry* mucRegistry_;
+ DummyEntityCapsProvider* entityCapsProvider_;
+ DummySettingsProvider* settings_;
+ HighlightManager* highlightManager_;
+ std::shared_ptr<ChatMessageParser> chatMessageParser_;
+ std::shared_ptr<CryptoProvider> crypto_;
+ VCardManager* vcardManager_;
+ VCardMemoryStorage* vcardStorage_;
+ ClientBlockListManager* clientBlockListManager_;
+ MUCBookmarkManager* mucBookmarkManager_;
+ XMPPRoster* xmppRoster_;
+ std::unique_ptr<Chattables> chattables_;
};
-CPPUNIT_TEST_SUITE_REGISTRATION(MUCControllerTest);
+TEST_F(MUCControllerTest, testAddressedToSelf) {
+ finishJoin();
+ Message::ref message(new Message());
+
+ message = Message::ref(new Message());
+ message->setFrom(JID(muc_->getJID().toString() + "/otherperson"));
+ message->setBody("basic " + nick_ + " test.");
+ message->setType(Message::Groupchat);
+ controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
+ ASSERT_EQ(1, eventController_->getEvents().size());
+
+ message = Message::ref(new Message());
+ message->setFrom(JID(muc_->getJID().toString() + "/otherperson"));
+ message->setBody(nick_ + ": hi there");
+ message->setType(Message::Groupchat);
+ controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
+ ASSERT_EQ(2, eventController_->getEvents().size());
+
+ message->setFrom(JID(muc_->getJID().toString() + "/other"));
+ message->setBody("Hi there " + nick_);
+ message->setType(Message::Groupchat);
+ controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
+ ASSERT_EQ(3, eventController_->getEvents().size());
+
+ message = Message::ref(new Message());
+ message->setFrom(JID(muc_->getJID().toString() + "/other2"));
+ message->setBody("Hi " + boost::to_lower_copy(nick_) + ".");
+ message->setType(Message::Groupchat);
+ controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
+
+ // The last message is ignored because self-mention highlights are matched case
+ // sensitive against the nickname.
+ ASSERT_EQ(3, eventController_->getEvents().size());
+
+ message = Message::ref(new Message());
+ message->setFrom(JID(muc_->getJID().toString() + "/other3"));
+ message->setBody("Hi bert.");
+ message->setType(Message::Groupchat);
+ controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
+ ASSERT_EQ(3, eventController_->getEvents().size());
+
+ message = Message::ref(new Message());
+ message->setFrom(JID(muc_->getJID().toString() + "/other2"));
+ message->setBody("Hi " + boost::to_lower_copy(nick_) + "ie.");
+ message->setType(Message::Groupchat);
+ controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
+ ASSERT_EQ(3, eventController_->getEvents().size());
+}
+
+TEST_F(MUCControllerTest, testNotAddressedToSelf) {
+ finishJoin();
+ Message::ref message(new Message());
+ message->setFrom(JID(muc_->getJID().toString() + "/other3"));
+ message->setBody("Hi there Hatter");
+ message->setType(Message::Groupchat);
+ controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
+ ASSERT_EQ(0, eventController_->getEvents().size());
+}
+
+TEST_F(MUCControllerTest, testAddressedToSelfBySelf) {
+ finishJoin();
+ Message::ref message(new Message());
+ message->setFrom(JID(muc_->getJID().toString() + "/" + nick_));
+ message->setBody("Hi there " + nick_);
+ message->setType(Message::Groupchat);
+ controller_->handleIncomingMessage(MessageEvent::ref(new MessageEvent(message)));
+ ASSERT_EQ(0, eventController_->getEvents().size());
+}
+
+TEST_F(MUCControllerTest, testMessageWithEmptyLabelItem) {
+ SecurityLabelsCatalog::Item label;
+ label.setSelector("Bob");
+ window_->label_ = label;
+ std::shared_ptr<DiscoInfo> features = std::make_shared<DiscoInfo>();
+ features->addFeature(DiscoInfo::SecurityLabelsCatalogFeature);
+ controller_->setAvailableServerFeatures(features);
+ IQ::ref iq = iqChannel_->iqs_[iqChannel_->iqs_.size() - 1];
+ SecurityLabelsCatalog::ref labelPayload = std::make_shared<SecurityLabelsCatalog>();
+ labelPayload->addItem(label);
+ IQ::ref result = IQ::createResult(self_, iq->getID(), labelPayload);
+ iqChannel_->onIQReceived(result);
+ std::string messageBody("agamemnon");
+ window_->onSendMessageRequest(messageBody, false);
+ std::shared_ptr<Stanza> rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
+ Message::ref message = std::dynamic_pointer_cast<Message>(rawStanza);
+ ASSERT_EQ(iq->getTo(), result->getFrom());
+ ASSERT_TRUE(window_->labelsEnabled_);
+ ASSERT_TRUE(stanzaChannel_->isAvailable()); /* Otherwise will prevent sends. */
+ ASSERT_TRUE(message);
+ ASSERT_EQ(messageBody, message->getBody().get());
+ ASSERT_FALSE(message->getPayload<SecurityLabel>());
+}
+
+TEST_F(MUCControllerTest, testMessageWithLabelItem) {
+ std::shared_ptr<SecurityLabel> label = std::make_shared<SecurityLabel>();
+ label->setLabel("a");
+ SecurityLabelsCatalog::Item labelItem;
+ labelItem.setSelector("Bob");
+ labelItem.setLabel(label);
+ window_->label_ = labelItem;
+ std::shared_ptr<DiscoInfo> features = std::make_shared<DiscoInfo>();
+ features->addFeature(DiscoInfo::SecurityLabelsCatalogFeature);
+ controller_->setAvailableServerFeatures(features);
+ IQ::ref iq = iqChannel_->iqs_[iqChannel_->iqs_.size() - 1];
+ SecurityLabelsCatalog::ref labelPayload = std::make_shared<SecurityLabelsCatalog>();
+ labelPayload->addItem(labelItem);
+ IQ::ref result = IQ::createResult(self_, iq->getID(), labelPayload);
+ iqChannel_->onIQReceived(result);
+ std::string messageBody("agamemnon");
+ window_->onSendMessageRequest(messageBody, false);
+ std::shared_ptr<Stanza> rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
+ Message::ref message = std::dynamic_pointer_cast<Message>(rawStanza);
+ ASSERT_EQ(iq->getTo(), result->getFrom());
+ ASSERT_TRUE(window_->labelsEnabled_);
+ ASSERT_TRUE(stanzaChannel_->isAvailable()); /* Otherwise will prevent sends. */
+ ASSERT_TRUE(message);
+ ASSERT_EQ(messageBody, message->getBody().get());
+ ASSERT_EQ(label, message->getPayload<SecurityLabel>());
+}
+
+TEST_F(MUCControllerTest, testCorrectMessageWithLabelItem) {
+ std::shared_ptr<SecurityLabel> label = std::make_shared<SecurityLabel>();
+ label->setLabel("a");
+ SecurityLabelsCatalog::Item labelItem;
+ labelItem.setSelector("Bob");
+ labelItem.setLabel(label);
+ std::shared_ptr<SecurityLabel> label2 = std::make_shared<SecurityLabel>();
+ label->setLabel("b");
+ SecurityLabelsCatalog::Item labelItem2;
+ labelItem2.setSelector("Charlie");
+ labelItem2.setLabel(label2);
+ window_->label_ = labelItem;
+ std::shared_ptr<DiscoInfo> features = std::make_shared<DiscoInfo>();
+ features->addFeature(DiscoInfo::SecurityLabelsCatalogFeature);
+ controller_->setAvailableServerFeatures(features);
+ IQ::ref iq = iqChannel_->iqs_[iqChannel_->iqs_.size() - 1];
+ SecurityLabelsCatalog::ref labelPayload = std::make_shared<SecurityLabelsCatalog>();
+ labelPayload->addItem(labelItem);
+ IQ::ref result = IQ::createResult(self_, iq->getID(), labelPayload);
+ iqChannel_->onIQReceived(result);
+ std::string messageBody("agamemnon");
+ window_->onSendMessageRequest(messageBody, false);
+ std::shared_ptr<Stanza> rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
+ Message::ref message = std::dynamic_pointer_cast<Message>(rawStanza);
+ ASSERT_EQ(iq->getTo(), result->getFrom());
+ ASSERT_TRUE(window_->labelsEnabled_);
+ ASSERT_TRUE(stanzaChannel_->isAvailable()); /* Otherwise will prevent sends. */
+ ASSERT_TRUE(message);
+ ASSERT_EQ(messageBody, message->getBody().get());
+ ASSERT_EQ(label, message->getPayload<SecurityLabel>());
+ window_->label_ = labelItem2;
+ window_->onSendMessageRequest(messageBody, true);
+ rawStanza = stanzaChannel_->sentStanzas[stanzaChannel_->sentStanzas.size() - 1];
+ message = std::dynamic_pointer_cast<Message>(rawStanza);
+ ASSERT_EQ(messageBody, message->getBody().get());
+ ASSERT_EQ(label, message->getPayload<SecurityLabel>());
+}
+
+TEST_F(MUCControllerTest, testAppendToJoinParts) {
+ std::vector<NickJoinPart> list;
+ std::vector<NickJoinPart> gold;
+ MUCController::appendToJoinParts(list, NickJoinPart("Kev", Join));
+ gold.push_back(NickJoinPart("Kev", Join));
+ checkEqual(gold, list);
+ MUCController::appendToJoinParts(list, NickJoinPart("Remko", Join));
+ gold.push_back(NickJoinPart("Remko", Join));
+ checkEqual(gold, list);
+ MUCController::appendToJoinParts(list, NickJoinPart("Bert", Join));
+ gold.push_back(NickJoinPart("Bert", Join));
+ checkEqual(gold, list);
+ MUCController::appendToJoinParts(list, NickJoinPart("Bert", Part));
+ gold[2].type = JoinThenPart;
+ checkEqual(gold, list);
+ MUCController::appendToJoinParts(list, NickJoinPart("Kev", Part));
+ gold[0].type = JoinThenPart;
+ checkEqual(gold, list);
+ MUCController::appendToJoinParts(list, NickJoinPart("Remko", Part));
+ gold[1].type = JoinThenPart;
+ checkEqual(gold, list);
+ MUCController::appendToJoinParts(list, NickJoinPart("Ernie", Part));
+ gold.push_back(NickJoinPart("Ernie", Part));
+ checkEqual(gold, list);
+ MUCController::appendToJoinParts(list, NickJoinPart("Ernie", Join));
+ gold[3].type = PartThenJoin;
+ checkEqual(gold, list);
+ MUCController::appendToJoinParts(list, NickJoinPart("Kev", Join));
+ gold[0].type = Join;
+ checkEqual(gold, list);
+ MUCController::appendToJoinParts(list, NickJoinPart("Ernie", Part));
+ gold[3].type = Part;
+ checkEqual(gold, list);
+
+}
+
+TEST_F(MUCControllerTest, testJoinPartStringContructionSimple) {
+ std::vector<NickJoinPart> list;
+ list.push_back(NickJoinPart("Kev", Join));
+ ASSERT_EQ(std::string("Kev has entered the room"), MUCController::generateJoinPartString(list, false));
+ list.push_back(NickJoinPart("Remko", Part));
+ ASSERT_EQ(std::string("Kev has entered the room and Remko has left the room"), MUCController::generateJoinPartString(list, false));
+ list.push_back(NickJoinPart("Bert", Join));
+ ASSERT_EQ(std::string("Kev and Bert have entered the room and Remko has left the room"), MUCController::generateJoinPartString(list, false));
+ list.push_back(NickJoinPart("Ernie", Join));
+ ASSERT_EQ(std::string("Kev, Bert and Ernie have entered the room and Remko has left the room"), MUCController::generateJoinPartString(list, false));
+}
+
+TEST_F(MUCControllerTest, testJoinPartStringContructionMixed) {
+ std::vector<NickJoinPart> list;
+ list.push_back(NickJoinPart("Kev", JoinThenPart));
+ ASSERT_EQ(std::string("Kev has entered then left the room"), MUCController::generateJoinPartString(list, false));
+ list.push_back(NickJoinPart("Remko", Part));
+ ASSERT_EQ(std::string("Remko has left the room and Kev has entered then left the room"), MUCController::generateJoinPartString(list, false));
+ list.push_back(NickJoinPart("Bert", PartThenJoin));
+ ASSERT_EQ(std::string("Remko has left the room, Kev has entered then left the room and Bert has left then returned to the room"), MUCController::generateJoinPartString(list, false));
+ list.push_back(NickJoinPart("Ernie", JoinThenPart));
+ ASSERT_EQ(std::string("Remko has left the room, Kev and Ernie have entered then left the room and Bert has left then returned to the room"), MUCController::generateJoinPartString(list, false));
+}
+
+TEST_F(MUCControllerTest, testRoleAffiliationStates) {
+
+ typedef std::map<std::string, MUCOccupant> occupant_map;
+ occupant_map occupants;
+ occupants.insert(occupant_map::value_type("Kev", MUCOccupant("Kev", MUCOccupant::Participant, MUCOccupant::Owner)));
+ occupants.insert(occupant_map::value_type("Remko", MUCOccupant("Remko", MUCOccupant::Participant, MUCOccupant::Owner)));
+ occupants.insert(occupant_map::value_type("Bert", MUCOccupant("Bert", MUCOccupant::Participant, MUCOccupant::Owner)));
+ occupants.insert(occupant_map::value_type("Ernie", MUCOccupant("Ernie", MUCOccupant::Participant, MUCOccupant::Owner)));
+
+ /* populate the MUC with fake users */
+ for (auto&& occupant : occupants) {
+ muc_->insertOccupant(occupant.second);
+ }
+
+ std::vector<MUCOccupant> alterations;
+ alterations.push_back(MUCOccupant("Kev", MUCOccupant::Visitor, MUCOccupant::Admin));
+ alterations.push_back(MUCOccupant("Remko", MUCOccupant::Moderator, MUCOccupant::Member));
+ alterations.push_back(MUCOccupant("Bert", MUCOccupant::Visitor, MUCOccupant::Outcast));
+ alterations.push_back(MUCOccupant("Ernie", MUCOccupant::NoRole, MUCOccupant::Member));
+ alterations.push_back(MUCOccupant("Bert", MUCOccupant::Moderator, MUCOccupant::Owner));
+ alterations.push_back(MUCOccupant("Kev", MUCOccupant::Participant, MUCOccupant::Outcast));
+ alterations.push_back(MUCOccupant("Bert", MUCOccupant::Visitor, MUCOccupant::NoAffiliation));
+ alterations.push_back(MUCOccupant("Remko", MUCOccupant::NoRole, MUCOccupant::NoAffiliation));
+ alterations.push_back(MUCOccupant("Ernie", MUCOccupant::Visitor, MUCOccupant::Outcast));
+
+ for (const auto& alteration : alterations) {
+ /* perform an alteration to a user's role and affiliation */
+ occupant_map::iterator occupant = occupants.find(alteration.getNick());
+ ASSERT_TRUE(occupant != occupants.end());
+ const JID jid = jidFromOccupant(occupant->second);
+ /* change the affiliation, leave the role in place */
+ muc_->changeAffiliation(jid, alteration.getAffiliation());
+ occupant->second = MUCOccupant(occupant->first, occupant->second.getRole(), alteration.getAffiliation());
+ testRoleAffiliationStatesVerify(occupants);
+ /* change the role, leave the affiliation in place */
+ muc_->changeOccupantRole(jid, alteration.getRole());
+ occupant->second = MUCOccupant(occupant->first, alteration.getRole(), occupant->second.getAffiliation());
+ testRoleAffiliationStatesVerify(occupants);
+ }
+}
+
+TEST_F(MUCControllerTest, testSubjectChangeCorrect) {
+ joinCompleted();
+
+ {
+ Message::ref message = std::make_shared<Message>();
+ message->setType(Message::Groupchat);
+ message->setTo(self_);
+ message->setFrom(mucJID_.withResource("SomeNickname"));
+ message->setID("3FB99C56-7C92-4755-91B0-9C0098BC7AE0");
+ message->setSubject("New Room Subject");
+
+ controller_->handleIncomingMessage(std::make_shared<MessageEvent>(message));
+ ASSERT_EQ(std::string("The room subject is now: New Room Subject"), std::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(window_->lastAddedSystemMessage_.getParts()[0])->text);
+ }
+}
+
+/*
+ * Test that message stanzas with subject element and non-empty body element do not cause a subject change.
+ */
+TEST_F(MUCControllerTest, testSubjectChangeIncorrectA) {
+ joinCompleted();
+
+ {
+ Message::ref message = std::make_shared<Message>();
+ message->setType(Message::Groupchat);
+ message->setTo(self_);
+ message->setFrom(mucJID_.withResource("SomeNickname"));
+ message->setID(iqChannel_->getNewIQID());
+ message->setSubject("New Room Subject");
+ message->setBody("Some body text that prevents this stanza from being a subject change.");
+
+ controller_->handleIncomingMessage(std::make_shared<MessageEvent>(message));
+ ASSERT_EQ(std::string("Trying to enter room teaparty@rooms.wonderland.lit"), std::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(window_->lastAddedSystemMessage_.getParts()[0])->text);
+ }
+}
+
+/*
+ * Test that message stanzas with subject element and thread element do not cause a subject change.
+ */
+TEST_F(MUCControllerTest, testSubjectChangeIncorrectB) {
+ joinCompleted();
+
+ {
+ Message::ref message = std::make_shared<Message>();
+ message->setType(Message::Groupchat);
+ message->setTo(self_);
+ message->setFrom(mucJID_.withResource("SomeNickname"));
+ message->setID(iqChannel_->getNewIQID());
+ message->setSubject("New Room Subject");
+ message->addPayload(std::make_shared<Thread>("Thread that prevents the subject change."));
+
+ controller_->handleIncomingMessage(std::make_shared<MessageEvent>(message));
+ ASSERT_EQ(std::string("Trying to enter room teaparty@rooms.wonderland.lit"), std::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(window_->lastAddedSystemMessage_.getParts()[0])->text);
+ }
+}
+
+/*
+ * Test that message stanzas with subject element and empty body element do not cause a subject change.
+ */
+TEST_F(MUCControllerTest, testSubjectChangeIncorrectC) {
+ joinCompleted();
+
+ {
+ Message::ref message = std::make_shared<Message>();
+ message->setType(Message::Groupchat);
+ message->setTo(self_);
+ message->setFrom(mucJID_.withResource("SomeNickname"));
+ message->setID(iqChannel_->getNewIQID());
+ message->setSubject("New Room Subject");
+ message->setBody("");
+
+ controller_->handleIncomingMessage(std::make_shared<MessageEvent>(message));
+ ASSERT_EQ(std::string("Trying to enter room teaparty@rooms.wonderland.lit"), std::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(window_->lastAddedSystemMessage_.getParts()[0])->text);
+ }
+}
+
+TEST_F(MUCControllerTest, testHandleOccupantNicknameChanged) {
+ const auto occupantCount = [&](const std::string & nick) {
+ auto roster = window_->getRosterModel();
+ const auto currentOccupantsJIDs = roster->getJIDs();
+ int count = 0;
+ for (auto & p : currentOccupantsJIDs) {
+ if (p.getResource() == nick) {
+ ++count;
+ }
+ }
+ return count;
+ };
+
+ muc_->insertOccupant(MUCOccupant("TestUserOne", MUCOccupant::Participant, MUCOccupant::Owner));
+ muc_->insertOccupant(MUCOccupant("TestUserTwo", MUCOccupant::Participant, MUCOccupant::Owner));
+ muc_->insertOccupant(MUCOccupant("TestUserThree", MUCOccupant::Participant, MUCOccupant::Owner));
+
+ muc_->onOccupantNicknameChanged("TestUserOne", "TestUserTwo");
+
+ ASSERT_EQ(0, occupantCount("TestUserOne"));
+ ASSERT_EQ(1, occupantCount("TestUserTwo"));
+ ASSERT_EQ(1, occupantCount("TestUserThree"));
+}
+
+TEST_F(MUCControllerTest, testHandleOccupantNicknameChangedRoster) {
+ const auto occupantCount = [&](const std::string & nick) {
+ auto roster = window_->getRosterModel();
+ const auto participants = roster->getGroup("Participants");
+ const auto displayedParticipants = participants->getDisplayedChildren();
+ int count = 0;
+ for (auto & p : displayedParticipants) {
+ if (p->getDisplayName() == nick) {
+ ++count;
+ }
+ }
+ return count;
+ };
+
+ muc_->insertOccupant(MUCOccupant("TestUserOne", MUCOccupant::Participant, MUCOccupant::Owner));
+ muc_->insertOccupant(MUCOccupant("TestUserTwo", MUCOccupant::Participant, MUCOccupant::Owner));
+ muc_->insertOccupant(MUCOccupant("TestUserThree", MUCOccupant::Participant, MUCOccupant::Owner));
+ ASSERT_EQ(1, occupantCount("TestUserOne"));
+ ASSERT_EQ(1, occupantCount("TestUserTwo"));
+ ASSERT_EQ(1, occupantCount("TestUserThree"));
+
+ muc_->onOccupantNicknameChanged("TestUserOne", "TestUserTwo");
+
+ ASSERT_EQ(0, occupantCount("TestUserOne"));
+ ASSERT_EQ(1, occupantCount("TestUserTwo"));
+ ASSERT_EQ(1, occupantCount("TestUserThree"));
+}
+
+TEST_F(MUCControllerTest, testHandleChangeSubjectRequest) {
+ std::string testStr("New Subject");
+ ASSERT_EQ(std::string(""), muc_->newSubjectSet_);
+ window_->onChangeSubjectRequest(testStr);
+ ASSERT_EQ(testStr, muc_->newSubjectSet_);
+}
+
+TEST_F(MUCControllerTest, testNonImpromptuMUCWindowTitle) {
+ ASSERT_EQ(muc_->getJID().getNode(), window_->name_);
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingRequestCompleteMarking) {
+ setMUCSecurityMarking("Test|Highest Possible Security", "Black", "Red", true);
+
+ ASSERT_EQ(std::string("Test|Highest Possible Security"), window_->markingValue_);
+ ASSERT_EQ(std::string("Black"), window_->markingForegroundColorValue_);
+ ASSERT_EQ(std::string("Red"), window_->markingBackgroundColorValue_);
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingRequestCompleteMarkingWithExtraForm) {
+ auto formTypeField = std::make_shared<FormField>(FormField::Type::HiddenType, "http://jabber.org/protocol/muc#roominfo");
+ auto markingField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Test|Highest Possible Security");
+ auto markingForegroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Black");
+ auto markingBackgroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Red");
+ formTypeField->setName("FORM_TYPE");
+ markingField->setName("x-isode#roominfo_marking");
+ markingForegroundColorField->setName("x-isode#roominfo_marking_fg_color");
+ markingBackgroundColorField->setName("x-isode#roominfo_marking_bg_color");
+
+ auto extraForm = std::make_shared<Form>(Form::Type::ResultType);
+ auto form = std::make_shared<Form>(Form::Type::ResultType);
+ form->addField(formTypeField);
+ form->addField(markingField);
+ form->addField(markingForegroundColorField);
+ form->addField(markingBackgroundColorField);
+
+ auto discoInfoRef = std::make_shared<DiscoInfo>();
+ discoInfoRef->addExtension(extraForm);
+ discoInfoRef->addExtension(form);
+
+ auto infoResponse = IQ::createResult(self_, mucJID_, "test-id", discoInfoRef);
+ iqChannel_->onIQReceived(infoResponse);
+ ASSERT_EQ(std::string("Test|Highest Possible Security"), window_->markingValue_);
+ ASSERT_EQ(std::string("Black"), window_->markingForegroundColorValue_);
+ ASSERT_EQ(std::string("Red"), window_->markingBackgroundColorValue_);
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingRequestNoColorsInMarking) {
+ auto formTypeField = std::make_shared<FormField>(FormField::Type::HiddenType, "http://jabber.org/protocol/muc#roominfo");
+ auto markingField = std::make_shared<FormField>(FormField::Type::TextSingleType, "Test|Highest Possible Security");
+ auto markingForegroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "");
+ auto markingBackgroundColorField = std::make_shared<FormField>(FormField::Type::TextSingleType, "");
+ formTypeField->setName("FORM_TYPE");
+ markingField->setName("x-isode#roominfo_marking");
+ markingForegroundColorField->setName("x-isode#roominfo_marking_fg_color");
+ markingBackgroundColorField->setName("x-isode#roominfo_marking_bg_color");
+
+ auto form = std::make_shared<Form>(Form::Type::ResultType);
+ form->addField(formTypeField);
+ form->addField(markingField);
+ form->addField(markingForegroundColorField);
+ form->addField(markingBackgroundColorField);
+
+ auto discoInfoRef = std::make_shared<DiscoInfo>();
+ discoInfoRef->addExtension(form);
+
+ auto infoResponse = IQ::createResult(self_, mucJID_, "test-id", discoInfoRef);
+ iqChannel_->onIQReceived(infoResponse);
+ ASSERT_EQ(std::string("Test|Highest Possible Security"), window_->markingValue_);
+ ASSERT_EQ(std::string("Black"), window_->markingForegroundColorValue_);
+ ASSERT_EQ(std::string("White"), window_->markingBackgroundColorValue_);
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingRequestEmptyMarking) {
+ setMUCSecurityMarking("", "", "", true);
+
+ ASSERT_EQ(std::string(""), window_->markingValue_);
+ ASSERT_EQ(std::string(""), window_->markingForegroundColorValue_);
+ ASSERT_EQ(std::string(""), window_->markingBackgroundColorValue_);
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingRequestWithMarkingNoFormType) {
+ setMUCSecurityMarking("Test|Highest Possible Security", "Black", "Red", false);
+
+ ASSERT_EQ(std::string(""), window_->markingValue_);
+ ASSERT_EQ(std::string(""), window_->markingForegroundColorValue_);
+ ASSERT_EQ(std::string(""), window_->markingBackgroundColorValue_);
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingRequestNoMarking) {
+ auto form = std::make_shared<Form>(Form::Type::ResultType);
+
+ auto discoInfoRef = std::make_shared<DiscoInfo>();
+ discoInfoRef->addExtension(form);
+
+ auto infoResponse = IQ::createResult(self_, mucJID_, "test-id", discoInfoRef);
+ iqChannel_->onIQReceived(infoResponse);
+ ASSERT_EQ(std::string(""), window_->markingValue_);
+ ASSERT_EQ(std::string(""), window_->markingForegroundColorValue_);
+ ASSERT_EQ(std::string(""), window_->markingBackgroundColorValue_);
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingRequestNoForm) {
+ auto discoInfoRef = std::make_shared<DiscoInfo>();
+
+ auto infoResponse = IQ::createResult( self_, mucJID_, "test-id", discoInfoRef);
+ iqChannel_->onIQReceived(infoResponse);
+ ASSERT_EQ(std::string(""), window_->markingValue_);
+ ASSERT_EQ(std::string(""), window_->markingForegroundColorValue_);
+ ASSERT_EQ(std::string(""), window_->markingBackgroundColorValue_);
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingRequestError) {
+ auto errorPayload = std::make_shared<ErrorPayload>(ErrorPayload::Condition::NotAuthorized, ErrorPayload::Type::Auth);
+
+ auto infoResponse = IQ::createResult( self_, mucJID_, "test-id", errorPayload);
+ iqChannel_->onIQReceived(infoResponse);
+ ASSERT_EQ(std::string(""), window_->markingValue_);
+ ASSERT_EQ(std::string(""), window_->markingForegroundColorValue_);
+ ASSERT_EQ(std::string(""), window_->markingBackgroundColorValue_);
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingAddedToMessage_Elision_NoRoomMarkingA) {
+ settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, true);
+ setMUCSecurityMarking("", "Black", "Red");
+
+ auto messageLabel = std::make_shared<SecurityLabel>();
+ messageLabel->setDisplayMarking("Test|Highest Possible Security");
+
+ auto sentMessage = createTestMessageWithoutSecurityLabel();
+ sentMessage->addPayload(messageLabel);
+
+ auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent);
+
+ auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_;
+
+ ASSERT_EQ(false, storedSecurityLabel == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string("Test|Highest Possible Security"), storedSecurityLabel->getDisplayMarking());
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingAddedToMessage_Elision_NoRoomMarkingB) {
+ settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, true);
+ setMUCSecurityMarking("", "Black", "Red");
+
+ auto messageLabel = std::make_shared<SecurityLabel>();
+ messageLabel->setDisplayMarking("");
+
+ auto sentMessage = createTestMessageWithoutSecurityLabel();
+ sentMessage->addPayload(messageLabel);
+
+ auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent);
+
+ auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_;
+
+ ASSERT_EQ(false, storedSecurityLabel == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string(""), storedSecurityLabel->getDisplayMarking());
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingAddedToMessage_Elision_WithRoomMarkingA) {
+ settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, true);
+ setMUCSecurityMarking("Test|Highest Possible Security", "Black", "Red");
+
+ auto messageLabel = std::make_shared<SecurityLabel>();
+ messageLabel->setDisplayMarking("Test|Highest Possible Security");
+
+ auto sentMessage = createTestMessageWithoutSecurityLabel();
+ sentMessage->addPayload(messageLabel);
+
+ // Test the first message matching MUC marking. This message SHOULD have a marking
+
+ auto sentMessageEvent1 = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent1);
+
+ auto storedSecurityLabel1 = window_->lastAddedMessageSecurityLabel_;
+
+ ASSERT_EQ(false, storedSecurityLabel1 == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string("Test|Highest Possible Security"), storedSecurityLabel1->getDisplayMarking());
+
+ // Test a consecutive message matching MUC marking. This message SHOULD NOT have a marking
+
+ auto sentMessageEvent2 = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent2);
+
+ auto storedSecurityLabel2 = window_->lastAddedMessageSecurityLabel_;
+
+ ASSERT_EQ(false, storedSecurityLabel2 == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string(""), storedSecurityLabel2->getDisplayMarking());
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingAddedToMessage_Elision_WithRoomMarkingB) {
+ settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, true);
+ setMUCSecurityMarking("Test|Lower Security Marking", "Black", "Red");
+
+ auto messageLabel = std::make_shared<SecurityLabel>();
+ messageLabel->setDisplayMarking("Test|Highest Possible Security");
+
+ auto sentMessage = createTestMessageWithoutSecurityLabel();
+ sentMessage->addPayload(messageLabel);
+
+ auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent);
+
+ auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_;
+
+ ASSERT_EQ(false, storedSecurityLabel == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string("Test|Highest Possible Security"), storedSecurityLabel->getDisplayMarking());
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingAddedToMessage_Elision_WithRoomMarkingC) {
+ settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, true);
+ setMUCSecurityMarking("Test|Highest Possible Security", "Black", "Red");
+
+ auto messageLabel = std::make_shared<SecurityLabel>();
+ messageLabel->setDisplayMarking("");
+
+ auto sentMessage = createTestMessageWithoutSecurityLabel();
+ sentMessage->addPayload(messageLabel);
+
+ auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent);
+
+ auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_;
+
+ ASSERT_EQ(false, storedSecurityLabel == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string("Unmarked"), storedSecurityLabel->getDisplayMarking());
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingAddedToMessage_NoElision_NoRoomMarkingA) {
+ settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, false);
+ setMUCSecurityMarking("", "Black", "Red");
+
+ auto messageLabel = std::make_shared<SecurityLabel>();
+ messageLabel->setDisplayMarking("Test|Highest Possible Security");
+
+ auto sentMessage = createTestMessageWithoutSecurityLabel();
+ sentMessage->addPayload(messageLabel);
+
+ auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent);
+
+ auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_;
+
+ ASSERT_EQ(false, storedSecurityLabel == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string("Test|Highest Possible Security"), storedSecurityLabel->getDisplayMarking());
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingAddedToMessage_NoElision_NoRoomMarkingB) {
+ settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, false);
+ setMUCSecurityMarking("", "Black", "Red");
+
+ auto messageLabel = std::make_shared<SecurityLabel>();
+ messageLabel->setDisplayMarking("");
+
+ auto sentMessage = createTestMessageWithoutSecurityLabel();
+ sentMessage->addPayload(messageLabel);
+
+ auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent);
+
+ auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_;
+
+ ASSERT_EQ(false, storedSecurityLabel == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string(""), storedSecurityLabel->getDisplayMarking());
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingAddedToMessage_NoElision_WithRoomMarkingA) {
+ settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, false);
+ setMUCSecurityMarking("Test|Highest Possible Security", "Black", "Red");
+
+ auto messageLabel = std::make_shared<SecurityLabel>();
+ messageLabel->setDisplayMarking("Test|Highest Possible Security");
+
+ auto sentMessage = createTestMessageWithoutSecurityLabel();
+ sentMessage->addPayload(messageLabel);
+
+ // Test the first message matching MUC marking. This message SHOULD have a marking
+
+ auto sentMessageEvent1 = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent1);
+
+ auto storedSecurityLabel1 = window_->lastAddedMessageSecurityLabel_;
+
+ ASSERT_EQ(false, storedSecurityLabel1 == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string("Test|Highest Possible Security"), storedSecurityLabel1->getDisplayMarking());
+
+ // Test a consecutive message matching MUC marking. This message SHOULD ALSO have a marking
+
+ auto sentMessageEvent2 = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent2);
+
+ auto storedSecurityLabel2 = window_->lastAddedMessageSecurityLabel_;
+
+ ASSERT_EQ(false, storedSecurityLabel2 == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string("Test|Highest Possible Security"), storedSecurityLabel2->getDisplayMarking());
+}
+
+TEST_F(MUCControllerTest, testSecurityMarkingAddedToMessage_NoElision_WithRoomMarkingB) {
+ settings_->storeSetting(SettingConstants::MUC_MARKING_ELISION, false);
+ setMUCSecurityMarking("", "Black", "Red");
+
+ auto messageLabel = std::make_shared<SecurityLabel>();
+ messageLabel->setDisplayMarking("");
+
+ auto sentMessage = createTestMessageWithoutSecurityLabel();
+ sentMessage->addPayload(messageLabel);
+
+ auto sentMessageEvent = std::make_shared<MessageEvent>(sentMessage);
+ controller_->handleIncomingMessage(sentMessageEvent);
+
+ auto storedSecurityLabel = window_->lastAddedMessageSecurityLabel_;
+ ASSERT_EQ(false, storedSecurityLabel == nullptr);
+ // This is the potentially altered security label that is displayed on the screen
+ ASSERT_EQ(std::string(""), storedSecurityLabel->getDisplayMarking());
+}
diff --git a/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h b/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h
index 5fa264d..1d980d3 100644
--- a/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h
+++ b/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h
@@ -1,27 +1,28 @@
/*
- * Copyright (c) 2011 Kevin Smith
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2011-2016 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
#pragma once
-#include "Swift/Controllers/UIInterfaces/ChatListWindow.h"
+#include <Swift/Controllers/UIInterfaces/ChatListWindow.h>
namespace Swift {
- class MockChatListWindow : public ChatListWindow {
- public:
- MockChatListWindow() {}
- virtual ~MockChatListWindow() {}
- void addMUCBookmark(const MUCBookmark& /*bookmark*/) {}
- void removeMUCBookmark(const MUCBookmark& /*bookmark*/) {}
- void addWhiteboardSession(const ChatListWindow::Chat& /*chat*/) {}
- void removeWhiteboardSession(const JID& /*jid*/) {}
- void setBookmarksEnabled(bool /*enabled*/) {}
- void setRecents(const std::list<ChatListWindow::Chat>& /*recents*/) {}
- void setUnreadCount(int /*unread*/) {}
- void clearBookmarks() {}
- };
+ class MockChatListWindow : public ChatListWindow {
+ public:
+ MockChatListWindow() {}
+ virtual ~MockChatListWindow() {}
+ void addMUCBookmark(const MUCBookmark& /*bookmark*/) {}
+ void removeMUCBookmark(const MUCBookmark& /*bookmark*/) {}
+ void addWhiteboardSession(const ChatListWindow::Chat& /*chat*/) {}
+ void removeWhiteboardSession(const JID& /*jid*/) {}
+ void setBookmarksEnabled(bool /*enabled*/) {}
+ void setRecents(const std::list<ChatListWindow::Chat>& /*recents*/) {}
+ void setUnreadCount(size_t /*unread*/) {}
+ void clearBookmarks() {}
+ void setOnline(bool /*isOnline*/) {}
+ };
}