diff options
author | Remko Tronçon <git@el-tramo.be> | 2010-03-28 15:46:49 (GMT) |
---|---|---|
committer | Remko Tronçon <git@el-tramo.be> | 2010-03-28 15:46:49 (GMT) |
commit | f53a1ef582494458301b97bf6e546be52d7ff7e8 (patch) | |
tree | 7571b5cbcbd8a8f1dd1c966c9045b6cb69f0e295 /Swiften/Queries | |
parent | 638345680d72ca6acaf123f2c8c1c391f696e371 (diff) | |
download | swift-f53a1ef582494458301b97bf6e546be52d7ff7e8.zip swift-f53a1ef582494458301b97bf6e546be52d7ff7e8.tar.bz2 |
Moving submodule contents back.
Diffstat (limited to 'Swiften/Queries')
29 files changed, 1294 insertions, 0 deletions
diff --git a/Swiften/Queries/DummyIQChannel.h b/Swiften/Queries/DummyIQChannel.h new file mode 100644 index 0000000..c0a4a25 --- /dev/null +++ b/Swiften/Queries/DummyIQChannel.h @@ -0,0 +1,29 @@ +#ifndef SWIFTEN_DummyIQChannel_H +#define SWIFTEN_DummyIQChannel_H + +#include <vector> + +#include "Swiften/Queries/IQChannel.h" + +namespace Swift { + class DummyIQChannel : public IQChannel { + public: + DummyIQChannel() {} + + virtual void sendIQ(boost::shared_ptr<IQ> iq) { + iqs_.push_back(iq); + } + + virtual String getNewIQID() { + return "test-id"; + } + + virtual bool isAvailable() { + return true; + } + + std::vector<boost::shared_ptr<IQ> > iqs_; + }; +} + +#endif diff --git a/Swiften/Queries/GenericRequest.h b/Swiften/Queries/GenericRequest.h new file mode 100644 index 0000000..77dae52 --- /dev/null +++ b/Swiften/Queries/GenericRequest.h @@ -0,0 +1,26 @@ +#pragma once + +#include <boost/signal.hpp> + +#include "Swiften/Queries/Request.h" + +namespace Swift { + template<typename PAYLOAD_TYPE> + class GenericRequest : public Request { + public: + GenericRequest( + IQ::Type type, + const JID& receiver, + boost::shared_ptr<Payload> payload, + IQRouter* router) : + Request(type, receiver, payload, router) { + } + + virtual void handleResponse(boost::shared_ptr<Payload> payload, boost::optional<ErrorPayload> error) { + onResponse(boost::dynamic_pointer_cast<PAYLOAD_TYPE>(payload), error); + } + + public: + boost::signal<void (boost::shared_ptr<PAYLOAD_TYPE>, const boost::optional<ErrorPayload>&)> onResponse; + }; +} diff --git a/Swiften/Queries/GetResponder.h b/Swiften/Queries/GetResponder.h new file mode 100644 index 0000000..2bd2fe2 --- /dev/null +++ b/Swiften/Queries/GetResponder.h @@ -0,0 +1,14 @@ +#pragma once + +#include "Swiften/Queries/Responder.h" + +namespace Swift { + template<typename T> + class GetResponder : public Responder<T> { + public: + GetResponder(IQRouter* router) : Responder<T>(router) {} + + private: + virtual bool handleSetRequest(const JID&, const String&, boost::shared_ptr<T>) { return false; } + }; +} diff --git a/Swiften/Queries/IQChannel.cpp b/Swiften/Queries/IQChannel.cpp new file mode 100644 index 0000000..539dea0 --- /dev/null +++ b/Swiften/Queries/IQChannel.cpp @@ -0,0 +1,8 @@ +#include "Swiften/Queries/IQChannel.h" + +namespace Swift { + +IQChannel::~IQChannel() { +} + +} diff --git a/Swiften/Queries/IQChannel.h b/Swiften/Queries/IQChannel.h new file mode 100644 index 0000000..1692afe --- /dev/null +++ b/Swiften/Queries/IQChannel.h @@ -0,0 +1,24 @@ +#ifndef SWIFTEN_IQChannel_H +#define SWIFTEN_IQChannel_H + +#include <boost/signal.hpp> +#include <boost/shared_ptr.hpp> + +#include "Swiften/Base/String.h" +#include "Swiften/Elements/IQ.h" + +namespace Swift { + class IQChannel { + public: + virtual ~IQChannel(); + + virtual void sendIQ(boost::shared_ptr<IQ>) = 0; + virtual String getNewIQID() = 0; + + virtual bool isAvailable() = 0; + + boost::signal<void (boost::shared_ptr<IQ>)> onIQReceived; + }; +} + +#endif diff --git a/Swiften/Queries/IQHandler.cpp b/Swiften/Queries/IQHandler.cpp new file mode 100644 index 0000000..81bd773 --- /dev/null +++ b/Swiften/Queries/IQHandler.cpp @@ -0,0 +1,9 @@ +#include "Swiften/Queries/IQHandler.h" +#include "Swiften/Queries/IQRouter.h" + +namespace Swift { + +IQHandler::~IQHandler() { +} + +} diff --git a/Swiften/Queries/IQHandler.h b/Swiften/Queries/IQHandler.h new file mode 100644 index 0000000..7389b3a --- /dev/null +++ b/Swiften/Queries/IQHandler.h @@ -0,0 +1,19 @@ +#ifndef SWIFTEN_IQHandler_H +#define SWIFTEN_IQHandler_H + +#include <boost/shared_ptr.hpp> + +#include "Swiften/Elements/IQ.h" + +namespace Swift { + class IQRouter; + + class IQHandler { + public: + virtual ~IQHandler(); + + virtual bool handleIQ(boost::shared_ptr<IQ>) = 0; + }; +} + +#endif diff --git a/Swiften/Queries/IQRouter.cpp b/Swiften/Queries/IQRouter.cpp new file mode 100644 index 0000000..fdfa00b --- /dev/null +++ b/Swiften/Queries/IQRouter.cpp @@ -0,0 +1,81 @@ +#include "Swiften/Queries/IQRouter.h" + +#include <algorithm> +#include <boost/bind.hpp> + +#include "Swiften/Base/foreach.h" +#include "Swiften/Queries/IQHandler.h" +#include "Swiften/Queries/IQChannel.h" +#include "Swiften/Elements/ErrorPayload.h" + +namespace Swift { + +static void noop(IQHandler*) {} + +IQRouter::IQRouter(IQChannel* channel) : channel_(channel), queueRemoves_(false) { + channel->onIQReceived.connect(boost::bind(&IQRouter::handleIQ, this, _1)); +} + +IQRouter::~IQRouter() { +} + +bool IQRouter::isAvailable() { + return channel_->isAvailable(); +} + +void IQRouter::handleIQ(boost::shared_ptr<IQ> iq) { + queueRemoves_ = true; + + bool handled = false; + foreach(boost::shared_ptr<IQHandler> handler, handlers_) { + handled |= handler->handleIQ(iq); + if (handled) { + break; + } + } + if (!handled && (iq->getType() == IQ::Get || iq->getType() == IQ::Set) ) { + channel_->sendIQ(IQ::createError(iq->getFrom(), iq->getID(), ErrorPayload::FeatureNotImplemented, ErrorPayload::Cancel)); + } + + processPendingRemoves(); + + queueRemoves_ = false; +} + +void IQRouter::processPendingRemoves() { + foreach(boost::shared_ptr<IQHandler> handler, queuedRemoves_) { + handlers_.erase(std::remove(handlers_.begin(), handlers_.end(), handler), handlers_.end()); + } + queuedRemoves_.clear(); +} + +void IQRouter::addHandler(IQHandler* handler) { + addHandler(boost::shared_ptr<IQHandler>(handler, noop)); +} + +void IQRouter::removeHandler(IQHandler* handler) { + removeHandler(boost::shared_ptr<IQHandler>(handler, noop)); +} + +void IQRouter::addHandler(boost::shared_ptr<IQHandler> handler) { + handlers_.push_back(handler); +} + +void IQRouter::removeHandler(boost::shared_ptr<IQHandler> handler) { + if (queueRemoves_) { + queuedRemoves_.push_back(handler); + } + else { + handlers_.erase(std::remove(handlers_.begin(), handlers_.end(), handler), handlers_.end()); + } +} + +void IQRouter::sendIQ(boost::shared_ptr<IQ> iq) { + channel_->sendIQ(iq); +} + +String IQRouter::getNewIQID() { + return channel_->getNewIQID(); +} + +} diff --git a/Swiften/Queries/IQRouter.h b/Swiften/Queries/IQRouter.h new file mode 100644 index 0000000..717a845 --- /dev/null +++ b/Swiften/Queries/IQRouter.h @@ -0,0 +1,41 @@ +#ifndef SWIFTEN_IQRouter_H +#define SWIFTEN_IQRouter_H + +#include <boost/shared_ptr.hpp> +#include <vector> + +#include "Swiften/Base/String.h" +#include "Swiften/Elements/IQ.h" + +namespace Swift { + class IQChannel; + class IQHandler; + + class IQRouter { + public: + IQRouter(IQChannel* channel); + ~IQRouter(); + + void addHandler(IQHandler* handler); + void removeHandler(IQHandler* handler); + void addHandler(boost::shared_ptr<IQHandler> handler); + void removeHandler(boost::shared_ptr<IQHandler> handler); + + void sendIQ(boost::shared_ptr<IQ> iq); + String getNewIQID(); + + bool isAvailable(); + + private: + void handleIQ(boost::shared_ptr<IQ> iq); + void processPendingRemoves(); + + private: + IQChannel* channel_; + std::vector< boost::shared_ptr<IQHandler> > handlers_; + std::vector< boost::shared_ptr<IQHandler> > queuedRemoves_; + bool queueRemoves_; + }; +} + +#endif diff --git a/Swiften/Queries/Request.cpp b/Swiften/Queries/Request.cpp new file mode 100644 index 0000000..ce9f763 --- /dev/null +++ b/Swiften/Queries/Request.cpp @@ -0,0 +1,55 @@ +#include "Swiften/Queries/Request.h" +#include "Swiften/Queries/IQRouter.h" +#include "Swiften/EventLoop/MainEventLoop.h" + +namespace Swift { + +Request::Request(IQ::Type type, const JID& receiver, boost::shared_ptr<Payload> payload, IQRouter* router) : router_(router), type_(type), receiver_(receiver), payload_(payload), sent_(false) { +} + +Request::Request(IQ::Type type, const JID& receiver, IQRouter* router) : router_(router), type_(type), receiver_(receiver), sent_(false) { +} + +void Request::send() { + assert(payload_); + assert(!sent_); + sent_ = true; + + boost::shared_ptr<IQ> iq(new IQ(type_)); + iq->setTo(receiver_); + iq->addPayload(payload_); + id_ = router_->getNewIQID(); + iq->setID(id_); + + try { + router_->addHandler(shared_from_this()); + } + catch (const std::exception&) { + router_->addHandler(this); + } + + router_->sendIQ(iq); +} + +bool Request::handleIQ(boost::shared_ptr<IQ> iq) { + bool handled = false; + if (sent_ && iq->getID() == id_) { + if (iq->getType() == IQ::Result) { + handleResponse(iq->getPayloadOfSameType(payload_), boost::optional<ErrorPayload>()); + } + else { + boost::shared_ptr<ErrorPayload> errorPayload = iq->getPayload<ErrorPayload>(); + if (errorPayload) { + handleResponse(boost::shared_ptr<Payload>(), boost::optional<ErrorPayload>(*errorPayload)); + } + else { + handleResponse(boost::shared_ptr<Payload>(), boost::optional<ErrorPayload>(ErrorPayload::UndefinedCondition)); + } + } + router_->removeHandler(this); + handled = true; + } + return handled; +} + +} diff --git a/Swiften/Queries/Request.h b/Swiften/Queries/Request.h new file mode 100644 index 0000000..cc4a58e --- /dev/null +++ b/Swiften/Queries/Request.h @@ -0,0 +1,50 @@ +#ifndef SWIFTEN_Request_H +#define SWIFTEN_Request_H + +#include <boost/shared_ptr.hpp> +#include <boost/optional.hpp> +#include <boost/enable_shared_from_this.hpp> + +#include "Swiften/Base/String.h" +#include "Swiften/Queries/IQHandler.h" +#include "Swiften/Elements/IQ.h" +#include "Swiften/Elements/Payload.h" +#include "Swiften/Elements/ErrorPayload.h" +#include "Swiften/JID/JID.h" + +namespace Swift { + class Request : public IQHandler, public boost::enable_shared_from_this<Request> { + public: + Request( + IQ::Type type, + const JID& receiver, + boost::shared_ptr<Payload> payload, + IQRouter* router); + Request( + IQ::Type type, + const JID& receiver, + IQRouter* router); + + void send(); + + protected: + virtual void setPayload(boost::shared_ptr<Payload> p) { + payload_ = p; + } + + virtual void handleResponse(boost::shared_ptr<Payload>, boost::optional<ErrorPayload>) = 0; + + private: + bool handleIQ(boost::shared_ptr<IQ>); + + private: + IQRouter* router_; + IQ::Type type_; + JID receiver_; + boost::shared_ptr<Payload> payload_; + String id_; + bool sent_; + }; +} + +#endif diff --git a/Swiften/Queries/Requests/GetDiscoInfoRequest.h b/Swiften/Queries/Requests/GetDiscoInfoRequest.h new file mode 100644 index 0000000..70f09ca --- /dev/null +++ b/Swiften/Queries/Requests/GetDiscoInfoRequest.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Swiften/Queries/GenericRequest.h" +#include "Swiften/Elements/DiscoInfo.h" + +namespace Swift { + class GetDiscoInfoRequest : public GenericRequest<DiscoInfo> { + public: + GetDiscoInfoRequest(const JID& jid, IQRouter* router) : + GenericRequest<DiscoInfo>(IQ::Get, jid, boost::shared_ptr<DiscoInfo>(new DiscoInfo()), router) { + } + }; +} diff --git a/Swiften/Queries/Requests/GetPrivateStorageRequest.h b/Swiften/Queries/Requests/GetPrivateStorageRequest.h new file mode 100644 index 0000000..5d6440e --- /dev/null +++ b/Swiften/Queries/Requests/GetPrivateStorageRequest.h @@ -0,0 +1,30 @@ +#pragma once + +#include <boost/signals.hpp> +#include <boost/shared_ptr.hpp> + +#include "Swiften/Queries/Request.h" +#include "Swiften/Elements/PrivateStorage.h" +#include "Swiften/Elements/ErrorPayload.h" + +namespace Swift { + template<typename PAYLOAD_TYPE> + class GetPrivateStorageRequest : public Request { + public: + GetPrivateStorageRequest(IQRouter* router) : Request(IQ::Get, JID(), boost::shared_ptr<PrivateStorage>(new PrivateStorage(boost::shared_ptr<Payload>(new PAYLOAD_TYPE()))), router) { + } + + virtual void handleResponse(boost::shared_ptr<Payload> payload, boost::optional<ErrorPayload> error) { + boost::shared_ptr<PrivateStorage> storage = boost::dynamic_pointer_cast<PrivateStorage>(payload); + if (storage) { + onResponse(boost::dynamic_pointer_cast<PAYLOAD_TYPE>(storage->getPayload()), error); + } + else { + onResponse(boost::shared_ptr<PAYLOAD_TYPE>(), error); + } + } + + public: + boost::signal<void (boost::shared_ptr<PAYLOAD_TYPE>, const boost::optional<ErrorPayload>&)> onResponse; + }; +} diff --git a/Swiften/Queries/Requests/GetRosterRequest.h b/Swiften/Queries/Requests/GetRosterRequest.h new file mode 100644 index 0000000..cac1c12 --- /dev/null +++ b/Swiften/Queries/Requests/GetRosterRequest.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Swiften/Queries/GenericRequest.h" +#include "Swiften/Elements/RosterPayload.h" + +namespace Swift { + class GetRosterRequest : public GenericRequest<RosterPayload> { + public: + GetRosterRequest(IQRouter* router) : + GenericRequest<RosterPayload>(IQ::Get, JID(), boost::shared_ptr<Payload>(new RosterPayload()), router) { + } + }; +} diff --git a/Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h b/Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h new file mode 100644 index 0000000..87b51ce --- /dev/null +++ b/Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Swiften/Queries/GenericRequest.h" +#include "Swiften/Elements/SecurityLabelsCatalog.h" + +namespace Swift { + class GetSecurityLabelsCatalogRequest : public GenericRequest<SecurityLabelsCatalog> { + public: + GetSecurityLabelsCatalogRequest( + const JID& recipient, + IQRouter* router) : + GenericRequest<SecurityLabelsCatalog>( + IQ::Get, JID(), boost::shared_ptr<SecurityLabelsCatalog>(new SecurityLabelsCatalog(recipient)), router) { + } + }; +} diff --git a/Swiften/Queries/Requests/GetVCardRequest.h b/Swiften/Queries/Requests/GetVCardRequest.h new file mode 100644 index 0000000..8fc6e17 --- /dev/null +++ b/Swiften/Queries/Requests/GetVCardRequest.h @@ -0,0 +1,12 @@ +#pragma once + +#include "Swiften/Queries/GenericRequest.h" +#include "Swiften/Elements/VCard.h" + +namespace Swift { + class GetVCardRequest : public GenericRequest<VCard> { + public: + GetVCardRequest(const JID& jid, IQRouter* router) : GenericRequest<VCard>(IQ::Get, jid, boost::shared_ptr<Payload>(new VCard()), router) { + } + }; +} diff --git a/Swiften/Queries/Requests/SetPrivateStorageRequest.h b/Swiften/Queries/Requests/SetPrivateStorageRequest.h new file mode 100644 index 0000000..834ddd8 --- /dev/null +++ b/Swiften/Queries/Requests/SetPrivateStorageRequest.h @@ -0,0 +1,24 @@ +#pragma once + +#include <boost/signals.hpp> +#include <boost/shared_ptr.hpp> + +#include "Swiften/Queries/Request.h" +#include "Swiften/Elements/PrivateStorage.h" +#include "Swiften/Elements/ErrorPayload.h" + +namespace Swift { + template<typename PAYLOAD_TYPE> + class SetPrivateStorageRequest : public Request { + public: + SetPrivateStorageRequest(boost::shared_ptr<PAYLOAD_TYPE> payload, IQRouter* router) : Request(IQ::Set, JID(), boost::shared_ptr<PrivateStorage>(new PrivateStorage(payload)), router) { + } + + virtual void handleResponse(boost::shared_ptr<Payload> payload, boost::optional<ErrorPayload> error) { + onResponse(error); + } + + public: + boost::signal<void (const boost::optional<ErrorPayload>&)> onResponse; + }; +} diff --git a/Swiften/Queries/Requests/UnitTest/GetPrivateStorageRequestTest.cpp b/Swiften/Queries/Requests/UnitTest/GetPrivateStorageRequestTest.cpp new file mode 100644 index 0000000..a86a111 --- /dev/null +++ b/Swiften/Queries/Requests/UnitTest/GetPrivateStorageRequestTest.cpp @@ -0,0 +1,106 @@ +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> +#include <boost/shared_ptr.hpp> +#include <boost/bind.hpp> + +#include "Swiften/Queries/Requests/GetPrivateStorageRequest.h" +#include "Swiften/Queries/IQRouter.h" +#include "Swiften/Queries/DummyIQChannel.h" +#include "Swiften/Elements/Payload.h" + +using namespace Swift; + +class GetPrivateStorageRequestTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(GetPrivateStorageRequestTest); + CPPUNIT_TEST(testSend); + CPPUNIT_TEST(testHandleResponse); + CPPUNIT_TEST(testHandleResponse_Error); + CPPUNIT_TEST_SUITE_END(); + + public: + class MyPayload : public Payload { + public: + MyPayload(const String& text = "") : text(text) {} + String text; + }; + + public: + GetPrivateStorageRequestTest() {} + + void setUp() { + channel = new DummyIQChannel(); + router = new IQRouter(channel); + } + + void tearDown() { + delete router; + delete channel; + } + + void testSend() { + GetPrivateStorageRequest<MyPayload> request(router); + request.send(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel->iqs_.size())); + CPPUNIT_ASSERT_EQUAL(JID(), channel->iqs_[0]->getTo()); + CPPUNIT_ASSERT_EQUAL(IQ::Get, channel->iqs_[0]->getType()); + boost::shared_ptr<PrivateStorage> storage = channel->iqs_[0]->getPayload<PrivateStorage>(); + CPPUNIT_ASSERT(storage); + boost::shared_ptr<MyPayload> payload = boost::dynamic_pointer_cast<MyPayload>(storage->getPayload()); + CPPUNIT_ASSERT(payload); + } + + void testHandleResponse() { + GetPrivateStorageRequest<MyPayload> testling(router); + testling.onResponse.connect(boost::bind(&GetPrivateStorageRequestTest::handleResponse, this, _1, _2)); + testling.send(); + channel->onIQReceived(createResponse("test-id", "foo")); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(responses.size())); + CPPUNIT_ASSERT_EQUAL(String("foo"), boost::dynamic_pointer_cast<MyPayload>(responses[0])->text); + } + + void testHandleResponse_Error() { + GetPrivateStorageRequest<MyPayload> testling(router); + testling.onResponse.connect(boost::bind(&GetPrivateStorageRequestTest::handleResponse, this, _1, _2)); + testling.send(); + channel->onIQReceived(createError("test-id")); + + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(responses.size())); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(errors.size())); + } + + private: + void handleResponse(boost::shared_ptr<Payload> p, const boost::optional<ErrorPayload>& e) { + if (e) { + errors.push_back(*e); + } + else { + responses.push_back(p); + } + } + + boost::shared_ptr<IQ> createResponse(const String& id, const String& text) { + boost::shared_ptr<IQ> iq(new IQ(IQ::Result)); + boost::shared_ptr<PrivateStorage> storage(new PrivateStorage()); + storage->setPayload(boost::shared_ptr<Payload>(new MyPayload(text))); + iq->addPayload(storage); + iq->setID(id); + return iq; + } + + boost::shared_ptr<IQ> createError(const String& id) { + boost::shared_ptr<IQ> iq(new IQ(IQ::Error)); + iq->setID(id); + return iq; + } + + private: + IQRouter* router; + DummyIQChannel* channel; + std::vector< ErrorPayload > errors; + std::vector< boost::shared_ptr<Payload> > responses; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(GetPrivateStorageRequestTest); diff --git a/Swiften/Queries/Responder.h b/Swiften/Queries/Responder.h new file mode 100644 index 0000000..9c025eb --- /dev/null +++ b/Swiften/Queries/Responder.h @@ -0,0 +1,58 @@ +#ifndef SWIFTEN_Responder_H +#define SWIFTEN_Responder_H + +#include "Swiften/Queries/IQHandler.h" +#include "Swiften/Queries/IQRouter.h" +#include "Swiften/Elements/ErrorPayload.h" + +namespace Swift { + template<typename PAYLOAD_TYPE> + class Responder : public IQHandler { + public: + Responder(IQRouter* router) : router_(router) { + router_->addHandler(this); + } + + ~Responder() { + router_->removeHandler(this); + } + + protected: + virtual bool handleGetRequest(const JID& from, const String& id, boost::shared_ptr<PAYLOAD_TYPE> payload) = 0; + virtual bool handleSetRequest(const JID& from, const String& id, boost::shared_ptr<PAYLOAD_TYPE> payload) = 0; + + void sendResponse(const JID& to, const String& id, boost::shared_ptr<Payload> payload) { + router_->sendIQ(IQ::createResult(to, id, payload)); + } + + void sendError(const JID& to, const String& id, ErrorPayload::Condition condition, ErrorPayload::Type type) { + router_->sendIQ(IQ::createError(to, id, condition, type)); + } + + private: + virtual bool handleIQ(boost::shared_ptr<IQ> iq) { + if (iq->getType() == IQ::Set || iq->getType() == IQ::Get) { + boost::shared_ptr<PAYLOAD_TYPE> payload(iq->getPayload<PAYLOAD_TYPE>()); + if (payload) { + bool result; + if (iq->getType() == IQ::Set) { + result = handleSetRequest(iq->getFrom(), iq->getID(), payload); + } + else { + result = handleGetRequest(iq->getFrom(), iq->getID(), payload); + } + if (!result) { + router_->sendIQ(IQ::createError(iq->getFrom(), iq->getID(), ErrorPayload::NotAllowed, ErrorPayload::Cancel)); + } + return true; + } + } + return false; + } + + private: + IQRouter* router_; + }; +} + +#endif diff --git a/Swiften/Queries/Responders/DiscoInfoResponder.cpp b/Swiften/Queries/Responders/DiscoInfoResponder.cpp new file mode 100644 index 0000000..572f83f --- /dev/null +++ b/Swiften/Queries/Responders/DiscoInfoResponder.cpp @@ -0,0 +1,36 @@ +#include "Swiften/Queries/Responders/DiscoInfoResponder.h" +#include "Swiften/Queries/IQRouter.h" +#include "Swiften/Elements/DiscoInfo.h" + +namespace Swift { + +DiscoInfoResponder::DiscoInfoResponder(IQRouter* router) : GetResponder<DiscoInfo>(router) { +} + +void DiscoInfoResponder::setDiscoInfo(const DiscoInfo& info) { + info_ = info; +} + +void DiscoInfoResponder::setDiscoInfo(const String& node, const DiscoInfo& info) { + DiscoInfo newInfo(info); + newInfo.setNode(node); + nodeInfo_[node] = newInfo; +} + +bool DiscoInfoResponder::handleGetRequest(const JID& from, const String& id, boost::shared_ptr<DiscoInfo> info) { + if (info->getNode().isEmpty()) { + sendResponse(from, id, boost::shared_ptr<DiscoInfo>(new DiscoInfo(info_))); + } + else { + std::map<String,DiscoInfo>::const_iterator i = nodeInfo_.find(info->getNode()); + if (i != nodeInfo_.end()) { + sendResponse(from, id, boost::shared_ptr<DiscoInfo>(new DiscoInfo((*i).second))); + } + else { + sendError(from, id, ErrorPayload::ItemNotFound, ErrorPayload::Cancel); + } + } + return true; +} + +} diff --git a/Swiften/Queries/Responders/DiscoInfoResponder.h b/Swiften/Queries/Responders/DiscoInfoResponder.h new file mode 100644 index 0000000..3270d5d --- /dev/null +++ b/Swiften/Queries/Responders/DiscoInfoResponder.h @@ -0,0 +1,28 @@ +#ifndef SWIFTEN_DiscoInfoResponder_H +#define SWIFTEN_DiscoInfoResponder_H + +#include <map> + +#include "Swiften/Queries/GetResponder.h" +#include "Swiften/Elements/DiscoInfo.h" + +namespace Swift { + class IQRouter; + + class DiscoInfoResponder : public GetResponder<DiscoInfo> { + public: + DiscoInfoResponder(IQRouter* router); + + void setDiscoInfo(const DiscoInfo& info); + void setDiscoInfo(const String& node, const DiscoInfo& info); + + private: + virtual bool handleGetRequest(const JID& from, const String& id, boost::shared_ptr<DiscoInfo> payload); + + private: + DiscoInfo info_; + std::map<String, DiscoInfo> nodeInfo_; + }; +} + +#endif diff --git a/Swiften/Queries/Responders/RosterPushResponder.h b/Swiften/Queries/Responders/RosterPushResponder.h new file mode 100644 index 0000000..69185c8 --- /dev/null +++ b/Swiften/Queries/Responders/RosterPushResponder.h @@ -0,0 +1,23 @@ +#pragma once + +#include <boost/signal.hpp> + +#include "Swiften/Queries/SetResponder.h" +#include "Swiften/Elements/RosterPayload.h" + +namespace Swift { + class RosterPushResponder : public SetResponder<RosterPayload> { + public: + RosterPushResponder(IQRouter* router) : SetResponder<RosterPayload>(router) {} + + public: + boost::signal<void (boost::shared_ptr<RosterPayload>)> onRosterReceived; + + private: + virtual bool handleSetRequest(const JID& from, const String& id, boost::shared_ptr<RosterPayload> payload) { + onRosterReceived(payload); + sendResponse(from, id, boost::shared_ptr<Payload>()); + return true; + } + }; +} diff --git a/Swiften/Queries/Responders/SoftwareVersionResponder.cpp b/Swiften/Queries/Responders/SoftwareVersionResponder.cpp new file mode 100644 index 0000000..e608f24 --- /dev/null +++ b/Swiften/Queries/Responders/SoftwareVersionResponder.cpp @@ -0,0 +1,16 @@ +#include "Swiften/Queries/Responders/SoftwareVersionResponder.h" +#include "Swiften/Queries/IQRouter.h" + +namespace Swift { + +SoftwareVersionResponder::SoftwareVersionResponder( + const String& client, const String& version, IQRouter* router) : + GetResponder<SoftwareVersion>(router), client_(client), version_(version) { +} + +bool SoftwareVersionResponder::handleGetRequest(const JID& from, const String& id, boost::shared_ptr<SoftwareVersion>) { + sendResponse(from, id, boost::shared_ptr<SoftwareVersion>(new SoftwareVersion(client_, version_))); + return true; +} + +} diff --git a/Swiften/Queries/Responders/SoftwareVersionResponder.h b/Swiften/Queries/Responders/SoftwareVersionResponder.h new file mode 100644 index 0000000..85d1089 --- /dev/null +++ b/Swiften/Queries/Responders/SoftwareVersionResponder.h @@ -0,0 +1,23 @@ +#ifndef SWIFTEN_SoftwareVersionResponder_H +#define SWIFTEN_SoftwareVersionResponder_H + +#include "Swiften/Queries/GetResponder.h" +#include "Swiften/Elements/SoftwareVersion.h" + +namespace Swift { + class IQRouter; + + class SoftwareVersionResponder : public GetResponder<SoftwareVersion> { + public: + SoftwareVersionResponder(const String& client, const String& version, IQRouter* router); + + private: + virtual bool handleGetRequest(const JID& from, const String& id, boost::shared_ptr<SoftwareVersion> payload); + + private: + String client_; + String version_; + }; +} + +#endif diff --git a/Swiften/Queries/Responders/UnitTest/DiscoInfoResponderTest.cpp b/Swiften/Queries/Responders/UnitTest/DiscoInfoResponderTest.cpp new file mode 100644 index 0000000..5993d0c --- /dev/null +++ b/Swiften/Queries/Responders/UnitTest/DiscoInfoResponderTest.cpp @@ -0,0 +1,84 @@ +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> +#include <typeinfo> + +#include "Swiften/Queries/Responders/DiscoInfoResponder.h" +#include "Swiften/Queries/IQRouter.h" +#include "Swiften/Queries/DummyIQChannel.h" + +using namespace Swift; + +class DiscoInfoResponderTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(DiscoInfoResponderTest); + CPPUNIT_TEST(testHandleRequest_GetToplevelInfo); + CPPUNIT_TEST(testHandleRequest_GetNodeInfo); + CPPUNIT_TEST(testHandleRequest_GetInvalidNodeInfo); + CPPUNIT_TEST_SUITE_END(); + + public: + DiscoInfoResponderTest() {} + + void setUp() { + channel_ = new DummyIQChannel(); + router_ = new IQRouter(channel_); + } + + void tearDown() { + delete router_; + delete channel_; + } + + void testHandleRequest_GetToplevelInfo() { + DiscoInfoResponder testling(router_); + DiscoInfo discoInfo; + discoInfo.addFeature("foo"); + testling.setDiscoInfo(discoInfo); + + boost::shared_ptr<DiscoInfo> query(new DiscoInfo()); + channel_->onIQReceived(IQ::createRequest(IQ::Get, JID("foo@bar.com"), "id-1", query)); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size())); + boost::shared_ptr<DiscoInfo> payload(channel_->iqs_[0]->getPayload<DiscoInfo>()); + CPPUNIT_ASSERT(payload); + CPPUNIT_ASSERT_EQUAL(String(""), payload->getNode()); + CPPUNIT_ASSERT(payload->hasFeature("foo")); + } + + void testHandleRequest_GetNodeInfo() { + DiscoInfoResponder testling(router_); + DiscoInfo discoInfo; + discoInfo.addFeature("foo"); + testling.setDiscoInfo(discoInfo); + DiscoInfo discoInfoBar; + discoInfoBar.addFeature("bar"); + testling.setDiscoInfo("bar-node", discoInfoBar); + + boost::shared_ptr<DiscoInfo> query(new DiscoInfo()); + query->setNode("bar-node"); + channel_->onIQReceived(IQ::createRequest(IQ::Get, JID("foo@bar.com"), "id-1", query)); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size())); + boost::shared_ptr<DiscoInfo> payload(channel_->iqs_[0]->getPayload<DiscoInfo>()); + CPPUNIT_ASSERT(payload); + CPPUNIT_ASSERT_EQUAL(String("bar-node"), payload->getNode()); + CPPUNIT_ASSERT(payload->hasFeature("bar")); + } + + void testHandleRequest_GetInvalidNodeInfo() { + DiscoInfoResponder testling(router_); + + boost::shared_ptr<DiscoInfo> query(new DiscoInfo()); + query->setNode("bar-node"); + channel_->onIQReceived(IQ::createRequest(IQ::Get, JID("foo@bar.com"), "id-1", query)); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size())); + boost::shared_ptr<ErrorPayload> payload(channel_->iqs_[0]->getPayload<ErrorPayload>()); + CPPUNIT_ASSERT(payload); + } + + private: + IQRouter* router_; + DummyIQChannel* channel_; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(DiscoInfoResponderTest); diff --git a/Swiften/Queries/SetResponder.h b/Swiften/Queries/SetResponder.h new file mode 100644 index 0000000..51fe39a --- /dev/null +++ b/Swiften/Queries/SetResponder.h @@ -0,0 +1,14 @@ +#pragma once + +#include "Swiften/Queries/Responder.h" + +namespace Swift { + template<typename T> + class SetResponder : public Responder<T> { + public: + SetResponder(IQRouter* router) : Responder<T>(router) {} + + private: + virtual bool handleGetRequest(const JID&, const String&, boost::shared_ptr<T>) { return false; } + }; +} diff --git a/Swiften/Queries/UnitTest/IQRouterTest.cpp b/Swiften/Queries/UnitTest/IQRouterTest.cpp new file mode 100644 index 0000000..5760b09 --- /dev/null +++ b/Swiften/Queries/UnitTest/IQRouterTest.cpp @@ -0,0 +1,143 @@ +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> +#include <boost/shared_ptr.hpp> +#include <boost/bind.hpp> + +#include "Swiften/Queries/IQHandler.h" +#include "Swiften/Queries/IQRouter.h" +#include "Swiften/Queries/DummyIQChannel.h" + +using namespace Swift; + +class IQRouterTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(IQRouterTest); + CPPUNIT_TEST(testRemoveHandler); + CPPUNIT_TEST(testRemoveHandler_AfterHandleIQ); + CPPUNIT_TEST(testHandleIQ_SuccesfulHandlerFirst); + CPPUNIT_TEST(testHandleIQ_SuccesfulHandlerLast); + CPPUNIT_TEST(testHandleIQ_NoSuccesfulHandler); + CPPUNIT_TEST(testHandleIQ_HandlerRemovedDuringHandle); + CPPUNIT_TEST_SUITE_END(); + + public: + IQRouterTest() {} + + void setUp() { + channel_ = new DummyIQChannel(); + } + + void tearDown() { + delete channel_; + } + + void testRemoveHandler() { + IQRouter testling(channel_); + DummyIQHandler handler1(true, &testling); + DummyIQHandler handler2(true, &testling); + testling.removeHandler(&handler1); + + channel_->onIQReceived(boost::shared_ptr<IQ>(new IQ())); + + CPPUNIT_ASSERT_EQUAL(0, handler1.called); + CPPUNIT_ASSERT_EQUAL(1, handler2.called); + } + + void testRemoveHandler_AfterHandleIQ() { + IQRouter testling(channel_); + DummyIQHandler handler1(true, &testling); + DummyIQHandler handler2(true, &testling); + + channel_->onIQReceived(boost::shared_ptr<IQ>(new IQ())); + testling.removeHandler(&handler1); + channel_->onIQReceived(boost::shared_ptr<IQ>(new IQ())); + + CPPUNIT_ASSERT_EQUAL(1, handler1.called); + CPPUNIT_ASSERT_EQUAL(1, handler2.called); + } + + void testHandleIQ_SuccesfulHandlerFirst() { + IQRouter testling(channel_); + DummyIQHandler handler1(true, &testling); + DummyIQHandler handler2(false, &testling); + + channel_->onIQReceived(boost::shared_ptr<IQ>(new IQ())); + + CPPUNIT_ASSERT_EQUAL(1, handler1.called); + CPPUNIT_ASSERT_EQUAL(0, handler2.called); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(channel_->iqs_.size())); + } + + void testHandleIQ_SuccesfulHandlerLast() { + IQRouter testling(channel_); + DummyIQHandler handler1(false, &testling); + DummyIQHandler handler2(true, &testling); + + channel_->onIQReceived(boost::shared_ptr<IQ>(new IQ())); + + CPPUNIT_ASSERT_EQUAL(1, handler1.called); + CPPUNIT_ASSERT_EQUAL(1, handler2.called); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(channel_->iqs_.size())); + } + + void testHandleIQ_NoSuccesfulHandler() { + IQRouter testling(channel_); + DummyIQHandler handler(false, &testling); + + channel_->onIQReceived(boost::shared_ptr<IQ>(new IQ())); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size())); + CPPUNIT_ASSERT(channel_->iqs_[0]->getPayload<ErrorPayload>()); + } + + + void testHandleIQ_HandlerRemovedDuringHandle() { + IQRouter testling(channel_); + RemovingIQHandler handler1(&testling); + DummyIQHandler handler2(true, &testling); + + channel_->onIQReceived(boost::shared_ptr<IQ>(new IQ())); + channel_->onIQReceived(boost::shared_ptr<IQ>(new IQ())); + + CPPUNIT_ASSERT_EQUAL(1, handler1.called); + CPPUNIT_ASSERT_EQUAL(2, handler2.called); + } + + private: + struct DummyIQHandler : public IQHandler { + DummyIQHandler(bool handle, IQRouter* router) : handle(handle), router(router), called(0) { + router->addHandler(this); + } + + ~DummyIQHandler() { + router->removeHandler(this); + } + + virtual bool handleIQ(boost::shared_ptr<IQ>) { + called++; + return handle; + } + bool handle; + IQRouter* router; + int called; + }; + + struct RemovingIQHandler : public IQHandler { + RemovingIQHandler(IQRouter* router) : router(router), called(0) { + router->addHandler(this); + } + + virtual bool handleIQ(boost::shared_ptr<IQ>) { + called++; + router->removeHandler(this); + return false; + } + IQRouter* router; + int called; + }; + + + DummyIQChannel* channel_; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(IQRouterTest); diff --git a/Swiften/Queries/UnitTest/RequestTest.cpp b/Swiften/Queries/UnitTest/RequestTest.cpp new file mode 100644 index 0000000..c569bb5 --- /dev/null +++ b/Swiften/Queries/UnitTest/RequestTest.cpp @@ -0,0 +1,167 @@ +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> +#include <boost/shared_ptr.hpp> +#include <boost/bind.hpp> + +#include "Swiften/Queries/GenericRequest.h" +#include "Swiften/Queries/IQRouter.h" +#include "Swiften/Queries/DummyIQChannel.h" +#include "Swiften/Elements/Payload.h" + +using namespace Swift; + +class RequestTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(RequestTest); + CPPUNIT_TEST(testSendGet); + CPPUNIT_TEST(testSendSet); + CPPUNIT_TEST(testHandleIQ); + CPPUNIT_TEST(testHandleIQ_InvalidID); + CPPUNIT_TEST(testHandleIQ_Error); + CPPUNIT_TEST(testHandleIQ_ErrorWithoutPayload); + CPPUNIT_TEST(testHandleIQ_BeforeSend); + CPPUNIT_TEST_SUITE_END(); + + public: + class MyPayload : public Payload { + public: + MyPayload(const String& s = "") : text_(s) {} + String text_; + }; + + typedef GenericRequest<MyPayload> MyRequest; + + public: + RequestTest() {} + + void setUp() { + channel_ = new DummyIQChannel(); + router_ = new IQRouter(channel_); + payload_ = boost::shared_ptr<Payload>(new MyPayload("foo")); + responsePayload_ = boost::shared_ptr<Payload>(new MyPayload("bar")); + responsesReceived_ = 0; + } + + void tearDown() { + delete router_; + delete channel_; + } + + void testSendSet() { + MyRequest testling(IQ::Set, JID("foo@bar.com/baz"), payload_, router_); + testling.send(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size())); + CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com/baz"), channel_->iqs_[0]->getTo()); + CPPUNIT_ASSERT_EQUAL(IQ::Set, channel_->iqs_[0]->getType()); + CPPUNIT_ASSERT_EQUAL(String("test-id"), channel_->iqs_[0]->getID()); + } + + void testSendGet() { + MyRequest testling(IQ::Get, JID("foo@bar.com/baz"), payload_, router_); + testling.send(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size())); + CPPUNIT_ASSERT_EQUAL(IQ::Get, channel_->iqs_[0]->getType()); + } + + void testHandleIQ() { + MyRequest testling(IQ::Get, JID("foo@bar.com/baz"), payload_, router_); + testling.onResponse.connect(boost::bind(&RequestTest::handleResponse, this, _1, _2)); + testling.send(); + + channel_->onIQReceived(createResponse("test-id")); + + CPPUNIT_ASSERT_EQUAL(1, responsesReceived_); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(receivedErrors.size())); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size())); + } + + // FIXME: Doesn't test that it didn't handle the payload + void testHandleIQ_InvalidID() { + MyRequest testling(IQ::Get, JID("foo@bar.com/baz"), payload_, router_); + testling.onResponse.connect(boost::bind(&RequestTest::handleResponse, this, _1, _2)); + testling.send(); + + channel_->onIQReceived(createResponse("different-id")); + + CPPUNIT_ASSERT_EQUAL(0, responsesReceived_); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(receivedErrors.size())); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size())); + } + + void testHandleIQ_Error() { + MyRequest testling(IQ::Get, JID("foo@bar.com/baz"), payload_, router_); + testling.onResponse.connect(boost::bind(&RequestTest::handleResponse, this, _1, _2)); + testling.send(); + + boost::shared_ptr<IQ> error = createError("test-id"); + boost::shared_ptr<Payload> errorPayload = boost::shared_ptr<ErrorPayload>(new ErrorPayload(ErrorPayload::FeatureNotImplemented)); + error->addPayload(errorPayload); + channel_->onIQReceived(error); + + CPPUNIT_ASSERT_EQUAL(0, responsesReceived_); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(receivedErrors.size())); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size())); + CPPUNIT_ASSERT_EQUAL(ErrorPayload::FeatureNotImplemented, receivedErrors[0].getCondition()); + } + + void testHandleIQ_ErrorWithoutPayload() { + MyRequest testling(IQ::Get, JID("foo@bar.com/baz"), payload_, router_); + testling.onResponse.connect(boost::bind(&RequestTest::handleResponse, this, _1, _2)); + testling.send(); + + channel_->onIQReceived(createError("test-id")); + + CPPUNIT_ASSERT_EQUAL(0, responsesReceived_); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(receivedErrors.size())); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size())); + CPPUNIT_ASSERT_EQUAL(ErrorPayload::UndefinedCondition, receivedErrors[0].getCondition()); + } + + void testHandleIQ_BeforeSend() { + MyRequest testling(IQ::Get, JID("foo@bar.com/baz"), payload_, router_); + testling.onResponse.connect(boost::bind(&RequestTest::handleResponse, this, _1, _2)); + channel_->onIQReceived(createResponse("test-id")); + + CPPUNIT_ASSERT_EQUAL(0, responsesReceived_); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(receivedErrors.size())); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(channel_->iqs_.size())); + } + + private: + void handleResponse(boost::shared_ptr<Payload> p, const boost::optional<ErrorPayload>& e) { + if (e) { + receivedErrors.push_back(*e); + } + else { + boost::shared_ptr<MyPayload> payload(boost::dynamic_pointer_cast<MyPayload>(p)); + CPPUNIT_ASSERT(payload); + CPPUNIT_ASSERT_EQUAL(String("bar"), payload->text_); + ++responsesReceived_; + } + } + + boost::shared_ptr<IQ> createResponse(const String& id) { + boost::shared_ptr<IQ> iq(new IQ(IQ::Result)); + iq->addPayload(responsePayload_); + iq->setID(id); + return iq; + } + + boost::shared_ptr<IQ> createError(const String& id) { + boost::shared_ptr<IQ> iq(new IQ(IQ::Error)); + iq->setID(id); + return iq; + } + + private: + IQRouter* router_; + DummyIQChannel* channel_; + boost::shared_ptr<Payload> payload_; + boost::shared_ptr<Payload> responsePayload_; + int responsesReceived_; + std::vector<ErrorPayload> receivedErrors; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(RequestTest); diff --git a/Swiften/Queries/UnitTest/ResponderTest.cpp b/Swiften/Queries/UnitTest/ResponderTest.cpp new file mode 100644 index 0000000..5c758e4 --- /dev/null +++ b/Swiften/Queries/UnitTest/ResponderTest.cpp @@ -0,0 +1,132 @@ +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> +#include <boost/shared_ptr.hpp> +#include <boost/bind.hpp> + +#include "Swiften/Queries/Responder.h" +#include "Swiften/Queries/IQRouter.h" +#include "Swiften/Queries/DummyIQChannel.h" +#include "Swiften/Elements/SoftwareVersion.h" + +using namespace Swift; + +class ResponderTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(ResponderTest); + CPPUNIT_TEST(testConstructor); + CPPUNIT_TEST(testHandleIQ_Set); + CPPUNIT_TEST(testHandleIQ_Get); + CPPUNIT_TEST(testHandleIQ_Error); + CPPUNIT_TEST(testHandleIQ_Result); + CPPUNIT_TEST(testHandleIQ_NoPayload); + CPPUNIT_TEST_SUITE_END(); + + public: + ResponderTest() {} + + void setUp() { + channel_ = new DummyIQChannel(); + router_ = new IQRouter(channel_); + payload_ = boost::shared_ptr<SoftwareVersion>(new SoftwareVersion("foo")); + } + + void tearDown() { + delete router_; + delete channel_; + } + + void testConstructor() { + MyResponder testling(router_); + + channel_->onIQReceived(createRequest(IQ::Set)); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(testling.setPayloads_.size())); + } + + void testHandleIQ_Set() { + MyResponder testling(router_); + + CPPUNIT_ASSERT(dynamic_cast<IQHandler*>(&testling)->handleIQ(createRequest(IQ::Set))); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(testling.setPayloads_.size())); + CPPUNIT_ASSERT(payload_ == testling.setPayloads_[0]); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(testling.getPayloads_.size())); + } + + void testHandleIQ_Get() { + MyResponder testling(router_); + + CPPUNIT_ASSERT(dynamic_cast<IQHandler*>(&testling)->handleIQ(createRequest(IQ::Get))); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(testling.getPayloads_.size())); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(testling.setPayloads_.size())); + CPPUNIT_ASSERT(payload_ == testling.getPayloads_[0]); + } + + void testHandleIQ_Error() { + MyResponder testling(router_); + + CPPUNIT_ASSERT(!dynamic_cast<IQHandler*>(&testling)->handleIQ(createRequest(IQ::Error))); + + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(testling.getPayloads_.size())); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(testling.setPayloads_.size())); + } + + void testHandleIQ_Result() { + MyResponder testling(router_); + + CPPUNIT_ASSERT(!dynamic_cast<IQHandler*>(&testling)->handleIQ(createRequest(IQ::Result))); + + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(testling.getPayloads_.size())); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(testling.setPayloads_.size())); + } + + void testHandleIQ_NoPayload() { + MyResponder testling(router_); + + CPPUNIT_ASSERT(!dynamic_cast<IQHandler*>(&testling)->handleIQ(boost::shared_ptr<IQ>(new IQ(IQ::Get)))); + + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(testling.getPayloads_.size())); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(testling.setPayloads_.size())); + } + + private: + boost::shared_ptr<IQ> createRequest(IQ::Type type) { + boost::shared_ptr<IQ> iq(new IQ(type)); + iq->addPayload(payload_); + iq->setID("myid"); + iq->setFrom(JID("foo@bar.com/baz")); + return iq; + } + + private: + class MyResponder : public Responder<SoftwareVersion> { + public: + MyResponder(IQRouter* router) : Responder<SoftwareVersion>(router), getRequestResponse_(true), setRequestResponse_(true) {} + + virtual bool handleGetRequest(const JID& from, const String& id, boost::shared_ptr<SoftwareVersion> payload) { + CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com/baz"), from); + CPPUNIT_ASSERT_EQUAL(String("myid"), id); + getPayloads_.push_back(payload); + return getRequestResponse_; + } + virtual bool handleSetRequest(const JID& from, const String& id, boost::shared_ptr<SoftwareVersion> payload) { + CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com/baz"), from); + CPPUNIT_ASSERT_EQUAL(String("myid"), id); + setPayloads_.push_back(payload); + return setRequestResponse_; + } + + bool getRequestResponse_; + bool setRequestResponse_; + std::vector<boost::shared_ptr<SoftwareVersion> > getPayloads_; + std::vector<boost::shared_ptr<SoftwareVersion> > setPayloads_; + }; + + private: + IQRouter* router_; + DummyIQChannel* channel_; + boost::shared_ptr<SoftwareVersion> payload_; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ResponderTest); |