diff options
| -rw-r--r-- | Swift/Controllers/ChatsManager.cpp | 38 | ||||
| -rw-r--r-- | Swift/Controllers/ChatsManager.h | 4 | ||||
| -rw-r--r-- | Swift/Controllers/UnitTest/ChatsManagerTest.cpp | 141 | ||||
| -rw-r--r-- | Swift/Controllers/UnitTest/MockChatWindow.h | 3 | 
4 files changed, 166 insertions, 20 deletions
diff --git a/Swift/Controllers/ChatsManager.cpp b/Swift/Controllers/ChatsManager.cpp index ef187f4..fe8efb3 100644 --- a/Swift/Controllers/ChatsManager.cpp +++ b/Swift/Controllers/ChatsManager.cpp @@ -1,5 +1,7 @@  #include "Swift/Controllers/ChatsManager.h" +#include <boost/bind.hpp> +  #include "Swiften/Client/Client.h"  #include "Swift/Controllers/ChatController.h" @@ -23,6 +25,7 @@ ChatsManager::ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRo  	avatarManager_ = NULL;  	serverDiscoInfo_ = serverDiscoInfo;  	presenceSender_ = presenceSender; +	presenceOracle_->onPresenceChange.connect(boost::bind(&ChatsManager::handlePresenceChange, this, _1, _2));  }  ChatsManager::~ChatsManager() { @@ -35,6 +38,20 @@ ChatsManager::~ChatsManager() {  } +/** + * If a resource goes offline, release bound chatdialog to that resource. + */ +void ChatsManager::handlePresenceChange(boost::shared_ptr<Presence> /*oldPresence*/, boost::shared_ptr<Presence> newPresence) { +	if (newPresence->getType() != Presence::Unavailable) return; +	JID fullJID(newPresence->getFrom()); +	std::map<JID, ChatController*>::iterator it = chatControllers_.find(fullJID); +	if (it == chatControllers_.end()) return; +	JID bareJID(fullJID.toBare()); +	//It doesn't make sense to have two unbound dialogs. +	if (chatControllers_.find(bareJID) != chatControllers_.end()) return; +	rebindControllerJID(fullJID, bareJID); +} +  void ChatsManager::setAvatarManager(AvatarManager* avatarManager) {  	avatarManager_ = avatarManager;  } @@ -83,19 +100,20 @@ void ChatsManager::handleChatRequest(const String &contact) {  }  ChatController* ChatsManager::getChatController(const JID &contact) { -	JID lookupContact(contact); -	if (chatControllers_.find(lookupContact) == chatControllers_.end()) { -		lookupContact = JID(contact.toBare()); -	} -	if (chatControllers_.find(lookupContact) == chatControllers_.end()) { -		chatControllers_[contact] = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_); -		chatControllers_[contact]->setAvailableServerFeatures(serverDiscoInfo_); -		lookupContact = contact; +	if (chatControllers_.find(contact) == chatControllers_.end()) { +		//Need to look for an unboud window to bind first +		JID bare(contact.toBare()); +		if (chatControllers_.find(bare) != chatControllers_.end()) { +			rebindControllerJID(bare, contact); +		} else { +			chatControllers_[contact] = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_); +			chatControllers_[contact]->setAvailableServerFeatures(serverDiscoInfo_); +		}  	} -	return chatControllers_[lookupContact]; +	return chatControllers_[contact];  } -void ChatsManager::handleChatControllerJIDChanged(const JID& from, const JID& to) { +void ChatsManager::rebindControllerJID(const JID& from, const JID& to) {  	chatControllers_[to] = chatControllers_[from];  	chatControllers_.erase(from);  } diff --git a/Swift/Controllers/ChatsManager.h b/Swift/Controllers/ChatsManager.h index e897e59..260bd1d 100644 --- a/Swift/Controllers/ChatsManager.h +++ b/Swift/Controllers/ChatsManager.h @@ -7,6 +7,7 @@  #include "Swiften/Base/String.h"  #include "Swiften/Elements/DiscoInfo.h"  #include "Swiften/Elements/Message.h" +#include "Swiften/Elements/Presence.h"  #include "Swiften/JID/JID.h"  #include "Swiften/MUC/MUCRegistry.h" @@ -33,7 +34,8 @@ namespace Swift {  			void handleChatRequest(const String& contact);  			void handleJoinMUCRequest(const JID& muc, const String& nick);  		private: -			void handleChatControllerJIDChanged(const JID& from, const JID& to); +			void rebindControllerJID(const JID& from, const JID& to); +			void handlePresenceChange(boost::shared_ptr<Presence> oldPresence, boost::shared_ptr<Presence> newPresence);  			ChatController* getChatController(const JID &contact);  			virtual bool isMUC(const JID& muc) const; diff --git a/Swift/Controllers/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/UnitTest/ChatsManagerTest.cpp index 071cd5b..9df244f 100644 --- a/Swift/Controllers/UnitTest/ChatsManagerTest.cpp +++ b/Swift/Controllers/UnitTest/ChatsManagerTest.cpp @@ -27,9 +27,12 @@ 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_SUITE_END();  public: @@ -70,13 +73,41 @@ public:  	void testFirstOpenWindowIncoming() {  		JID messageJID("testling@test.com/resource1"); -		ChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>(); +		MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();  		mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID).Return(window);  		boost::shared_ptr<Message> message(new Message());  		message->setFrom(messageJID); -		message->setBody("This is a legible message."); +		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).Return(window1); + +		boost::shared_ptr<Message> message1(new Message()); +		message1->setFrom(messageJID1); +		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).Return(window2); + +		boost::shared_ptr<Message> message2(new Message()); +		message2->setFrom(messageJID2); +		String body2("This is a legible message. .cmaulm.chul"); +		message2->setBody(body2); +		manager_->handleIncomingMessage(message2); +		CPPUNIT_ASSERT_EQUAL(body2, window2->lastMessageBody_);  	}  	void testFirstOpenWindowOutgoing() { @@ -99,28 +130,122 @@ public:  		boost::shared_ptr<Message> message(new Message());  		message->setFrom(JID(fullJIDString)); -		message->setBody("This is a legible message."); +		String body("This is a legible message. mjuga3089gm8G(*>M)@*("); +		message->setBody(body);  		manager_->handleIncomingMessage(message); -		/*FIXME: check the message got through. For now, checking that there isn't a new window created is useful enough.*/ -		//CPPUNIT_ASSERT_EQUAL(fullJIDString, window->name_); +		CPPUNIT_ASSERT_EQUAL(body, window->lastMessageBody_);  	}  	void testSecondWindow() {  		String messageJIDString1("testling1@test.com"); -		  		ChatWindow* window1 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();  		mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString1)).Return(window1); -  		manager_->handleChatRequest(messageJIDString1);  		String messageJIDString2("testling2@test.com"); -		  		ChatWindow* window2 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>();  		mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString2)).Return(window2);  		manager_->handleChatRequest(messageJIDString2);  	} +	/** Complete cycle. +		Create unbound window. +		Bind it. +		Unbind it. +		Rebind it. +	 */ +	void testUnbindRebind() { +		String bareJIDString("testling@test.com"); +		String fullJIDString1("testling@test.com/resource1"); +		String fullJIDString2("testling@test.com/resource2"); +		 +		MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>(); +		mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(bareJIDString)).Return(window); +		manager_->handleChatRequest(bareJIDString); + +		boost::shared_ptr<Message> message1(new Message()); +		message1->setFrom(JID(fullJIDString1)); +		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(jid1Online, jid1Offline); + +		boost::shared_ptr<Message> message2(new Message()); +		message2->setFrom(JID(fullJIDString2)); +		String messageBody2("This is another legible message."); +		message2->setBody(messageBody2); +		manager_->handleIncomingMessage(message2); +		CPPUNIT_ASSERT_EQUAL(messageBody2, window->lastMessageBody_); +	} + +	/** +	   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).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).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(jid1Online, 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(jid2Online, jid2Offline); + +		JID messageJID3("testling@test.com/resource3"); + +		boost::shared_ptr<Message> message3(new Message()); +		message3->setFrom(messageJID3); +		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); +		String body2b("This is a legible message2b."); +		message2b->setBody(body2b); +		manager_->handleIncomingMessage(message2b); +		CPPUNIT_ASSERT_EQUAL(body2b, window2->lastMessageBody_); +	}  private:  	JID jid_; diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h index 015bb9b..2625553 100644 --- a/Swift/Controllers/UnitTest/MockChatWindow.h +++ b/Swift/Controllers/UnitTest/MockChatWindow.h @@ -8,7 +8,7 @@ namespace Swift {  			MockChatWindow() {};  			virtual ~MockChatWindow(); -			virtual void addMessage(const String& /*message*/, const String& /*senderName*/, bool /*senderIsSelf*/, const boost::optional<SecurityLabel>& /*label*/, const String& /*avatarPath*/) {}; +			virtual void addMessage(const String& message, const String& /*senderName*/, bool /*senderIsSelf*/, const boost::optional<SecurityLabel>& /*label*/, const String& /*avatarPath*/) {lastMessageBody_ = message;};  			virtual void addSystemMessage(const String& /*message*/) {};  			virtual void addErrorMessage(const String& /*message*/) {}; @@ -29,6 +29,7 @@ namespace Swift {  			boost::signal<void (const String&)> onSendMessageRequest;  			String name_; +			String lastMessageBody_;  			std::vector<SecurityLabel> labels_;  			bool labelsEnabled_;  	};  | 
 Swift