summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/Queries')
-rw-r--r--Swiften/Queries/DummyIQChannel.h25
-rw-r--r--Swiften/Queries/GenericRequest.h30
-rw-r--r--Swiften/Queries/IQChannel.cpp8
-rw-r--r--Swiften/Queries/IQChannel.h22
-rw-r--r--Swiften/Queries/IQHandler.cpp14
-rw-r--r--Swiften/Queries/IQHandler.h28
-rw-r--r--Swiften/Queries/IQRouter.cpp46
-rw-r--r--Swiften/Queries/IQRouter.h33
-rw-r--r--Swiften/Queries/Makefile.inc8
-rw-r--r--Swiften/Queries/Request.cpp39
-rw-r--r--Swiften/Queries/Request.h46
-rw-r--r--Swiften/Queries/Requests/GetDiscoInfoRequest.h16
-rw-r--r--Swiften/Queries/Requests/GetRosterRequest.h16
-rw-r--r--Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h20
-rw-r--r--Swiften/Queries/Responder.h49
-rw-r--r--Swiften/Queries/Responders/DiscoInfoResponder.cpp40
-rw-r--r--Swiften/Queries/Responders/DiscoInfoResponder.h29
-rw-r--r--Swiften/Queries/Responders/Makefile.inc5
-rw-r--r--Swiften/Queries/Responders/SoftwareVersionResponder.cpp20
-rw-r--r--Swiften/Queries/Responders/SoftwareVersionResponder.h24
-rw-r--r--Swiften/Queries/Responders/UnitTest/DiscoInfoResponderTest.cpp84
-rw-r--r--Swiften/Queries/Responders/UnitTest/Makefile.inc2
-rw-r--r--Swiften/Queries/UnitTest/Makefile.inc3
-rw-r--r--Swiften/Queries/UnitTest/RequestTest.cpp139
-rw-r--r--Swiften/Queries/UnitTest/ResponderTest.cpp132
25 files changed, 878 insertions, 0 deletions
diff --git a/Swiften/Queries/DummyIQChannel.h b/Swiften/Queries/DummyIQChannel.h
new file mode 100644
index 0000000..f72d7a5
--- /dev/null
+++ b/Swiften/Queries/DummyIQChannel.h
@@ -0,0 +1,25 @@
+#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";
+ }
+
+ 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..c81760f
--- /dev/null
+++ b/Swiften/Queries/GenericRequest.h
@@ -0,0 +1,30 @@
+#ifndef SWIFTEN_GenericRequest_H
+#define SWIFTEN_GenericRequest_H
+
+#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,
+ AutoDeleteBehavior autoDeleteBehavior = DoNotAutoDelete) :
+ Request(type, receiver, payload, router, autoDeleteBehavior) {
+ }
+
+ virtual void handleResponse(boost::shared_ptr<Payload> payload, boost::optional<Error> error) {
+ onResponse(boost::dynamic_pointer_cast<PAYLOAD_TYPE>(payload), error);
+ }
+
+ public:
+ boost::signal<void (boost::shared_ptr<PAYLOAD_TYPE>, const boost::optional<Error>&)> onResponse;
+ };
+}
+
+#endif
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..0dbb1be
--- /dev/null
+++ b/Swiften/Queries/IQChannel.h
@@ -0,0 +1,22 @@
+#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;
+
+ 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..b5e7e49
--- /dev/null
+++ b/Swiften/Queries/IQHandler.cpp
@@ -0,0 +1,14 @@
+#include "Swiften/Queries/IQHandler.h"
+#include "Swiften/Queries/IQRouter.h"
+
+namespace Swift {
+
+IQHandler::IQHandler(IQRouter* router) : router_(router) {
+ router_->addHandler(this);
+}
+
+IQHandler::~IQHandler() {
+ router_->removeHandler(this);
+}
+
+}
diff --git a/Swiften/Queries/IQHandler.h b/Swiften/Queries/IQHandler.h
new file mode 100644
index 0000000..7a8d008
--- /dev/null
+++ b/Swiften/Queries/IQHandler.h
@@ -0,0 +1,28 @@
+#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:
+ IQHandler(IQRouter* router);
+ virtual ~IQHandler();
+
+ virtual bool handleIQ(boost::shared_ptr<IQ>) = 0;
+
+ protected:
+ IQRouter* getRouter() const {
+ return router_;
+ }
+
+ private:
+ IQRouter* router_;
+ };
+}
+
+#endif
diff --git a/Swiften/Queries/IQRouter.cpp b/Swiften/Queries/IQRouter.cpp
new file mode 100644
index 0000000..b474640
--- /dev/null
+++ b/Swiften/Queries/IQRouter.cpp
@@ -0,0 +1,46 @@
+#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/Error.h"
+
+namespace Swift {
+
+IQRouter::IQRouter(IQChannel* channel) : channel_(channel) {
+ channel->onIQReceived.connect(boost::bind(&IQRouter::handleIQ, this, _1));
+}
+
+void IQRouter::handleIQ(boost::shared_ptr<IQ> iq) {
+ bool handled = false;
+ foreach(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(), Error::FeatureNotImplemented, Error::Cancel));
+ }
+}
+
+void IQRouter::addHandler(IQHandler* handler) {
+ handlers_.push_back(handler);
+}
+
+void IQRouter::removeHandler(IQHandler* handler) {
+ 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..2240dfb
--- /dev/null
+++ b/Swiften/Queries/IQRouter.h
@@ -0,0 +1,33 @@
+#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);
+
+ void addHandler(IQHandler* handler);
+ void removeHandler(IQHandler* handler);
+
+ void sendIQ(boost::shared_ptr<IQ> iq);
+ String getNewIQID();
+
+ private:
+ void handleIQ(boost::shared_ptr<IQ> iq);
+
+ private:
+ IQChannel* channel_;
+ std::vector<IQHandler*> handlers_;
+ };
+}
+
+#endif
diff --git a/Swiften/Queries/Makefile.inc b/Swiften/Queries/Makefile.inc
new file mode 100644
index 0000000..53a712d
--- /dev/null
+++ b/Swiften/Queries/Makefile.inc
@@ -0,0 +1,8 @@
+SWIFTEN_SOURCES += \
+ Swiften/Queries/IQRouter.cpp \
+ Swiften/Queries/IQHandler.cpp \
+ Swiften/Queries/IQChannel.cpp \
+ Swiften/Queries/Request.cpp
+
+include Swiften/Queries/Responders/Makefile.inc
+include Swiften/Queries/UnitTest/Makefile.inc
diff --git a/Swiften/Queries/Request.cpp b/Swiften/Queries/Request.cpp
new file mode 100644
index 0000000..ac361cc
--- /dev/null
+++ b/Swiften/Queries/Request.cpp
@@ -0,0 +1,39 @@
+#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, AutoDeleteBehavior autoDeleteBehavior) : IQHandler(router), type_(type), receiver_(receiver), payload_(payload), autoDeleteBehavior_(autoDeleteBehavior) {
+ id_ = getRouter()->getNewIQID();
+}
+
+void Request::send() {
+ boost::shared_ptr<IQ> iq(new IQ(type_));
+ iq->setTo(receiver_);
+ iq->addPayload(payload_);
+ iq->setID(id_);
+ getRouter()->sendIQ(iq);
+}
+
+bool Request::handleIQ(boost::shared_ptr<IQ> iq) {
+ if (iq->getID() == id_) {
+ if (iq->getType() == IQ::Result) {
+ handleResponse(iq->getPayloadOfSameType(payload_), boost::optional<Error>());
+ if (autoDeleteBehavior_ == AutoDeleteAfterResponse) {
+ MainEventLoop::deleteLater(this);
+ }
+ return true;
+ }
+ else {
+ // FIXME: Get proper error
+ handleResponse(boost::shared_ptr<Payload>(), boost::optional<Error>(Error::UndefinedCondition));
+ return true;
+ }
+ }
+ else {
+ return false;
+ }
+}
+
+}
diff --git a/Swiften/Queries/Request.h b/Swiften/Queries/Request.h
new file mode 100644
index 0000000..f084303
--- /dev/null
+++ b/Swiften/Queries/Request.h
@@ -0,0 +1,46 @@
+#ifndef SWIFTEN_Request_H
+#define SWIFTEN_Request_H
+
+#include <boost/shared_ptr.hpp>
+#include <boost/optional.hpp>
+
+#include "Swiften/Base/String.h"
+#include "Swiften/Queries/IQHandler.h"
+#include "Swiften/Elements/IQ.h"
+#include "Swiften/Elements/Payload.h"
+#include "Swiften/Elements/Error.h"
+#include "Swiften/JID/JID.h"
+
+namespace Swift {
+ class Request : public IQHandler {
+ public:
+ enum AutoDeleteBehavior {
+ DoNotAutoDelete,
+ AutoDeleteAfterResponse
+ };
+
+ Request(
+ IQ::Type type,
+ const JID& receiver,
+ boost::shared_ptr<Payload> payload,
+ IQRouter* router,
+ AutoDeleteBehavior = DoNotAutoDelete);
+
+ void send();
+
+ protected:
+ virtual void handleResponse(boost::shared_ptr<Payload>, boost::optional<Error>) = 0;
+
+ private:
+ bool handleIQ(boost::shared_ptr<IQ>);
+
+ private:
+ IQ::Type type_;
+ JID receiver_;
+ boost::shared_ptr<Payload> payload_;
+ AutoDeleteBehavior autoDeleteBehavior_;
+ String id_;
+ };
+}
+
+#endif
diff --git a/Swiften/Queries/Requests/GetDiscoInfoRequest.h b/Swiften/Queries/Requests/GetDiscoInfoRequest.h
new file mode 100644
index 0000000..0e8508e
--- /dev/null
+++ b/Swiften/Queries/Requests/GetDiscoInfoRequest.h
@@ -0,0 +1,16 @@
+#ifndef SWIFTEN_GetDiscoInfoRequest_H
+#define SWIFTEN_GetDiscoInfoRequest_H
+
+#include "Swiften/Queries/GenericRequest.h"
+#include "Swiften/Elements/DiscoInfo.h"
+
+namespace Swift {
+ class GetDiscoInfoRequest : public GenericRequest<DiscoInfo> {
+ public:
+ GetDiscoInfoRequest(const JID& jid, IQRouter* router, AutoDeleteBehavior autoDeleteBehavior = DoNotAutoDelete) :
+ GenericRequest<DiscoInfo>(IQ::Get, jid, boost::shared_ptr<DiscoInfo>(new DiscoInfo()), router, autoDeleteBehavior) {
+ }
+ };
+}
+
+#endif
diff --git a/Swiften/Queries/Requests/GetRosterRequest.h b/Swiften/Queries/Requests/GetRosterRequest.h
new file mode 100644
index 0000000..2364d81
--- /dev/null
+++ b/Swiften/Queries/Requests/GetRosterRequest.h
@@ -0,0 +1,16 @@
+#ifndef SWIFTEN_GetRosterRequest_H
+#define SWIFTEN_GetRosterRequest_H
+
+#include "Swiften/Queries/GenericRequest.h"
+#include "Swiften/Elements/RosterPayload.h"
+
+namespace Swift {
+ class GetRosterRequest : public GenericRequest<RosterPayload> {
+ public:
+ GetRosterRequest(IQRouter* router, AutoDeleteBehavior autoDeleteBehavior = DoNotAutoDelete) :
+ GenericRequest<RosterPayload>(IQ::Get, JID(), boost::shared_ptr<Payload>(new RosterPayload()), router, autoDeleteBehavior) {
+ }
+ };
+}
+
+#endif
diff --git a/Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h b/Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h
new file mode 100644
index 0000000..53ca3eb
--- /dev/null
+++ b/Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h
@@ -0,0 +1,20 @@
+#ifndef SWIFTEN_GetSecurityLabelsCatalogRequest_H
+#define SWIFTEN_GetSecurityLabelsCatalogRequest_H
+
+#include "Swiften/Queries/GenericRequest.h"
+#include "Swiften/Elements/SecurityLabelsCatalog.h"
+
+namespace Swift {
+ class GetSecurityLabelsCatalogRequest : public GenericRequest<SecurityLabelsCatalog> {
+ public:
+ GetSecurityLabelsCatalogRequest(
+ const JID& recipient,
+ IQRouter* router,
+ AutoDeleteBehavior autoDeleteBehavior = DoNotAutoDelete) :
+ GenericRequest<SecurityLabelsCatalog>(
+ IQ::Get, JID(), boost::shared_ptr<SecurityLabelsCatalog>(new SecurityLabelsCatalog(recipient)), router, autoDeleteBehavior) {
+ }
+ };
+}
+
+#endif
diff --git a/Swiften/Queries/Responder.h b/Swiften/Queries/Responder.h
new file mode 100644
index 0000000..b6029ae
--- /dev/null
+++ b/Swiften/Queries/Responder.h
@@ -0,0 +1,49 @@
+#ifndef SWIFTEN_Responder_H
+#define SWIFTEN_Responder_H
+
+#include "Swiften/Queries/IQHandler.h"
+#include "Swiften/Elements/Error.h"
+
+namespace Swift {
+ template<typename PAYLOAD_TYPE>
+ class Responder : public IQHandler {
+ public:
+ Responder(IQRouter* router) : IQHandler(router) {
+ }
+
+ 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) {
+ getRouter()->sendIQ(IQ::createResult(to, id, payload));
+ }
+
+ void sendError(const JID& to, const String& id, Error::Condition condition, Error::Type type) {
+ getRouter()->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) {
+ getRouter()->sendIQ(IQ::createError(iq->getFrom(), iq->getID(), Error::NotAllowed, Error::Cancel));
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+}
+
+#endif
diff --git a/Swiften/Queries/Responders/DiscoInfoResponder.cpp b/Swiften/Queries/Responders/DiscoInfoResponder.cpp
new file mode 100644
index 0000000..e207133
--- /dev/null
+++ b/Swiften/Queries/Responders/DiscoInfoResponder.cpp
@@ -0,0 +1,40 @@
+#include "Swiften/Queries/Responders/DiscoInfoResponder.h"
+#include "Swiften/Queries/IQRouter.h"
+#include "Swiften/Elements/DiscoInfo.h"
+
+namespace Swift {
+
+DiscoInfoResponder::DiscoInfoResponder(IQRouter* router) : Responder<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, Error::ItemNotFound, Error::Cancel);
+ }
+ }
+ return true;
+}
+
+bool DiscoInfoResponder::handleSetRequest(const JID&, const String&, boost::shared_ptr<DiscoInfo>) {
+ return false;
+}
+
+}
diff --git a/Swiften/Queries/Responders/DiscoInfoResponder.h b/Swiften/Queries/Responders/DiscoInfoResponder.h
new file mode 100644
index 0000000..aa79163
--- /dev/null
+++ b/Swiften/Queries/Responders/DiscoInfoResponder.h
@@ -0,0 +1,29 @@
+#ifndef SWIFTEN_DiscoInfoResponder_H
+#define SWIFTEN_DiscoInfoResponder_H
+
+#include <map>
+
+#include "Swiften/Queries/Responder.h"
+#include "Swiften/Elements/DiscoInfo.h"
+
+namespace Swift {
+ class IQRouter;
+
+ class DiscoInfoResponder : public Responder<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);
+ virtual bool handleSetRequest(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/Makefile.inc b/Swiften/Queries/Responders/Makefile.inc
new file mode 100644
index 0000000..5049440
--- /dev/null
+++ b/Swiften/Queries/Responders/Makefile.inc
@@ -0,0 +1,5 @@
+SWIFTEN_SOURCES += \
+ Swiften/Queries/Responders/SoftwareVersionResponder.cpp \
+ Swiften/Queries/Responders/DiscoInfoResponder.cpp
+
+include Swiften/Queries/Responders/UnitTest/Makefile.inc
diff --git a/Swiften/Queries/Responders/SoftwareVersionResponder.cpp b/Swiften/Queries/Responders/SoftwareVersionResponder.cpp
new file mode 100644
index 0000000..dad2442
--- /dev/null
+++ b/Swiften/Queries/Responders/SoftwareVersionResponder.cpp
@@ -0,0 +1,20 @@
+#include "Swiften/Queries/Responders/SoftwareVersionResponder.h"
+#include "Swiften/Queries/IQRouter.h"
+
+namespace Swift {
+
+SoftwareVersionResponder::SoftwareVersionResponder(
+ const String& client, const String& version, IQRouter* router) :
+ Responder<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;
+}
+
+bool SoftwareVersionResponder::handleSetRequest(const JID&, const String&, boost::shared_ptr<SoftwareVersion>) {
+ return false;
+}
+
+}
diff --git a/Swiften/Queries/Responders/SoftwareVersionResponder.h b/Swiften/Queries/Responders/SoftwareVersionResponder.h
new file mode 100644
index 0000000..d66e168
--- /dev/null
+++ b/Swiften/Queries/Responders/SoftwareVersionResponder.h
@@ -0,0 +1,24 @@
+#ifndef SWIFTEN_SoftwareVersionResponder_H
+#define SWIFTEN_SoftwareVersionResponder_H
+
+#include "Swiften/Queries/Responder.h"
+#include "Swiften/Elements/SoftwareVersion.h"
+
+namespace Swift {
+ class IQRouter;
+
+ class SoftwareVersionResponder : public Responder<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);
+ virtual bool handleSetRequest(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..44db138
--- /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<Error> payload(channel_->iqs_[0]->getPayload<Error>());
+ CPPUNIT_ASSERT(payload);
+ }
+
+ private:
+ IQRouter* router_;
+ DummyIQChannel* channel_;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(DiscoInfoResponderTest);
diff --git a/Swiften/Queries/Responders/UnitTest/Makefile.inc b/Swiften/Queries/Responders/UnitTest/Makefile.inc
new file mode 100644
index 0000000..8f06682
--- /dev/null
+++ b/Swiften/Queries/Responders/UnitTest/Makefile.inc
@@ -0,0 +1,2 @@
+UNITTEST_SOURCES += \
+ Swiften/Queries/Responders/UnitTest/DiscoInfoResponderTest.cpp
diff --git a/Swiften/Queries/UnitTest/Makefile.inc b/Swiften/Queries/UnitTest/Makefile.inc
new file mode 100644
index 0000000..265357f
--- /dev/null
+++ b/Swiften/Queries/UnitTest/Makefile.inc
@@ -0,0 +1,3 @@
+UNITTEST_SOURCES += \
+ Swiften/Queries/UnitTest/RequestTest.cpp \
+ Swiften/Queries/UnitTest/ResponderTest.cpp
diff --git a/Swiften/Queries/UnitTest/RequestTest.cpp b/Swiften/Queries/UnitTest/RequestTest.cpp
new file mode 100644
index 0000000..31c0603
--- /dev/null
+++ b/Swiften/Queries/UnitTest/RequestTest.cpp
@@ -0,0 +1,139 @@
+#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_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;
+ errorsReceived_ = 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, errorsReceived_);
+ 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, errorsReceived_);
+ 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();
+
+ channel_->onIQReceived(createError("test-id"));
+
+ CPPUNIT_ASSERT_EQUAL(0, responsesReceived_);
+ CPPUNIT_ASSERT_EQUAL(1, errorsReceived_);
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel_->iqs_.size()));
+ }
+
+ private:
+ void handleResponse(boost::shared_ptr<Payload> p, const boost::optional<Error>& e) {
+ if (e) {
+ ++errorsReceived_;
+ }
+ 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_;
+ int errorsReceived_;
+};
+
+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);