/* * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Swift; 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(testChatControllerFullJIDBindingOnMessageAndNotReceipt); CPPUNIT_TEST(testChatControllerFullJIDBindingOnTypingAndNotActive); CPPUNIT_TEST(testChatControllerPMPresenceHandling); CPPUNIT_TEST(testLocalMUCServiceDiscoveryResetOnDisconnect); CPPUNIT_TEST(testChatControllerHighlightingNotificationTesting); CPPUNIT_TEST(testChatControllerHighlightingNotificationDeduplicateSounds); 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(); joinMUCWindowFactory_ = mocks_->InterfaceMock(); xmppRoster_ = new XMPPRosterImpl(); mucRegistry_ = new MUCRegistry(); nickResolver_ = new NickResolver(jid_.toBare(), xmppRoster_, NULL, mucRegistry_); presenceOracle_ = new PresenceOracle(stanzaChannel_, xmppRoster_); serverDiscoInfo_ = boost::make_shared(); presenceSender_ = new StanzaChannelPresenceSender(stanzaChannel_); directedPresenceSender_ = new DirectedPresenceSender(presenceSender_); mucManager_ = new MUCManager(stanzaChannel_, iqRouter_, directedPresenceSender_, mucRegistry_); uiEventStream_ = new UIEventStream(); // entityCapsManager_ = new EntityCapsManager(capsProvider_, stanzaChannel_); entityCapsProvider_ = new DummyEntityCapsProvider(); chatListWindowFactory_ = mocks_->InterfaceMock(); mucSearchWindowFactory_ = mocks_->InterfaceMock(); 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_, entityCapsProvider_); wbManager_ = new WhiteboardManager(whiteboardWindowFactory_, uiEventStream_, nickResolver_, wbSessionManager_); highlightManager_ = new HighlightManager(settings_); 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_); manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsProvider_, mucManager_, mucSearchWindowFactory_, profileSettings_, ftOverview_, xmppRoster_, false, settings_, NULL, wbManager_, highlightManager_, clientBlockListManager_, emoticons_, vcardManager_); manager_->setAvatarManager(avatarManager_); } void tearDown() { delete highlightManager_; //delete chatListWindowFactory delete profileSettings_; delete avatarManager_; delete manager_; 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 stanzaChannel_; delete eventController_; delete iqRouter_; delete iqChannel_; 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); boost::shared_ptr 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(); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID1, uiEventStream_).Return(window1); boost::shared_ptr 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(); //mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID2, uiEventStream_).Return(window2); boost::shared_ptr 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(); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString), uiEventStream_).Return(window); uiEventStream_->send(boost::shared_ptr(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(); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(bareJIDString), uiEventStream_).Return(window); uiEventStream_->send(boost::shared_ptr(new RequestChatUIEvent(JID(bareJIDString)))); boost::shared_ptr 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(); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString1), uiEventStream_).Return(window1); uiEventStream_->send(boost::shared_ptr(new RequestChatUIEvent(JID(messageJIDString1)))); std::string messageJIDString2("testling2@test.com"); ChatWindow* window2 = new MockChatWindow();//mocks_->InterfaceMock(); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString2), uiEventStream_).Return(window2); uiEventStream_->send(boost::shared_ptr(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(); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(bareJIDString), uiEventStream_).Return(window); uiEventStream_->send(boost::shared_ptr(new RequestChatUIEvent(JID(bareJIDString)))); boost::shared_ptr 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 jid1Online(new Presence()); jid1Online->setFrom(JID(fullJIDString1)); boost::shared_ptr jid1Offline(new Presence()); jid1Offline->setFrom(JID(fullJIDString1)); jid1Offline->setType(Presence::Unavailable); presenceOracle_->onPresenceChange(jid1Offline); boost::shared_ptr 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(muc, std::string("nick"))); std::string messageJIDString1("testling@test.com/1"); ChatWindow* window1 = new MockChatWindow();//mocks_->InterfaceMock(); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString1), uiEventStream_).Return(window1); uiEventStream_->send(boost::shared_ptr(new RequestChatUIEvent(JID(messageJIDString1)))); std::string messageJIDString2("testling@test.com/2"); ChatWindow* window2 = new MockChatWindow();//mocks_->InterfaceMock(); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString2), uiEventStream_).Return(window2); uiEventStream_->send(boost::shared_ptr(new RequestChatUIEvent(JID(messageJIDString2)))); std::string messageJIDString3("testling@test.com/3"); ChatWindow* window3 = new MockChatWindow();//mocks_->InterfaceMock(); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString3), uiEventStream_).Return(window3); uiEventStream_->send(boost::shared_ptr(new RequestChatUIEvent(JID(messageJIDString3)))); /* Refetch an earlier window */ /* We do not expect a new window to be created */ uiEventStream_->send(boost::shared_ptr(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(); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID1, uiEventStream_).Return(window1); boost::shared_ptr 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(); //mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID2, uiEventStream_).Return(window2); boost::shared_ptr message2(new Message()); message2->setFrom(messageJID2); message2->setBody("This is a legible message2."); manager_->handleIncomingMessage(message2); boost::shared_ptr jid1Online(new Presence()); jid1Online->setFrom(JID(messageJID1)); boost::shared_ptr jid1Offline(new Presence()); jid1Offline->setFrom(JID(messageJID1)); jid1Offline->setType(Presence::Unavailable); presenceOracle_->onPresenceChange(jid1Offline); boost::shared_ptr jid2Online(new Presence()); jid2Online->setFrom(JID(messageJID2)); boost::shared_ptr jid2Offline(new Presence()); jid2Offline->setFrom(JID(messageJID2)); jid2Offline->setType(Presence::Unavailable); presenceOracle_->onPresenceChange(jid2Offline); JID messageJID3("testling@test.com/resource3"); boost::shared_ptr 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 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(), RosterItemPayload::Both); MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock(); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window); settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, true); boost::shared_ptr message = makeDeliveryReceiptTestMessage(messageJID, "1"); manager_->handleIncomingMessage(message); Stanza::ref stanzaContactOnRoster = stanzaChannel_->getStanzaAtIndex(0); CPPUNIT_ASSERT_EQUAL(st(1), stanzaChannel_->sentStanzas.size()); CPPUNIT_ASSERT(stanzaContactOnRoster->getPayload() != 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(); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window); settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, true); boost::shared_ptr message = makeDeliveryReceiptTestMessage(messageJID, "1"); manager_->handleIncomingMessage(message); CPPUNIT_ASSERT_EQUAL(st(0), stanzaChannel_->sentStanzas.size()); xmppRoster_->addContact(messageJID, "foo", std::vector(), RosterItemPayload::Both); message->setID("2"); manager_->handleIncomingMessage(message); CPPUNIT_ASSERT_EQUAL(st(1), stanzaChannel_->sentStanzas.size()); Stanza::ref stanzaContactOnRoster = stanzaChannel_->getStanzaAtIndex(0); CPPUNIT_ASSERT(stanzaContactOnRoster->getPayload() != 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 testChatControllerFullJIDBindingOnMessageAndNotReceipt() { JID ownJID("test@test.com/resource"); JID sender("foo@test.com"); std::vector 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(boost::make_shared(sender)); foreach(const JID& senderJID, senderResource) { // The sender supports delivery receipts. DiscoInfo::ref disco = boost::make_shared(); disco->addFeature(DiscoInfo::MessageDeliveryReceiptsFeature); entityCapsProvider_->caps[senderJID] = disco; // The sender is online. Presence::ref senderPresence = boost::make_shared(); 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(0)->getTo()); CPPUNIT_ASSERT(stanzaChannel_->getStanzaAtIndex(0)->getPayload()); // Two resources respond with message receipts. foreach(const JID& senderJID, senderResource) { Message::ref receiptReply = boost::make_shared(); receiptReply->setFrom(senderJID); receiptReply->setTo(ownJID); boost::shared_ptr receipt = boost::make_shared(); receipt->setReceivedID(stanzaChannel_->getStanzaAtIndex(0)->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(1)->getTo()); CPPUNIT_ASSERT(stanzaChannel_->getStanzaAtIndex(1)->getPayload()); // Two resources respond with message receipts. foreach(const JID& senderJID, senderResource) { Message::ref receiptReply = boost::make_shared(); receiptReply->setFrom(senderJID); receiptReply->setTo(ownJID); boost::shared_ptr receipt = boost::make_shared(); receipt->setReceivedID(stanzaChannel_->getStanzaAtIndex(1)->getID()); receiptReply->addPayload(receipt); manager_->handleIncomingMessage(receiptReply); } // Reply with a message including a body text. Message::ref reply = boost::make_shared(); 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(2)->getTo()); CPPUNIT_ASSERT(stanzaChannel_->getStanzaAtIndex(2)->getPayload()); // Receive random receipt from second sender resource. reply = boost::make_shared(); reply->setFrom(senderResource[1]); reply->setTo(ownJID); boost::shared_ptr receipt = boost::make_shared(); receipt->setReceivedID(stanzaChannel_->getStanzaAtIndex(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(3)->getTo()); CPPUNIT_ASSERT(stanzaChannel_->getStanzaAtIndex(3)->getPayload()); // Reply with a message including a body text from second resource. reply = boost::make_shared(); 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(4)->getTo()); CPPUNIT_ASSERT(stanzaChannel_->getStanzaAtIndex(4)->getPayload()); } void testChatControllerFullJIDBindingOnTypingAndNotActive() { JID ownJID("test@test.com/resource"); JID sender("foo@test.com"); std::vector 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(boost::make_shared(sender)); foreach(const JID& senderJID, senderResource) { // The sender supports delivery receipts. DiscoInfo::ref disco = boost::make_shared(); disco->addFeature(DiscoInfo::MessageDeliveryReceiptsFeature); entityCapsProvider_->caps[senderJID] = disco; // The sender is online. Presence::ref senderPresence = boost::make_shared(); 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(0)->getTo()); CPPUNIT_ASSERT(stanzaChannel_->getStanzaAtIndex(0)->getPayload()); // Two resources respond with message receipts. foreach(const JID& senderJID, senderResource) { Message::ref reply = boost::make_shared(); reply->setFrom(senderJID); reply->setTo(ownJID); boost::shared_ptr csn = boost::make_shared(); 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(1)->getTo()); CPPUNIT_ASSERT(stanzaChannel_->getStanzaAtIndex(1)->getPayload()); // Two resources respond with message receipts. foreach(const JID& senderJID, senderResource) { Message::ref receiptReply = boost::make_shared(); receiptReply->setFrom(senderJID); receiptReply->setTo(ownJID); boost::shared_ptr receipt = boost::make_shared(); receipt->setReceivedID(stanzaChannel_->getStanzaAtIndex(1)->getID()); receiptReply->addPayload(receipt); manager_->handleIncomingMessage(receiptReply); } // Reply with a message including a CSN. Message::ref reply = boost::make_shared(); reply->setFrom(senderResource[0]); reply->setTo(ownJID); boost::shared_ptr csn = boost::make_shared(); 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(2)->getTo()); CPPUNIT_ASSERT(stanzaChannel_->getStanzaAtIndex(2)->getPayload()); // Reply with a message including a CSN from the other resource. reply = boost::make_shared(); reply->setFrom(senderResource[1]); reply->setTo(ownJID); csn = boost::make_shared(); 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(3)->getTo()); CPPUNIT_ASSERT(stanzaChannel_->getStanzaAtIndex(3)->getPayload()); } 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(boost::shared_ptr(new 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->lastReplacedMessage_)); } 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(boost::make_shared(sender)); CPPUNIT_ASSERT_EQUAL(false, window->impromptuMUCSupported_); boost::shared_ptr infoRequest= iqChannel_->iqs_[1]; boost::shared_ptr 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(boost::make_shared(info)); iqChannel_->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(), from); MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock(); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window); settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, true); boost::shared_ptr message = makeDeliveryReceiptTestMessage(messageJID, "1"); manager_->handleIncomingMessage(message); CPPUNIT_ASSERT_EQUAL(st(0), stanzaChannel_->sentStanzas.size()); xmppRoster_->addContact(messageJID, "foo", std::vector(), to); message->setID("2"); manager_->handleIncomingMessage(message); CPPUNIT_ASSERT_EQUAL(st(1), stanzaChannel_->sentStanzas.size()); Stanza::ref stanzaContactOnRoster = stanzaChannel_->getStanzaAtIndex(0); CPPUNIT_ASSERT(stanzaContactOnRoster->getPayload() != 0); } void testChatControllerHighlightingNotificationTesting() { HighlightRule keywordRuleA; keywordRuleA.setMatchChat(true); std::vector keywordsA; keywordsA.push_back("Romeo"); keywordRuleA.setKeywords(keywordsA); keywordRuleA.getAction().setTextColor("yellow"); keywordRuleA.getAction().setPlaySound(true); highlightManager_->insertRule(0, keywordRuleA); HighlightRule keywordRuleB; keywordRuleB.setMatchChat(true); std::vector keywordsB; keywordsB.push_back("Juliet"); keywordRuleB.setKeywords(keywordsB); keywordRuleB.getAction().setTextColor("green"); keywordRuleB.getAction().setPlaySound(true); keywordRuleB.getAction().setSoundFile("/tmp/someotherfile.wav"); highlightManager_->insertRule(0, keywordRuleB); JID messageJID = JID("testling@test.com"); MockChatWindow* window = new MockChatWindow(); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window); boost::shared_ptr 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.getAction().getSoundFile()) != soundsPlayed_.end()); CPPUNIT_ASSERT(soundsPlayed_.find(keywordRuleB.getAction().getSoundFile()) != soundsPlayed_.end()); } void testChatControllerHighlightingNotificationDeduplicateSounds() { HighlightRule keywordRuleA; keywordRuleA.setMatchChat(true); std::vector keywordsA; keywordsA.push_back("Romeo"); keywordRuleA.setKeywords(keywordsA); keywordRuleA.getAction().setTextColor("yellow"); keywordRuleA.getAction().setPlaySound(true); highlightManager_->insertRule(0, keywordRuleA); HighlightRule keywordRuleB; keywordRuleB.setMatchChat(true); std::vector keywordsB; keywordsB.push_back("Juliet"); keywordRuleB.setKeywords(keywordsB); keywordRuleB.getAction().setTextColor("green"); keywordRuleB.getAction().setPlaySound(true); highlightManager_->insertRule(0, keywordRuleB); JID messageJID = JID("testling@test.com"); MockChatWindow* window = new MockChatWindow(); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window); boost::shared_ptr 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.getAction().getSoundFile()) != soundsPlayed_.end()); CPPUNIT_ASSERT(soundsPlayed_.find(keywordRuleB.getAction().getSoundFile()) != soundsPlayed_.end()); } private: boost::shared_ptr makeDeliveryReceiptTestMessage(const JID& from, const std::string& id) { boost::shared_ptr message = boost::make_shared(); message->setFrom(from); message->setID(id); message->setBody("This will cause the window to open"); message->addPayload(boost::make_shared()); return message; } size_t st(int i) { return static_cast(i); } void handleHighlightAction(const HighlightAction& action) { handledHighlightActions_++; if (action.playSound()) { soundsPlayed_.insert(action.getSoundFile()); } } private: JID jid_; ChatsManager* manager_; DummyStanzaChannel* stanzaChannel_; DummyIQChannel* iqChannel_; IQRouter* iqRouter_; EventController* eventController_; ChatWindowFactory* chatWindowFactory_; JoinMUCWindowFactory* joinMUCWindowFactory_; NickResolver* nickResolver_; PresenceOracle* presenceOracle_; AvatarManager* avatarManager_; boost::shared_ptr 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 emoticons_; int handledHighlightActions_; std::set soundsPlayed_; }; CPPUNIT_TEST_SUITE_REGISTRATION(ChatsManagerTest);