summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/Chat')
-rw-r--r--Swiften/Chat/ChatStateNotifier.cpp112
-rw-r--r--Swiften/Chat/ChatStateNotifier.h85
-rw-r--r--Swiften/Chat/ChatStateTracker.cpp40
-rw-r--r--Swiften/Chat/ChatStateTracker.h35
-rw-r--r--Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp328
5 files changed, 325 insertions, 275 deletions
diff --git a/Swiften/Chat/ChatStateNotifier.cpp b/Swiften/Chat/ChatStateNotifier.cpp
index d507c4d..48a65ab 100644
--- a/Swiften/Chat/ChatStateNotifier.cpp
+++ b/Swiften/Chat/ChatStateNotifier.cpp
@@ -1,93 +1,117 @@
/*
- * Copyright (c) 2010 Kevin Smith
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * 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 <boost/smart_ptr/make_shared.hpp>
-#include <Swiften/Elements/Message.h>
-#include <Swiften/Elements/ChatState.h>
#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) {
- setContact(contact);
- entityCapsManager_->onCapsChanged.connect(boost::bind(&ChatStateNotifier::handleCapsChanged, this, _1));
+
+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));
+ 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_);
+ contactHasSentActive_ = false;
+ userIsTyping_ = false;
+ contactIsOnline_ = false;
+ contact_ = contact;
+ handleCapsChanged(contact_);
}
void ChatStateNotifier::setContactIsOnline(bool online) {
- contactIsOnline_ = online;
+ contactIsOnline_ = online;
}
void ChatStateNotifier::setUserIsTyping() {
- bool should = contactShouldReceiveStates();
- if (should && !userIsTyping_) {
- userIsTyping_ = true;
- changeState(ChatState::Composing);
- }
+ idleTimer_->stop();
+ bool should = contactShouldReceiveStates();
+ if (should && !userIsTyping_) {
+ userIsTyping_ = true;
+ changeState(ChatState::Composing);
+ }
+ if (should) {
+ idleTimer_->start();
+ }
}
void ChatStateNotifier::userSentMessage() {
- userIsTyping_ = false;
+ idleTimer_->stop();
+ userIsTyping_ = false;
}
void ChatStateNotifier::userCancelledNewMessage() {
- if (userIsTyping_) {
- userIsTyping_ = false;
- changeState(ChatState::Active);
- }
+ 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;
+ 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_);
+ /* 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) {
- boost::shared_ptr<Message> message(boost::make_shared<Message>());
- message->setTo(contact_);
- message->addPayload(boost::make_shared<ChatState>(state));
- stanzaChannel_->sendMessage(message);
+ 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(boost::make_shared<ChatState>(ChatState::Active));
- }
+ 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);
- contactHas85Caps_ = hasCSN;
- }
+ if (jid == contact_) {
+ DiscoInfo::ref caps = entityCapsManager_->getCaps(contact_);
+ bool hasCSN = caps && caps->hasFeature(DiscoInfo::ChatStatesFeature);
+ contactHas85Caps_ = hasCSN;
+ }
}
}
diff --git a/Swiften/Chat/ChatStateNotifier.h b/Swiften/Chat/ChatStateNotifier.h
index 5b99266..2b24c76 100644
--- a/Swiften/Chat/ChatStateNotifier.h
+++ b/Swiften/Chat/ChatStateNotifier.h
@@ -1,51 +1,58 @@
/*
- * Copyright (c) 2010 Kevin Smith
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010-2016 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
#pragma once
-#include <Swiften/Base/boost_bsignals.h>
-#include <boost/shared_ptr.hpp>
+#include <memory>
+
+#include <boost/signals2.hpp>
#include <Swiften/Base/API.h>
-#include <Swiften/Elements/Message.h>
#include <Swiften/Elements/ChatState.h>
+#include <Swiften/Elements/Message.h>
#include <Swiften/JID/JID.h>
namespace Swift {
- class StanzaChannel;
- class EntityCapsProvider;
-
- class SWIFTEN_API ChatStateNotifier {
- public:
- ChatStateNotifier(StanzaChannel* stanzaChannel, const JID& contact, EntityCapsProvider* entityCapsManager);
- ~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:
- 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_;
- };
+ class StanzaChannel;
+ class EntityCapsProvider;
+ class TimerFactory;
+ class Timer;
+
+
+ class SWIFTEN_API ChatStateNotifier {
+ public:
+ 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/ChatStateTracker.cpp b/Swiften/Chat/ChatStateTracker.cpp
index 27be86c..839f47d 100644
--- a/Swiften/Chat/ChatStateTracker.cpp
+++ b/Swiften/Chat/ChatStateTracker.cpp
@@ -1,37 +1,37 @@
/*
- * Copyright (c) 2010 Kevin Smith
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010-2016 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
#include <Swiften/Chat/ChatStateTracker.h>
namespace Swift {
ChatStateTracker::ChatStateTracker() {
- currentState_ = ChatState::Gone;
+ currentState_ = ChatState::Gone;
}
-void ChatStateTracker::handleMessageReceived(boost::shared_ptr<Message> message) {
- if (message->getType() == Message::Error) {
- return;
- }
- boost::shared_ptr<ChatState> statePayload = message->getPayload<ChatState>();
- if (statePayload) {
- changeState(statePayload->getChatState());;
- }
+void ChatStateTracker::handleMessageReceived(std::shared_ptr<Message> message) {
+ if (message->getType() == Message::Error) {
+ return;
+ }
+ std::shared_ptr<ChatState> statePayload = message->getPayload<ChatState>();
+ if (statePayload) {
+ changeState(statePayload->getChatState());
+ }
}
-void ChatStateTracker::handlePresenceChange(boost::shared_ptr<Presence> newPresence) {
- if (newPresence->getType() == Presence::Unavailable) {
- onChatStateChange(ChatState::Gone);
- }
+void ChatStateTracker::handlePresenceChange(std::shared_ptr<Presence> newPresence) {
+ if (newPresence->getType() == Presence::Unavailable) {
+ onChatStateChange(ChatState::Gone);
+ }
}
void ChatStateTracker::changeState(ChatState::ChatStateType state) {
- if (state != currentState_) {
- currentState_ = state;
- onChatStateChange(state);
- }
+ if (state != currentState_) {
+ currentState_ = state;
+ onChatStateChange(state);
+ }
}
}
diff --git a/Swiften/Chat/ChatStateTracker.h b/Swiften/Chat/ChatStateTracker.h
index e401b0a..c903e3a 100644
--- a/Swiften/Chat/ChatStateTracker.h
+++ b/Swiften/Chat/ChatStateTracker.h
@@ -1,28 +1,29 @@
/*
- * Copyright (c) 2010 Kevin Smith
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010-2016 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
#pragma once
-#include <Swiften/Base/boost_bsignals.h>
-#include <boost/shared_ptr.hpp>
-#include <Swiften/Base/API.h>
+#include <memory>
+
+#include <boost/signals2.hpp>
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/ChatState.h>
#include <Swiften/Elements/Message.h>
#include <Swiften/Elements/Presence.h>
-#include <Swiften/Elements/ChatState.h>
namespace Swift {
- class SWIFTEN_API ChatStateTracker {
- public:
- ChatStateTracker();
- void handleMessageReceived(boost::shared_ptr<Message> message);
- void handlePresenceChange(boost::shared_ptr<Presence> newPresence);
- boost::signal<void (ChatState::ChatStateType)> onChatStateChange;
- private:
- void changeState(ChatState::ChatStateType state);
- ChatState::ChatStateType currentState_;
- };
+ class SWIFTEN_API ChatStateTracker {
+ public:
+ ChatStateTracker();
+ void handleMessageReceived(std::shared_ptr<Message> message);
+ void handlePresenceChange(std::shared_ptr<Presence> newPresence);
+ boost::signals2::signal<void (ChatState::ChatStateType)> onChatStateChange;
+ private:
+ void changeState(ChatState::ChatStateType state);
+ ChatState::ChatStateType currentState_;
+ };
}
diff --git a/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp b/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp
index 1b91076..b6c909a 100644
--- a/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp
+++ b/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp
@@ -1,168 +1,186 @@
/*
- * Copyright (c) 2010 Kevin Smith
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010-2018 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
-#include <cppunit/extensions/HelperMacros.h>
-#include <cppunit/extensions/TestFactoryRegistry.h>
#include <boost/bind.hpp>
-#include <Swiften/Base/foreach.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>
+
+// Clang wrongly things that tests for 0 are using 0 as null.
+#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
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() {
- stanzaChannel = new DummyStanzaChannel();
- stanzaChannel->setAvailable(true);
- entityCapsProvider = new DummyEntityCapsProvider();
- notifier_ = new ChatStateNotifier(stanzaChannel, JID("foo@bar.com/baz"), entityCapsProvider);
- notifier_->setContactIsOnline(true);
- }
-
- void tearDown() {
- delete notifier_;
- 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();
- boost::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() {
- boost::shared_ptr<Message> message(new Message());
- notifier_->addChatStateRequest(message);
- CPPUNIT_ASSERT(!message->getPayload<ChatState>());
- }
-
- void testContactShouldReceiveStates_ActiveOverrideOn() {
- notifier_->receivedMessageFromContact(true);
- boost::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.
- */
- boost::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 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;
- foreach(boost::shared_ptr<Stanza> stanza, stanzaChannel->sentStanzas) {
- if (stanza->getPayload<ChatState>() && stanza->getPayload<ChatState>()->getChatState() == ChatState::Composing) {
- result++;
- }
- }
- return result;
- }
-
- int getActiveCount() const {
- int result = 0;
- foreach(boost::shared_ptr<Stanza> stanza, stanzaChannel->sentStanzas) {
- if (stanza->getPayload<ChatState>() && stanza->getPayload<ChatState>()->getChatState() == ChatState::Active) {
- result++;
- }
- }
- return result;
- }
-
- private:
- DummyStanzaChannel* stanzaChannel;
- DummyEntityCapsProvider* entityCapsProvider;
- ChatStateNotifier* notifier_;
+class ChatStateNotifierTest : public ::testing::Test {
+
+protected:
+ virtual void SetUp() {
+ stanzaChannel = new DummyStanzaChannel();
+ stanzaChannel->setAvailable(true);
+ entityCapsProvider = new DummyEntityCapsProvider();
+ timerFactory_ = new DummyTimerFactory();
+ notifier_ = new ChatStateNotifier(stanzaChannel, JID("foo@bar.com/baz"), entityCapsProvider, timerFactory_, 2);
+ notifier_->setContactIsOnline(true);
+ }
+
+ virtual void TearDown() {
+ delete notifier_;
+ delete timerFactory_;
+ delete entityCapsProvider;
+ delete stanzaChannel;
+ }
+
+ 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++;
+ }
+ }
+ return 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;
+ }
+
+ 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());
+}