diff options
Diffstat (limited to 'Swift/Controllers/Chat')
-rw-r--r-- | Swift/Controllers/Chat/ChatControllerBase.cpp | 8 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatsManager.cpp | 14 | ||||
-rw-r--r-- | Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp | 71 |
3 files changed, 78 insertions, 15 deletions
diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp index b339bd0..da9064e 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.cpp +++ b/Swift/Controllers/Chat/ChatControllerBase.cpp @@ -243,61 +243,67 @@ std::string ChatControllerBase::addMessage(const ChatWindow::ChatMessage& chatMe } void ChatControllerBase::replaceMessage(const ChatWindow::ChatMessage& chatMessage, const std::string& id, const boost::posix_time::ptime& time) { if (chatMessage.isMeCommand()) { chatWindow_->replaceWithAction(chatMessage, id, time); } else { chatWindow_->replaceMessage(chatMessage, id, time); } } bool ChatControllerBase::isFromContact(const JID& from) { return from.toBare() == toJID_.toBare(); } void ChatControllerBase::handleIncomingMessage(std::shared_ptr<MessageEvent> messageEvent) { preHandleIncomingMessage(messageEvent); if (messageEvent->isReadable() && !messageEvent->getConcluded()) { unreadMessages_.push_back(messageEvent); if (messageEvent->targetsMe()) { targetedUnreadMessages_.push_back(messageEvent); } } std::shared_ptr<Message> message = messageEvent->getStanza(); ChatWindow::ChatMessage chatMessage; boost::optional<std::string> optionalBody = message->getBody(); std::string body = optionalBody.get_value_or(""); if (message->isError()) { if (!message->getTo().getResource().empty()) { - std::string errorMessage = str(format(QT_TRANSLATE_NOOP("", "Couldn't send message: %1%")) % getErrorMessage(message->getPayload<ErrorPayload>())); + std::string errorMessage; + if (message->getPayload<Swift::ErrorPayload>()->getCondition() == ErrorPayload::ItemNotFound) { + errorMessage = QT_TRANSLATE_NOOP("", "This user could not be found in the room."); + } + else { + errorMessage = str(format(QT_TRANSLATE_NOOP("", "Couldn't send message: %1%")) % getErrorMessage(message->getPayload<ErrorPayload>())); + } chatWindow_->addErrorMessage(chatMessageParser_->parseMessageBody(errorMessage)); } } else if (messageEvent->getStanza()->getPayload<MUCInvitationPayload>()) { handleMUCInvitation(messageEvent->getStanza()); return; } else if (messageEvent->getStanza()->getPayload<MUCUserPayload>() && messageEvent->getStanza()->getPayload<MUCUserPayload>()->getInvite()) { handleMediatedMUCInvitation(messageEvent->getStanza()); return; } else { if (!messageEvent->isReadable()) { return; } showChatWindow(); JID from = message->getFrom(); std::vector<std::shared_ptr<Delay> > delayPayloads = message->getPayloads<Delay>(); for (size_t i = 0; useDelayForLatency_ && i < delayPayloads.size(); i++) { if (!delayPayloads[i]->getFrom()) { continue; } boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time(); std::ostringstream s; s << "The following message took " << (now - delayPayloads[i]->getStamp()).total_milliseconds() / 1000.0 << " seconds to be delivered from " << delayPayloads[i]->getFrom()->toString() << "."; chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(std::string(s.str())), ChatWindow::DefaultDirection); } std::shared_ptr<SecurityLabel> label = message->getPayload<SecurityLabel>(); // Determine the timestamp diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp index b9e2cf4..4f95d71 100644 --- a/Swift/Controllers/Chat/ChatsManager.cpp +++ b/Swift/Controllers/Chat/ChatsManager.cpp @@ -910,62 +910,72 @@ void ChatsManager::handleIncomingMessage(std::shared_ptr<Message> incomingMessag (forwardedMessage = std::dynamic_pointer_cast<Message>(forwarded->getStanza()))) { message = forwardedMessage; } else if ((carbonsSent = incomingMessage->getPayload<CarbonsSent>()) && (forwarded = carbonsSent->getForwarded()) && (forwardedMessage = std::dynamic_pointer_cast<Message>(forwarded->getStanza()))) { JID toJID = forwardedMessage->getTo(); ChatController* controller = getChatControllerOrCreate(toJID); if (controller) { controller->handleIncomingOwnMessage(forwardedMessage); } else { SWIFT_LOG(error) << "Carbons message ignored." << std::endl; } return; } } JID fromJID = message->getFrom(); std::shared_ptr<MessageEvent> event(new MessageEvent(message)); bool isInvite = !!message->getPayload<MUCInvitationPayload>(); bool isMediatedInvite = (message->getPayload<MUCUserPayload>() && message->getPayload<MUCUserPayload>()->getInvite()); if (isMediatedInvite) { fromJID = (*message->getPayload<MUCUserPayload>()->getInvite()).from; } if (!event->isReadable() && !message->getPayload<ChatState>() && !message->getPayload<DeliveryReceipt>() && !message->getPayload<DeliveryReceiptRequest>() && !isInvite && !isMediatedInvite && !message->hasSubject()) { return; } - // Try to deliver it to a MUC - if (message->getType() == Message::Groupchat || message->getType() == Message::Error /*|| (isInvite && message->getType() == Message::Normal)*/) { + // Try to deliver MUC errors to a MUC PM window if a suitable window is open. + if (message->getType() == Message::Error) { + auto controller = getChatControllerIfExists(fromJID, messageCausesSessionBinding(message)); + if (controller) { + controller->handleIncomingMessage(event); + return; + } + } + + // Try to deliver it to a MUC. + if (message->getType() == Message::Groupchat || message->getType() == Message::Error) { + // Try to deliver it to a MUC room. std::map<JID, MUCController*>::iterator i = mucControllers_.find(fromJID.toBare()); if (i != mucControllers_.end()) { i->second->handleIncomingMessage(event); return; } else if (message->getType() == Message::Groupchat) { //FIXME: Error handling - groupchat messages from an unknown muc. return; } } // check for impromptu invite to potentially auto-accept MUCInvitationPayload::ref invite = message->getPayload<MUCInvitationPayload>(); if (invite && autoAcceptMUCInviteDecider_->isAutoAcceptedInvite(message->getFrom(), invite)) { if (invite->getIsContinuation()) { // check for existing chat controller for the from JID ChatController* controller = getChatControllerIfExists(fromJID); if (controller) { ChatWindow* window = controller->detachChatWindow(); chatControllers_.erase(fromJID); delete controller; handleJoinMUCRequest(invite->getJID(), boost::optional<std::string>(), boost::optional<std::string>(), false, false, true, window); return; } } else { handleJoinMUCRequest(invite->getJID(), boost::optional<std::string>(), boost::optional<std::string>(), false, false, true); return; } } diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp index a5e68cf..cff54f8 100644 --- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp @@ -54,64 +54,67 @@ #include <Swift/Controllers/UIEvents/RequestChatUIEvent.h> #include <Swift/Controllers/UIEvents/UIEventStream.h> #include <Swift/Controllers/UIInterfaces/ChatListWindowFactory.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 <Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h> #include <Swift/Controllers/UnitTest/MockChatWindow.h> #include <Swift/Controllers/WhiteboardManager.h> #include <Swift/Controllers/XMPPEvents/EventController.h> 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(testPresenceChangeDoesNotReplaceMUCInvite); + // MUC PM Tests + CPPUNIT_TEST(testChatControllerPMPresenceHandling); + CPPUNIT_TEST(testChatControllerMucPmUnavailableErrorHandling); + // Highlighting tests CPPUNIT_TEST(testChatControllerHighlightingNotificationTesting); CPPUNIT_TEST(testChatControllerHighlightingNotificationDeduplicateSounds); CPPUNIT_TEST(testChatControllerMeMessageHandling); CPPUNIT_TEST(testRestartingMUCComponentCrash); CPPUNIT_TEST(testChatControllerMeMessageHandlingInMUC); // Carbons tests CPPUNIT_TEST(testCarbonsForwardedIncomingMessageToSecondResource); CPPUNIT_TEST(testCarbonsForwardedOutgoingMessageFromSecondResource); CPPUNIT_TEST_SUITE_END(); public: void setUp() { mocks_ = new MockRepository(); 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_); @@ -163,202 +166,202 @@ public: 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_->InterfaceMock<ChatWindow>(); + 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_->InterfaceMock<ChatWindow>(); + 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_->InterfaceMock<ChatWindow>(); + 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_->InterfaceMock<ChatWindow>(); + 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_->InterfaceMock<ChatWindow>(); + 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_->InterfaceMock<ChatWindow>(); + 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_->InterfaceMock<ChatWindow>(); + 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_->InterfaceMock<ChatWindow>(); + 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_->InterfaceMock<ChatWindow>(); + 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_->InterfaceMock<ChatWindow>(); + 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"); @@ -380,61 +383,61 @@ public: /** * 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_->InterfaceMock<ChatWindow>(); + 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); } @@ -661,60 +664,104 @@ public: 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->lastReplacedMessage_)); } + 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>(2); + 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"); |