summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swift/Controllers/Chat/ChatController.cpp2
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp8
-rw-r--r--Swiften/Chat/ChatStateNotifier.cpp25
-rw-r--r--Swiften/Chat/ChatStateNotifier.h8
-rw-r--r--Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp279
5 files changed, 186 insertions, 136 deletions
diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp
index 9cef9fc..8cbf059 100644
--- a/Swift/Controllers/Chat/ChatController.cpp
+++ b/Swift/Controllers/Chat/ChatController.cpp
@@ -28,61 +28,61 @@
#include <Swiften/FileTransfer/FileTransferManager.h>
#include <Swift/Controllers/Chat/ChatMessageParser.h>
#include <Swift/Controllers/FileTransfer/FileTransferController.h>
#include <Swift/Controllers/Highlighting/Highlighter.h>
#include <Swift/Controllers/Intl.h>
#include <Swift/Controllers/SettingConstants.h>
#include <Swift/Controllers/StatusUtil.h>
#include <Swift/Controllers/Translator.h>
#include <Swift/Controllers/UIEvents/AcceptWhiteboardSessionUIEvent.h>
#include <Swift/Controllers/UIEvents/CancelWhiteboardSessionUIEvent.h>
#include <Swift/Controllers/UIEvents/InviteToMUCUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestChangeBlockStateUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestInviteToMUCUIEvent.h>
#include <Swift/Controllers/UIEvents/SendFileUIEvent.h>
#include <Swift/Controllers/UIEvents/ShowWhiteboardUIEvent.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
#include <Swift/Controllers/XMPPEvents/EventController.h>
#include <Swift/Controllers/XMPPEvents/IncomingFileTransferEvent.h>
namespace Swift {
/**
* The controller does not gain ownership of the stanzaChannel, nor the factory.
*/
ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider)
: ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, nickResolver, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider), userWantsReceipts_(userWantsReceipts), settings_(settings), clientBlockListManager_(clientBlockListManager) {
isInMUC_ = isInMUC;
lastWasPresence_ = false;
- chatStateNotifier_ = new ChatStateNotifier(stanzaChannel, contact, entityCapsProvider);
+ chatStateNotifier_ = new ChatStateNotifier(stanzaChannel, contact, entityCapsProvider, timerFactory, 20000);
chatStateTracker_ = new ChatStateTracker();
nickResolver_ = nickResolver;
presenceOracle_->onPresenceChange.connect(boost::bind(&ChatController::handlePresenceChange, this, _1));
chatStateTracker_->onChatStateChange.connect(boost::bind(&ChatWindow::setContactChatState, chatWindow_, _1));
stanzaChannel_->onStanzaAcked.connect(boost::bind(&ChatController::handleStanzaAcked, this, _1));
nickResolver_->onNickChanged.connect(boost::bind(&ChatController::handleContactNickChanged, this, _1, _2));
std::string nick = nickResolver_->jidToNick(toJID_);
chatWindow_->setName(nick);
std::string startMessage;
Presence::ref theirPresence;
if (isInMUC) {
startMessage = str(format(QT_TRANSLATE_NOOP("", "Starting chat with %1% in chatroom %2%")) % nick % contact.toBare().toString());
theirPresence = presenceOracle->getLastPresence(contact);
} else {
startMessage = str(format(QT_TRANSLATE_NOOP("", "Starting chat with %1% - %2%")) % nick % contact.toBare().toString());
theirPresence = contact.isBare() ? presenceOracle->getAccountPresence(contact) : presenceOracle->getLastPresence(contact);
}
Idle::ref idle;
if (theirPresence && (idle = theirPresence->getPayload<Idle>())) {
startMessage += str(format(QT_TRANSLATE_NOOP("", ", who has been idle since %1%")) % Swift::Translator::getInstance()->ptimeToHumanReadableString(idle->getSince()));
}
startMessage += ": " + statusShowTypeToFriendlyName(theirPresence ? theirPresence->getShow() : StatusShow::None);
if (theirPresence && !theirPresence->getStatus().empty()) {
startMessage += " (" + theirPresence->getStatus() + ")";
}
lastShownStatus_ = theirPresence ? theirPresence->getShow() : StatusShow::None;
chatStateNotifier_->setContactIsOnline(theirPresence && theirPresence->getType() == Presence::Available);
startMessage += ".";
chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(startMessage), ChatWindow::DefaultDirection);
chatWindow_->onUserTyping.connect(boost::bind(&ChatStateNotifier::setUserIsTyping, chatStateNotifier_));
diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
index 1958408..2f77ec7 100644
--- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
@@ -14,60 +14,61 @@
#include <hippomocks.h>
#include <Swiften/Avatars/AvatarMemoryStorage.h>
#include <Swiften/Avatars/NullAvatarManager.h>
#include <Swiften/Base/Algorithm.h>
#include <Swiften/Client/Client.h>
#include <Swiften/Client/ClientBlockListManager.h>
#include <Swiften/Client/DummyStanzaChannel.h>
#include <Swiften/Client/NickResolver.h>
#include <Swiften/Crypto/CryptoProvider.h>
#include <Swiften/Crypto/PlatformCryptoProvider.h>
#include <Swiften/Disco/DummyEntityCapsProvider.h>
#include <Swiften/Elements/CarbonsReceived.h>
#include <Swiften/Elements/CarbonsSent.h>
#include <Swiften/Elements/DeliveryReceipt.h>
#include <Swiften/Elements/DeliveryReceiptRequest.h>
#include <Swiften/Elements/Forwarded.h>
#include <Swiften/Elements/MUCInvitationPayload.h>
#include <Swiften/Elements/MUCUserPayload.h>
#include <Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h>
#include <Swiften/Jingle/JingleSessionManager.h>
#include <Swiften/MUC/MUCManager.h>
#include <Swiften/Presence/DirectedPresenceSender.h>
#include <Swiften/Presence/PresenceOracle.h>
#include <Swiften/Presence/StanzaChannelPresenceSender.h>
#include <Swiften/Queries/DummyIQChannel.h>
#include <Swiften/Roster/XMPPRosterImpl.h>
#include <Swiften/VCards/VCardManager.h>
#include <Swiften/VCards/VCardMemoryStorage.h>
#include <Swiften/Whiteboard/WhiteboardSessionManager.h>
+#include <Swiften/Network/DummyTimerFactory.h>
#include <Swift/Controllers/Chat/ChatController.h>
#include <Swift/Controllers/Chat/ChatsManager.h>
#include <Swift/Controllers/Chat/MUCController.h>
#include <Swift/Controllers/Chat/UnitTest/MockChatListWindow.h>
#include <Swift/Controllers/EventNotifier.h>
#include <Swift/Controllers/FileTransfer/FileTransferOverview.h>
#include <Swift/Controllers/ProfileSettingsProvider.h>
#include <Swift/Controllers/SettingConstants.h>
#include <Swift/Controllers/Settings/DummySettingsProvider.h>
#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIInterfaces/ChatListWindowFactory.h>
#include <Swift/Controllers/UIInterfaces/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>
#include <SwifTools/Notifier/Notifier.h>
using namespace Swift;
class DummyNotifier : public Notifier {
public:
virtual void showMessage(
@@ -152,94 +153,97 @@ public:
nickResolver_ = new NickResolver(jid_.toBare(), xmppRoster_, nullptr, mucRegistry_);
presenceOracle_ = new PresenceOracle(stanzaChannel_, xmppRoster_);
serverDiscoInfo_ = std::make_shared<DiscoInfo>();
presenceSender_ = new StanzaChannelPresenceSender(stanzaChannel_);
directedPresenceSender_ = new DirectedPresenceSender(presenceSender_);
mucManager_ = new MUCManager(stanzaChannel_, iqRouter_, directedPresenceSender_, mucRegistry_);
uiEventStream_ = new UIEventStream();
entityCapsProvider_ = new DummyEntityCapsProvider();
chatListWindowFactory_ = mocks_->InterfaceMock<ChatListWindowFactory>();
mucSearchWindowFactory_ = mocks_->InterfaceMock<MUCSearchWindowFactory>();
settings_ = new DummySettingsProvider();
profileSettings_ = new ProfileSettingsProvider("a", settings_);
chatListWindow_ = new MockChatListWindow();
ftManager_ = new DummyFileTransferManager();
ftOverview_ = new FileTransferOverview(ftManager_);
avatarManager_ = new NullAvatarManager();
eventNotifier_ = new EventNotifier(eventController_, notifier_.get(), avatarManager_, nickResolver_);
wbSessionManager_ = new WhiteboardSessionManager(iqRouter_, stanzaChannel_, presenceOracle_, entityCapsProvider_);
wbManager_ = new WhiteboardManager(whiteboardWindowFactory_, uiEventStream_, nickResolver_, wbSessionManager_);
highlightManager_ = new HighlightManager(settings_);
highlightManager_->resetToDefaultConfiguration();
handledHighlightActions_ = 0;
soundsPlayed_.clear();
highlightManager_->onHighlight.connect(boost::bind(&ChatsManagerTest::handleHighlightAction, this, _1));
crypto_ = PlatformCryptoProvider::create();
vcardStorage_ = new VCardMemoryStorage(crypto_);
vcardManager_ = new VCardManager(jid_, iqRouter_, vcardStorage_);
mocks_->ExpectCall(chatListWindowFactory_, ChatListWindowFactory::createChatListWindow).With(uiEventStream_).Return(chatListWindow_);
clientBlockListManager_ = new ClientBlockListManager(iqRouter_);
- manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, nullptr, mucRegistry_, entityCapsProvider_, mucManager_, mucSearchWindowFactory_, profileSettings_, ftOverview_, xmppRoster_, false, settings_, nullptr, wbManager_, highlightManager_, clientBlockListManager_, emoticons_, vcardManager_);
+ timerFactory_ = new DummyTimerFactory();
+ manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, timerFactory_, mucRegistry_, entityCapsProvider_, mucManager_, mucSearchWindowFactory_, profileSettings_, ftOverview_, xmppRoster_, false, settings_, nullptr, wbManager_, highlightManager_, clientBlockListManager_, emoticons_, vcardManager_);
manager_->setAvatarManager(avatarManager_);
}
void tearDown() {
delete highlightManager_;
delete profileSettings_;
delete eventNotifier_;
delete avatarManager_;
delete manager_;
+ delete timerFactory_;
delete clientBlockListManager_;
delete vcardManager_;
delete vcardStorage_;
delete crypto_;
delete ftOverview_;
delete ftManager_;
delete wbSessionManager_;
delete wbManager_;
delete directedPresenceSender_;
delete presenceSender_;
delete presenceOracle_;
delete nickResolver_;
delete mucRegistry_;
delete iqRouter_;
delete stanzaChannel_;
delete eventController_;
delete uiEventStream_;
delete mucManager_;
delete xmppRoster_;
delete entityCapsProvider_;
delete chatListWindow_;
delete mocks_;
delete settings_;
+
}
void testFirstOpenWindowIncoming() {
JID messageJID("testling@test.com/resource1");
MockChatWindow* window = new MockChatWindow();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
std::shared_ptr<Message> message(new Message());
message->setFrom(messageJID);
std::string body("This is a legible message. >HEH@)oeueu");
message->setBody(body);
manager_->handleIncomingMessage(message);
CPPUNIT_ASSERT_EQUAL(body, MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
}
void testSecondOpenWindowIncoming() {
JID messageJID1("testling@test.com/resource1");
MockChatWindow* window1 = new MockChatWindow();
mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID1, uiEventStream_).Return(window1);
std::shared_ptr<Message> message1(new Message());
message1->setFrom(messageJID1);
std::string body1("This is a legible message. >HEH@)oeueu");
message1->setBody(body1);
manager_->handleIncomingMessage(message1);
CPPUNIT_ASSERT_EQUAL(body1, MockChatWindow::bodyFromMessage(window1->lastAddedMessage_));
JID messageJID2("testling@test.com/resource2");
@@ -1295,34 +1299,36 @@ private:
PresenceOracle* presenceOracle_;
AvatarManager* avatarManager_;
EventNotifier* eventNotifier_;
std::shared_ptr<DiscoInfo> serverDiscoInfo_;
XMPPRosterImpl* xmppRoster_;
PresenceSender* presenceSender_;
MockRepository* mocks_;
UIEventStream* uiEventStream_;
ChatListWindowFactory* chatListWindowFactory_;
WhiteboardWindowFactory* whiteboardWindowFactory_;
MUCSearchWindowFactory* mucSearchWindowFactory_;
MUCRegistry* mucRegistry_;
DirectedPresenceSender* directedPresenceSender_;
DummyEntityCapsProvider* entityCapsProvider_;
MUCManager* mucManager_;
DummySettingsProvider* settings_;
ProfileSettingsProvider* profileSettings_;
ChatListWindow* chatListWindow_;
FileTransferOverview* ftOverview_;
FileTransferManager* ftManager_;
WhiteboardSessionManager* wbSessionManager_;
WhiteboardManager* wbManager_;
HighlightManager* highlightManager_;
ClientBlockListManager* clientBlockListManager_;
VCardManager* vcardManager_;
CryptoProvider* crypto_;
VCardStorage* vcardStorage_;
std::map<std::string, std::string> emoticons_;
int handledHighlightActions_;
std::set<std::string> soundsPlayed_;
+ DummyTimerFactory* timerFactory_;
+
};
CPPUNIT_TEST_SUITE_REGISTRATION(ChatsManagerTest);
diff --git a/Swiften/Chat/ChatStateNotifier.cpp b/Swiften/Chat/ChatStateNotifier.cpp
index cbb9b0b..48a65ab 100644
--- a/Swiften/Chat/ChatStateNotifier.cpp
+++ b/Swiften/Chat/ChatStateNotifier.cpp
@@ -1,89 +1,112 @@
/*
* Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swiften/Chat/ChatStateNotifier.h>
+#include <cassert>
#include <memory>
#include <boost/bind.hpp>
#include <Swiften/Client/StanzaChannel.h>
#include <Swiften/Disco/EntityCapsProvider.h>
#include <Swiften/Elements/ChatState.h>
#include <Swiften/Elements/Message.h>
+#include <Swiften/Network/Timer.h>
+#include <Swiften/Network/TimerFactory.h>
+
namespace Swift {
-ChatStateNotifier::ChatStateNotifier(StanzaChannel* stanzaChannel, const JID& contact, EntityCapsProvider* entityCapsManager) : stanzaChannel_(stanzaChannel), entityCapsManager_(entityCapsManager), contact_(contact) {
+
+ChatStateNotifier::ChatStateNotifier(StanzaChannel* stanzaChannel, const JID& contact, EntityCapsProvider* entityCapsManager, TimerFactory* timerFactory, int idleTimeInMilliSecs) : stanzaChannel_(stanzaChannel), entityCapsManager_(entityCapsManager), contact_(contact) {
setContact(contact);
entityCapsManager_->onCapsChanged.connect(boost::bind(&ChatStateNotifier::handleCapsChanged, this, _1));
+ assert(timerFactory);
+ idleTimer_ = timerFactory->createTimer(idleTimeInMilliSecs);
+ assert(!!idleTimer_);
+ idleTimer_->onTick.connect(boost::bind(&ChatStateNotifier::userBecameIdleWhileTyping, this));
}
ChatStateNotifier::~ChatStateNotifier() {
entityCapsManager_->onCapsChanged.disconnect(boost::bind(&ChatStateNotifier::handleCapsChanged, this, _1));
+ idleTimer_->stop();
+ idleTimer_->onTick.disconnect(boost::bind(&ChatStateNotifier::userBecameIdleWhileTyping, this));
}
void ChatStateNotifier::setContact(const JID& contact) {
contactHasSentActive_ = false;
userIsTyping_ = false;
contactIsOnline_ = false;
contact_ = contact;
handleCapsChanged(contact_);
}
void ChatStateNotifier::setContactIsOnline(bool online) {
contactIsOnline_ = online;
}
void ChatStateNotifier::setUserIsTyping() {
+ idleTimer_->stop();
bool should = contactShouldReceiveStates();
if (should && !userIsTyping_) {
userIsTyping_ = true;
changeState(ChatState::Composing);
}
+ if (should) {
+ idleTimer_->start();
+ }
}
void ChatStateNotifier::userSentMessage() {
+ idleTimer_->stop();
userIsTyping_ = false;
}
void ChatStateNotifier::userCancelledNewMessage() {
+ idleTimer_->stop();
if (userIsTyping_) {
userIsTyping_ = false;
changeState(ChatState::Active);
}
}
+void ChatStateNotifier::userBecameIdleWhileTyping() {
+ // For now we are returning to active state. When support for the Paused, Inactive and Gone states
+ // is implemeted, this function should Implement the Pause/Inactive functionality.
+ userCancelledNewMessage();
+}
+
void ChatStateNotifier::receivedMessageFromContact(bool hasActiveElement) {
contactHasSentActive_ = hasActiveElement;
}
bool ChatStateNotifier::contactShouldReceiveStates() {
/* So, yes, the XEP says to look at caps, but it also says that once you've
heard from the contact, the active state overrides this.
*HOWEVER* it says that the MUST NOT send csn if you haven't received
active is OPTIONAL behaviour for if you haven't got caps.*/
return contactIsOnline_ && (contactHasSentActive_ || contactHas85Caps_);
}
void ChatStateNotifier::changeState(ChatState::ChatStateType state) {
std::shared_ptr<Message> message(std::make_shared<Message>());
message->setTo(contact_);
message->addPayload(std::make_shared<ChatState>(state));
stanzaChannel_->sendMessage(message);
}
void ChatStateNotifier::addChatStateRequest(Message::ref message) {
if (contactShouldReceiveStates()) {
message->addPayload(std::make_shared<ChatState>(ChatState::Active));
}
}
void ChatStateNotifier::handleCapsChanged(const JID& jid) {
if (jid == contact_) {
DiscoInfo::ref caps = entityCapsManager_->getCaps(contact_);
bool hasCSN = caps && caps->hasFeature(DiscoInfo::ChatStatesFeature);
diff --git a/Swiften/Chat/ChatStateNotifier.h b/Swiften/Chat/ChatStateNotifier.h
index a7af9e4..2b24c76 100644
--- a/Swiften/Chat/ChatStateNotifier.h
+++ b/Swiften/Chat/ChatStateNotifier.h
@@ -1,52 +1,58 @@
/*
* Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#pragma once
#include <memory>
#include <boost/signals2.hpp>
#include <Swiften/Base/API.h>
#include <Swiften/Elements/ChatState.h>
#include <Swiften/Elements/Message.h>
#include <Swiften/JID/JID.h>
namespace Swift {
class StanzaChannel;
class EntityCapsProvider;
+ class TimerFactory;
+ class Timer;
+
class SWIFTEN_API ChatStateNotifier {
public:
- ChatStateNotifier(StanzaChannel* stanzaChannel, const JID& contact, EntityCapsProvider* entityCapsManager);
+ ChatStateNotifier(StanzaChannel* stanzaChannel, const JID& contact, EntityCapsProvider* entityCapsManager, TimerFactory* timerFactory, int idleTimeInMilliSecs);
~ChatStateNotifier();
void setContact(const JID& contact);
void addChatStateRequest(Message::ref message);
void setUserIsTyping();
void userSentMessage();
void userCancelledNewMessage();
void receivedMessageFromContact(bool hasActiveElement);
void setContactIsOnline(bool online);
private:
+ void userBecameIdleWhileTyping();
bool contactShouldReceiveStates();
void changeState(ChatState::ChatStateType type);
void handleCapsChanged(const JID& contact);
private:
StanzaChannel* stanzaChannel_;
EntityCapsProvider* entityCapsManager_;
JID contact_;
bool contactHas85Caps_;
bool contactHasSentActive_;
bool userIsTyping_;
bool contactIsOnline_;
+ std::shared_ptr<Timer> idleTimer_;
+
};
}
diff --git a/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp b/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp
index 7eeb531..efd37d9 100644
--- a/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp
+++ b/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp
@@ -1,168 +1,183 @@
/*
* Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <boost/bind.hpp>
-#include <cppunit/extensions/HelperMacros.h>
-#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <gtest/gtest.h>
#include <Swiften/Chat/ChatStateNotifier.h>
#include <Swiften/Client/DummyStanzaChannel.h>
#include <Swiften/Disco/DummyEntityCapsProvider.h>
+#include <Swiften/Network/DummyTimerFactory.h>
using namespace Swift;
-class ChatStateNotifierTest : public CppUnit::TestFixture {
- CPPUNIT_TEST_SUITE(ChatStateNotifierTest);
- CPPUNIT_TEST(testStartTypingReply_CapsNotIncluded);
- CPPUNIT_TEST(testStartTypingReply_CapsIncluded);
- CPPUNIT_TEST(testCancelledNewMessage);
- CPPUNIT_TEST(testContinueTypingReply_CapsIncluded);
- CPPUNIT_TEST(testTypeReplies_WentOffline);
- CPPUNIT_TEST(testContactShouldReceiveStates_CapsOnly);
- CPPUNIT_TEST(testContactShouldReceiveStates_CapsNorActive);
- CPPUNIT_TEST(testContactShouldReceiveStates_ActiveOverrideOn);
- CPPUNIT_TEST(testContactShouldReceiveStates_ActiveOverrideOff);
- CPPUNIT_TEST_SUITE_END();
-
-public:
- void setUp() {
+class ChatStateNotifierTest : public ::testing::Test {
+
+protected:
+ virtual void SetUp() {
stanzaChannel = new DummyStanzaChannel();
stanzaChannel->setAvailable(true);
entityCapsProvider = new DummyEntityCapsProvider();
- notifier_ = new ChatStateNotifier(stanzaChannel, JID("foo@bar.com/baz"), entityCapsProvider);
+ timerFactory_ = new DummyTimerFactory();
+ notifier_ = new ChatStateNotifier(stanzaChannel, JID("foo@bar.com/baz"), entityCapsProvider, timerFactory_, 2);
notifier_->setContactIsOnline(true);
}
- void tearDown() {
+ virtual void TearDown() {
delete notifier_;
+ delete timerFactory_;
delete entityCapsProvider;
delete stanzaChannel;
}
- void testStartTypingReply_CapsNotIncluded() {
- notifier_->setUserIsTyping();
- CPPUNIT_ASSERT_EQUAL(0, getComposingCount());
- }
-
- void testSendTwoMessages() {
- setContactHas85Caps();
- notifier_->setUserIsTyping();
- notifier_->userSentMessage();
- notifier_->setUserIsTyping();
- notifier_->userSentMessage();
- CPPUNIT_ASSERT_EQUAL(2, getComposingCount());
- }
-
- void testCancelledNewMessage() {
- setContactHas85Caps();
- notifier_->setUserIsTyping();
- notifier_->userCancelledNewMessage();
- CPPUNIT_ASSERT_EQUAL(1, getComposingCount());
- CPPUNIT_ASSERT_EQUAL(1, getActiveCount());
- CPPUNIT_ASSERT_EQUAL(ChatState::Active, stanzaChannel->sentStanzas[stanzaChannel->sentStanzas.size()-1]->getPayload<ChatState>()->getChatState());
- }
-
-
- void testContactShouldReceiveStates_CapsOnly() {
- setContactHas85Caps();
- std::shared_ptr<Message> message(new Message());
- notifier_->addChatStateRequest(message);
- CPPUNIT_ASSERT(message->getPayload<ChatState>());
- CPPUNIT_ASSERT_EQUAL(ChatState::Active, message->getPayload<ChatState>()->getChatState());
- }
-
- void testContactShouldReceiveStates_CapsNorActive() {
- std::shared_ptr<Message> message(new Message());
- notifier_->addChatStateRequest(message);
- CPPUNIT_ASSERT(!message->getPayload<ChatState>());
- }
-
- void testContactShouldReceiveStates_ActiveOverrideOn() {
- notifier_->receivedMessageFromContact(true);
- std::shared_ptr<Message> message(new Message());
- notifier_->addChatStateRequest(message);
- CPPUNIT_ASSERT(message->getPayload<ChatState>());
- CPPUNIT_ASSERT_EQUAL(ChatState::Active, message->getPayload<ChatState>()->getChatState());
- }
-
- void testContactShouldReceiveStates_ActiveOverrideOff() {
- setContactHas85Caps();
- notifier_->receivedMessageFromContact(false);
- /* I originally read the MUST NOT send after receiving without Active and
- * thought this should check for false, but I later found it was OPTIONAL
- * (MAY) behaviour only for if you didn't receive caps.
- */
- std::shared_ptr<Message> message(new Message());
- notifier_->addChatStateRequest(message);
- CPPUNIT_ASSERT(message->getPayload<ChatState>());
- CPPUNIT_ASSERT_EQUAL(ChatState::Active, message->getPayload<ChatState>()->getChatState());
- }
-
-
- void testStartTypingReply_CapsIncluded() {
- setContactHas85Caps();
- notifier_->setUserIsTyping();
- CPPUNIT_ASSERT_EQUAL(1, getComposingCount());
- }
-
- void testContinueTypingReply_CapsIncluded() {
- setContactHas85Caps();
- notifier_->setUserIsTyping();
- notifier_->setUserIsTyping();
- notifier_->setUserIsTyping();
- CPPUNIT_ASSERT_EQUAL(1, getComposingCount());
- notifier_->userSentMessage();
- notifier_->setUserIsTyping();
- CPPUNIT_ASSERT_EQUAL(2, getComposingCount());
-
+ void setContactHas85Caps() {
+ DiscoInfo::ref caps(new DiscoInfo());
+ caps->addFeature(DiscoInfo::ChatStatesFeature);
+ entityCapsProvider->caps[JID("foo@bar.com/baz")] = caps;
+ entityCapsProvider->onCapsChanged(JID("foo@bar.com/baz"));
}
- void testTypeReplies_WentOffline() {
- setContactHas85Caps();
- notifier_->setUserIsTyping();
- CPPUNIT_ASSERT_EQUAL(1, getComposingCount());
- notifier_->setContactIsOnline(false);
- notifier_->userSentMessage();
- notifier_->setUserIsTyping();
- CPPUNIT_ASSERT_EQUAL(1, getComposingCount());
- }
-
- private:
- void setContactHas85Caps() {
- DiscoInfo::ref caps(new DiscoInfo());
- caps->addFeature(DiscoInfo::ChatStatesFeature);
- entityCapsProvider->caps[JID("foo@bar.com/baz")] = caps;
- entityCapsProvider->onCapsChanged(JID("foo@bar.com/baz"));
- }
-
- int getComposingCount() const {
- int result = 0;
- for (auto&& stanza : stanzaChannel->sentStanzas) {
- if (stanza->getPayload<ChatState>() && stanza->getPayload<ChatState>()->getChatState() == ChatState::Composing) {
- result++;
- }
+ int getComposingCount() const {
+ int result = 0;
+ for (auto&& stanza : stanzaChannel->sentStanzas) {
+ if (stanza->getPayload<ChatState>() && stanza->getPayload<ChatState>()->getChatState() == ChatState::Composing) {
+ result++;
}
- return result;
}
+ return result;
+ }
- int getActiveCount() const {
- int result = 0;
- for (auto&& stanza : stanzaChannel->sentStanzas) {
- if (stanza->getPayload<ChatState>() && stanza->getPayload<ChatState>()->getChatState() == ChatState::Active) {
- result++;
- }
+ int getActiveCount() const {
+ int result = 0;
+ for (auto&& stanza : stanzaChannel->sentStanzas) {
+ if (stanza->getPayload<ChatState>() && stanza->getPayload<ChatState>()->getChatState() == ChatState::Active) {
+ result++;
}
- return result;
}
+ return result;
+ }
- private:
- DummyStanzaChannel* stanzaChannel;
- DummyEntityCapsProvider* entityCapsProvider;
- ChatStateNotifier* notifier_;
+ DummyStanzaChannel* stanzaChannel;
+ DummyEntityCapsProvider* entityCapsProvider;
+ DummyTimerFactory* timerFactory_;
+ ChatStateNotifier* notifier_;
};
-CPPUNIT_TEST_SUITE_REGISTRATION(ChatStateNotifierTest);
+TEST_F(ChatStateNotifierTest, testStartTypingReply_CapsNotIncluded) {
+ notifier_->setUserIsTyping();
+ ASSERT_EQ(0, getComposingCount());
+}
+
+TEST_F(ChatStateNotifierTest, testSendTwoMessages) {
+ setContactHas85Caps();
+ notifier_->setUserIsTyping();
+ notifier_->userSentMessage();
+ notifier_->setUserIsTyping();
+ notifier_->userSentMessage();
+ ASSERT_EQ(2, getComposingCount());
+}
+
+TEST_F(ChatStateNotifierTest, testCancelledNewMessage) {
+ setContactHas85Caps();
+ notifier_->setUserIsTyping();
+ notifier_->userCancelledNewMessage();
+ ASSERT_EQ(1, getComposingCount());
+ ASSERT_EQ(1, getActiveCount());
+ ASSERT_EQ(ChatState::Active, stanzaChannel->sentStanzas[stanzaChannel->sentStanzas.size() - 1]->getPayload<ChatState>()->getChatState());
+}
+
+TEST_F(ChatStateNotifierTest, testIdleWhileTypingNewMessage) {
+ setContactHas85Caps();
+ //The channel should be empty
+ ASSERT_EQ(0, getComposingCount());
+ ASSERT_EQ(0, getActiveCount());
+ notifier_->setUserIsTyping();
+ timerFactory_->setTime(1);
+ //1 Composing stanza is expected
+ ASSERT_EQ(1, getComposingCount());
+ ASSERT_EQ(0, getActiveCount());
+ timerFactory_->setTime(2);
+ //The idleTimer period has expired, the channel should have 1 composing and 1 active status stanza
+ ASSERT_EQ(1, getComposingCount());
+ ASSERT_EQ(1, getActiveCount());
+ ASSERT_EQ(ChatState::Active, stanzaChannel->sentStanzas[stanzaChannel->sentStanzas.size() - 1]->getPayload<ChatState>()->getChatState());
+ timerFactory_->setTime(4);
+ //At the second tick no further state stanzas should be sent.
+ ASSERT_EQ(1, getComposingCount());
+ ASSERT_EQ(1, getActiveCount());
+ ASSERT_EQ(ChatState::Active, stanzaChannel->sentStanzas[stanzaChannel->sentStanzas.size() - 1]->getPayload<ChatState>()->getChatState());
+}
+
+TEST_F(ChatStateNotifierTest, testIdleWhileTypingNewMessageNoCaps) {
+ notifier_->setUserIsTyping();
+ timerFactory_->setTime(3);
+ ASSERT_EQ(0, getComposingCount());
+ ASSERT_EQ(0, getActiveCount());
+}
+TEST_F(ChatStateNotifierTest, testContactShouldReceiveStates_CapsOnly) {
+ setContactHas85Caps();
+ std::shared_ptr<Message> message(new Message());
+ notifier_->addChatStateRequest(message);
+ EXPECT_TRUE(message->getPayload<ChatState>());
+ ASSERT_EQ(ChatState::Active, message->getPayload<ChatState>()->getChatState());
+}
+
+TEST_F(ChatStateNotifierTest, testContactShouldReceiveStates_CapsNorActive) {
+ std::shared_ptr<Message> message(new Message());
+ notifier_->addChatStateRequest(message);
+ EXPECT_TRUE(!message->getPayload<ChatState>());
+}
+
+TEST_F(ChatStateNotifierTest, testContactShouldReceiveStates_ActiveOverrideOn) {
+ notifier_->receivedMessageFromContact(true);
+ std::shared_ptr<Message> message(new Message());
+ notifier_->addChatStateRequest(message);
+ EXPECT_TRUE(message->getPayload<ChatState>());
+ ASSERT_EQ(ChatState::Active, message->getPayload<ChatState>()->getChatState());
+}
+
+TEST_F(ChatStateNotifierTest, testContactShouldReceiveStates_ActiveOverrideOff) {
+ setContactHas85Caps();
+ notifier_->receivedMessageFromContact(false);
+ /* I originally read the MUST NOT send after receiving without Active and
+ * thought this should check for false, but I later found it was OPTIONAL
+ * (MAY) behaviour only for if you didn't receive caps.
+ */
+ std::shared_ptr<Message> message(new Message());
+ notifier_->addChatStateRequest(message);
+ EXPECT_TRUE(message->getPayload<ChatState>());
+ ASSERT_EQ(ChatState::Active, message->getPayload<ChatState>()->getChatState());
+}
+
+
+TEST_F(ChatStateNotifierTest, testStartTypingReply_CapsIncluded) {
+ setContactHas85Caps();
+ notifier_->setUserIsTyping();
+ ASSERT_EQ(1, getComposingCount());
+}
+
+TEST_F(ChatStateNotifierTest, testContinueTypingReply_CapsIncluded) {
+ setContactHas85Caps();
+ notifier_->setUserIsTyping();
+ notifier_->setUserIsTyping();
+ notifier_->setUserIsTyping();
+ ASSERT_EQ(1, getComposingCount());
+ notifier_->userSentMessage();
+ notifier_->setUserIsTyping();
+ ASSERT_EQ(2, getComposingCount());
+
+}
+
+TEST_F(ChatStateNotifierTest, testTypeReplies_WentOffline) {
+ setContactHas85Caps();
+ notifier_->setUserIsTyping();
+ ASSERT_EQ(1, getComposingCount());
+ notifier_->setContactIsOnline(false);
+ notifier_->userSentMessage();
+ notifier_->setUserIsTyping();
+ ASSERT_EQ(1, getComposingCount());
+}