diff options
-rw-r--r-- | Swift/Controllers/Chat/MUCController.cpp | 16 | ||||
-rw-r--r-- | Swift/Controllers/Chat/MUCController.h | 4 | ||||
-rw-r--r-- | Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp | 57 |
3 files changed, 69 insertions, 8 deletions
diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp index 8f43b08..9d1459d 100644 --- a/Swift/Controllers/Chat/MUCController.cpp +++ b/Swift/Controllers/Chat/MUCController.cpp @@ -60,82 +60,82 @@ namespace Swift { class MUCBookmarkPredicate { public: MUCBookmarkPredicate(const JID& mucJID) : roomJID_(mucJID) { } bool operator()(const MUCBookmark& operand) { return operand.getRoom() == roomJID_; } private: JID roomJID_; }; /** * The controller does not gain ownership of the stanzaChannel, nor the factory. */ MUCController::MUCController ( const JID& self, MUC::ref muc, const boost::optional<std::string>& password, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* uiEventStream, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, - XMPPRoster* roster, + XMPPRoster* xmppRoster, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, bool isImpromptu, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, VCardManager* vcardManager, MUCBookmarkManager* mucBookmarkManager) : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider), muc_(muc), nick_(nick), desiredNick_(nick), password_(password), renameCounter_(0), isImpromptu_(isImpromptu), isImpromptuAlreadyConfigured_(false), clientBlockListManager_(clientBlockListManager), mucBookmarkManager_(mucBookmarkManager) { parting_ = true; joined_ = false; lastWasPresence_ = false; shouldJoinOnReconnect_ = true; doneGettingHistory_ = false; - xmppRoster_ = roster; + xmppRoster_ = xmppRoster; - roster_ = new Roster(false, true); - rosterVCardProvider_ = new RosterVCardProvider(roster_, vcardManager, JID::WithResource); + roster_ = std::unique_ptr<Roster>(new Roster(false, true)); + rosterVCardProvider_ = new RosterVCardProvider(roster_.get(), vcardManager, JID::WithResource); completer_ = new TabComplete(); - chatWindow_->setRosterModel(roster_); + chatWindow_->setRosterModel(roster_.get()); chatWindow_->setTabComplete(completer_); chatWindow_->onClosed.connect(boost::bind(&MUCController::handleWindowClosed, this)); chatWindow_->onOccupantSelectionChanged.connect(boost::bind(&MUCController::handleWindowOccupantSelectionChanged, this, _1)); chatWindow_->onOccupantActionSelected.connect(boost::bind(&MUCController::handleActionRequestedOnOccupant, this, _1, _2)); chatWindow_->onChangeSubjectRequest.connect(boost::bind(&MUCController::handleChangeSubjectRequest, this, _1)); chatWindow_->onBookmarkRequest.connect(boost::bind(&MUCController::handleBookmarkRequest, this)); chatWindow_->onConfigureRequest.connect(boost::bind(&MUCController::handleConfigureRequest, this, _1)); chatWindow_->onConfigurationFormCancelled.connect(boost::bind(&MUCController::handleConfigurationCancelled, this)); chatWindow_->onDestroyRequest.connect(boost::bind(&MUCController::handleDestroyRoomRequest, this)); chatWindow_->onInviteToChat.connect(boost::bind(&MUCController::handleInvitePersonToThisMUCRequest, this, _1)); chatWindow_->onGetAffiliationsRequest.connect(boost::bind(&MUCController::handleGetAffiliationsRequest, this)); chatWindow_->onChangeAffiliationsRequest.connect(boost::bind(&MUCController::handleChangeAffiliationsRequest, this, _1)); chatWindow_->onUnblockUserRequest.connect(boost::bind(&MUCController::handleUnblockUserRequest, this)); muc_->onJoinComplete.connect(boost::bind(&MUCController::handleJoinComplete, this, _1)); muc_->onJoinFailed.connect(boost::bind(&MUCController::handleJoinFailed, this, _1)); muc_->onOccupantJoined.connect(boost::bind(&MUCController::handleOccupantJoined, this, _1)); muc_->onOccupantNicknameChanged.connect(boost::bind(&MUCController::handleOccupantNicknameChanged, this, _1, _2)); muc_->onOccupantPresenceChange.connect(boost::bind(&MUCController::handleOccupantPresenceChange, this, _1)); muc_->onOccupantLeft.connect(boost::bind(&MUCController::handleOccupantLeft, this, _1, _2, _3)); muc_->onRoleChangeFailed.connect(boost::bind(&MUCController::handleOccupantRoleChangeFailed, this, _1, _2, _3)); muc_->onAffiliationListReceived.connect(boost::bind(&MUCController::handleAffiliationListReceived, this, _1, _2)); muc_->onConfigurationFailed.connect(boost::bind(&MUCController::handleConfigurationFailed, this, _1)); muc_->onConfigurationFormReceived.connect(boost::bind(&MUCController::handleConfigurationFormReceived, this, _1)); highlighter_->setMode(isImpromptu_ ? Highlighter::ChatMode : Highlighter::MUCMode); highlighter_->setNick(nick_); if (timerFactory && stanzaChannel_->isAvailable()) { loginCheckTimer_ = std::shared_ptr<Timer>(timerFactory->createTimer(MUC_JOIN_WARNING_TIMEOUT_MILLISECONDS)); loginCheckTimer_->onTick.connect(boost::bind(&MUCController::handleJoinTimeoutTick, this)); loginCheckTimer_->start(); } @@ -152,61 +152,60 @@ MUCController::MUCController ( chatWindow_->setName(muc->getJID().getNode()); } if (stanzaChannel->isAvailable()) { MUCController::setOnline(true); } if (avatarManager_ != nullptr) { avatarChangedConnection_ = (avatarManager_->onAvatarChanged.connect(boost::bind(&MUCController::handleAvatarChanged, this, _1))); } MUCController::handleBareJIDCapsChanged(muc->getJID()); eventStream_->onUIEvent.connect(boost::bind(&MUCController::handleUIEvent, this, _1)); // setup handling of MUC bookmark changes mucBookmarkManagerBookmarkAddedConnection_ = (mucBookmarkManager_->onBookmarkAdded.connect(boost::bind(&MUCController::handleMUCBookmarkAdded, this, _1))); mucBookmarkManagerBookmarkRemovedConnection_ = (mucBookmarkManager_->onBookmarkRemoved.connect(boost::bind(&MUCController::handleMUCBookmarkRemoved, this, _1))); std::vector<MUCBookmark> mucBookmarks = mucBookmarkManager_->getBookmarks(); std::vector<MUCBookmark>::iterator bookmarkIterator = std::find_if(mucBookmarks.begin(), mucBookmarks.end(), MUCBookmarkPredicate(muc->getJID())); if (bookmarkIterator != mucBookmarks.end()) { updateChatWindowBookmarkStatus(*bookmarkIterator); } else { updateChatWindowBookmarkStatus(boost::optional<MUCBookmark>()); } } MUCController::~MUCController() { eventStream_->onUIEvent.disconnect(boost::bind(&MUCController::handleUIEvent, this, _1)); chatWindow_->setRosterModel(nullptr); delete rosterVCardProvider_; - delete roster_; if (loginCheckTimer_) { loginCheckTimer_->stop(); } chatWindow_->setTabComplete(nullptr); delete completer_; } void MUCController::cancelReplaces() { lastWasPresence_ = false; } void MUCController::handleWindowOccupantSelectionChanged(ContactRosterItem* item) { std::vector<ChatWindow::OccupantAction> actions; if (item) { MUCOccupant::Affiliation affiliation = muc_->getOccupant(getNick()).getAffiliation(); MUCOccupant::Role role = muc_->getOccupant(getNick()).getRole(); if (role == MUCOccupant::Moderator && !isImpromptu_) { if (affiliation == MUCOccupant::Admin || affiliation == MUCOccupant::Owner) { actions.push_back(ChatWindow::Ban); } actions.push_back(ChatWindow::Kick); actions.push_back(ChatWindow::MakeModerator); actions.push_back(ChatWindow::MakeParticipant); actions.push_back(ChatWindow::MakeVisitor); } // Add contact is available only if the real JID is also available if (muc_->getOccupant(item->getJID().getResource()).getRealJID()) { @@ -737,60 +736,65 @@ void MUCController::handleOccupantLeft(const MUCOccupant& occupant, MUC::Leaving roster_->removeContact(JID(toJID_.getNode(), toJID_.getDomain(), occupant.getNick())); } else { addPresenceMessage(partMessage); parting_ = true; processUserPart(); } if (clearAfter) { clearPresenceQueue(); } if (isImpromptu_) { setImpromptuWindowTitle(); } } void MUCController::handleOccupantNicknameChanged(const std::string& oldNickname, const std::string& newNickname) { addPresenceMessage(generateNicknameChangeString(oldNickname, newNickname)); JID oldJID = muc_->getJID().withResource(oldNickname); JID newJID = muc_->getJID().withResource(newNickname); // adjust occupants currentOccupants_.erase(oldNickname); currentOccupants_.insert(newNickname); // adjust completer completer_->removeWord(oldNickname); completer_->addWord(newNickname); // update contact roster_->removeContact(oldJID); + auto it = currentOccupants_.find(newNickname); + if (it != currentOccupants_.end()) { + roster_->removeContact(newJID); + } + MUCOccupant occupant = muc_->getOccupant(newNickname); JID realJID; if (occupant.getRealJID()) { realJID = occupant.getRealJID().get(); } MUCOccupant::Role role = MUCOccupant::Participant; MUCOccupant::Affiliation affiliation = MUCOccupant::NoAffiliation; if (!isImpromptu_) { role = occupant.getRole(); affiliation = occupant.getAffiliation(); } std::string groupName(roleToGroupName(role)); roster_->addContact(newJID, realJID, newNickname, groupName, avatarManager_->getAvatarPath(newJID)); roster_->applyOnItems(SetMUC(newJID, role, affiliation)); if (avatarManager_ != nullptr) { handleAvatarChanged(newJID); } clearPresenceQueue(); onUserNicknameChanged(oldNickname, newNickname); } void MUCController::handleOccupantPresenceChange(std::shared_ptr<Presence> presence) { receivedActivity(); roster_->applyOnItems(SetPresence(presence, JID::WithResource)); } bool MUCController::isIncomingMessageFromMe(std::shared_ptr<Message> message) { JID from = message->getFrom(); diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h index 467f2e7..7aff627 100644 --- a/Swift/Controllers/Chat/MUCController.h +++ b/Swift/Controllers/Chat/MUCController.h @@ -27,61 +27,61 @@ #include <Swift/Controllers/UIInterfaces/ChatWindow.h> namespace Swift { class StanzaChannel; class IQRouter; class ChatWindowFactory; class Roster; class AvatarManager; class UIEventStream; class TimerFactory; class TabComplete; class XMPPRoster; class HighlightManager; class UIEvent; class VCardManager; class RosterVCardProvider; class ClientBlockListManager; class MUCBookmarkManager; class MUCBookmark; enum JoinPart {Join, Part, JoinThenPart, PartThenJoin}; struct NickJoinPart { NickJoinPart(const std::string& nick, JoinPart type) : nick(nick), type(type) {} std::string nick; JoinPart type; }; class MUCController : public ChatControllerBase { public: - MUCController(const JID& self, MUC::ref muc, const boost::optional<std::string>& password, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, XMPPRoster* roster, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, bool isImpromptu, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, VCardManager* vcardManager, MUCBookmarkManager* mucBookmarkManager); + MUCController(const JID& self, MUC::ref muc, const boost::optional<std::string>& password, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, XMPPRoster* xmppRoster, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, bool isImpromptu, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, VCardManager* vcardManager, MUCBookmarkManager* mucBookmarkManager); virtual ~MUCController(); boost::signals2::signal<void ()> onUserLeft; boost::signals2::signal<void ()> onUserJoined; boost::signals2::signal<void ()> onImpromptuConfigCompleted; boost::signals2::signal<void (const std::string&, const std::string& )> onUserNicknameChanged; virtual void setOnline(bool online) SWIFTEN_OVERRIDE; virtual void setAvailableServerFeatures(std::shared_ptr<DiscoInfo> info) SWIFTEN_OVERRIDE; void rejoin(); static void appendToJoinParts(std::vector<NickJoinPart>& joinParts, const NickJoinPart& newEvent); static std::string generateJoinPartString(const std::vector<NickJoinPart>& joinParts, bool isImpromptu); static std::string concatenateListOfNames(const std::vector<NickJoinPart>& joinParts); static std::string generateNicknameChangeString(const std::string& oldNickname, const std::string& newNickname); bool isJoined(); const std::string& getNick(); const boost::optional<std::string> getPassword() const; bool isImpromptu() const; std::map<std::string, JID> getParticipantJIDs() const; void sendInvites(const std::vector<JID>& jids, const std::string& reason) const; protected: virtual void preSendMessageRequest(std::shared_ptr<Message> message) SWIFTEN_OVERRIDE; virtual bool isIncomingMessageFromMe(std::shared_ptr<Message> message) SWIFTEN_OVERRIDE; virtual std::string senderHighlightNameFromMessage(const JID& from) SWIFTEN_OVERRIDE; virtual std::string senderDisplayNameFromMessage(const JID& from) SWIFTEN_OVERRIDE; virtual boost::optional<boost::posix_time::ptime> getMessageTimestamp(std::shared_ptr<Message> message) const SWIFTEN_OVERRIDE; virtual void preHandleIncomingMessage(std::shared_ptr<MessageEvent>) SWIFTEN_OVERRIDE; virtual void addMessageHandleIncomingMessage(const JID& from, const ChatWindow::ChatMessage& message, bool senderIsSelf, std::shared_ptr<SecurityLabel> label, const boost::posix_time::ptime& time) SWIFTEN_OVERRIDE; virtual void postHandleIncomingMessage(std::shared_ptr<MessageEvent>, const ChatWindow::ChatMessage& chatMessage) SWIFTEN_OVERRIDE; virtual void cancelReplaces() SWIFTEN_OVERRIDE; virtual void logMessage(const std::string& message, const JID& fromJID, const JID& toJID, const boost::posix_time::ptime& timeStamp, bool isIncoming) SWIFTEN_OVERRIDE; @@ -121,63 +121,63 @@ namespace Swift { void handleConfigurationFormReceived(Form::ref); void handleDestroyRoomRequest(); void handleInvitePersonToThisMUCRequest(const std::vector<JID>& jidsToInvite); void handleConfigurationCancelled(); void handleOccupantRoleChangeFailed(ErrorPayload::ref, const JID&, MUCOccupant::Role); void handleGetAffiliationsRequest(); void handleAffiliationListReceived(MUCOccupant::Affiliation affiliation, const std::vector<JID>& jids); void handleChangeAffiliationsRequest(const std::vector<std::pair<MUCOccupant::Affiliation, JID> >& changes); void handleInviteToMUCWindowDismissed(); void handleInviteToMUCWindowCompleted(); void handleUIEvent(std::shared_ptr<UIEvent> event); void addRecentLogs(); void checkDuplicates(std::shared_ptr<Message> newMessage); void setNick(const std::string& nick); void setImpromptuWindowTitle(); void handleRoomUnlocked(); void configureAsImpromptuRoom(Form::ref form); Form::ref buildImpromptuRoomConfiguration(Form::ref roomConfigurationForm); void handleUnblockUserRequest(); void handleBlockingStateChanged(); void handleMUCBookmarkAdded(const MUCBookmark& bookmark); void handleMUCBookmarkRemoved(const MUCBookmark& bookmark); void updateChatWindowBookmarkStatus(const boost::optional<MUCBookmark>& bookmark); private: MUC::ref muc_; std::string nick_; std::string desiredNick_; - Roster* roster_; TabComplete* completer_; bool parting_; bool joined_; bool shouldJoinOnReconnect_; bool doneGettingHistory_; boost::signals2::scoped_connection avatarChangedConnection_; std::shared_ptr<Timer> loginCheckTimer_; std::set<std::string> currentOccupants_; std::vector<NickJoinPart> joinParts_; boost::posix_time::ptime lastActivity_; boost::optional<std::string> password_; XMPPRoster* xmppRoster_; + std::unique_ptr<Roster> roster_; std::vector<HistoryMessage> joinContext_; size_t renameCounter_; bool isImpromptu_; bool isImpromptuAlreadyConfigured_; RosterVCardProvider* rosterVCardProvider_; std::string lastJoinMessageUID_; ClientBlockListManager* clientBlockListManager_; boost::signals2::scoped_connection blockingOnStateChangedConnection_; boost::signals2::scoped_connection blockingOnItemAddedConnection_; boost::signals2::scoped_connection blockingOnItemRemovedConnection_; boost::optional<ChatWindow::AlertID> blockedContactAlert_; MUCBookmarkManager* mucBookmarkManager_; boost::signals2::scoped_connection mucBookmarkManagerBookmarkAddedConnection_; boost::signals2::scoped_connection mucBookmarkManagerBookmarkRemovedConnection_; }; } diff --git a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp index 32639f6..59dcd77 100644 --- a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp @@ -35,60 +35,62 @@ #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/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 <Swift/Controllers/UnitTest/MockChatWindow.h> #include <Swift/Controllers/XMPPEvents/EventController.h> 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(testRoleAffiliationStates); CPPUNIT_TEST(testSubjectChangeCorrect); CPPUNIT_TEST(testSubjectChangeIncorrectA); CPPUNIT_TEST(testSubjectChangeIncorrectB); CPPUNIT_TEST(testSubjectChangeIncorrectC); + CPPUNIT_TEST(testHandleOccupantNicknameChanged); + CPPUNIT_TEST(testHandleOccupantNicknameChangedRoster); CPPUNIT_TEST_SUITE_END(); public: 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_); 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_->getRules(), true); @@ -474,60 +476,115 @@ public: CPPUNIT_ASSERT_EQUAL(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. */ void testSubjectChangeIncorrectC() { 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); CPPUNIT_ASSERT(stanzaChannel_->isAvailable()); /* Otherwise will prevent sends. */ CPPUNIT_ASSERT(message); CPPUNIT_ASSERT_EQUAL(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("New Room Subject"); message->setBody(""); controller_->handleIncomingMessage(std::make_shared<MessageEvent>(message)); CPPUNIT_ASSERT_EQUAL(std::string("Trying to enter room teaparty@rooms.wonderland.lit"), std::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(window_->lastAddedSystemMessage_.getParts()[0])->text); } } + void testHandleOccupantNicknameChanged() { + const auto occupantCount = [&](const std::string & nick) { + auto roster = window_->getRosterModel(); + CPPUNIT_ASSERT(roster != nullptr); + 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"); + + CPPUNIT_ASSERT_EQUAL(0, occupantCount("TestUserOne")); + CPPUNIT_ASSERT_EQUAL(1, occupantCount("TestUserTwo")); + CPPUNIT_ASSERT_EQUAL(1, occupantCount("TestUserThree")); + } + + void testHandleOccupantNicknameChangedRoster() { + const auto occupantCount = [&](const std::string & nick) { + auto roster = window_->getRosterModel(); + CPPUNIT_ASSERT(roster != nullptr); + const auto participants = roster->getGroup("Participants"); + CPPUNIT_ASSERT(participants != nullptr); + 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)); + CPPUNIT_ASSERT_EQUAL(1, occupantCount("TestUserOne")); + CPPUNIT_ASSERT_EQUAL(1, occupantCount("TestUserTwo")); + CPPUNIT_ASSERT_EQUAL(1, occupantCount("TestUserThree")); + + muc_->onOccupantNicknameChanged("TestUserOne", "TestUserTwo"); + + CPPUNIT_ASSERT_EQUAL(0, occupantCount("TestUserOne")); + CPPUNIT_ASSERT_EQUAL(1, occupantCount("TestUserTwo")); + CPPUNIT_ASSERT_EQUAL(1, occupantCount("TestUserThree")); + } + 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); CPPUNIT_ASSERT(child); for (auto childItem : child->getChildren()) { ContactRosterItem* item = dynamic_cast<ContactRosterItem*>(childItem); CPPUNIT_ASSERT(item); std::map<std::string, MUCOccupant>::const_iterator occupant = occupants.find(item->getJID().getResource()); CPPUNIT_ASSERT(occupant != occupants.end()); CPPUNIT_ASSERT(item->getMUCRole() == occupant->second.getRole()); CPPUNIT_ASSERT(item->getMUCAffiliation() == occupant->second.getAffiliation()); } } } private: 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_; |