From 860ef54501e8c32d91160f798c8f9ecf811f2501 Mon Sep 17 00:00:00 2001 From: Peter Burgess Date: Mon, 26 Mar 2018 12:17:24 +0100 Subject: Add new ReferencePayload element class, parser and serializer Added a new element object ReferencePayload, and created the parser and serializer to handle this element. Currently no functionality to send references directly in swift, nor to render their contents. Test-Information: Unit tests written and passed for serializer and parser, testing various types of valid and invalid references, and testing references with embedded payloads. Change-Id: I81fd5d9e020fac1729640f297705806af97f6388 diff --git a/Sluift/Examples/SendReference.lua b/Sluift/Examples/SendReference.lua index b705172..2e60182 100644 --- a/Sluift/Examples/SendReference.lua +++ b/Sluift/Examples/SendReference.lua @@ -37,7 +37,7 @@ function get_password(prompt) if stty_ret then io.write("\027[m") else - os.execute("stty sane") + os.execute("stty echo") end io.write("\n"); if ok then @@ -55,6 +55,7 @@ datauri = #arg > 2 and arg[3] or DEFAULT_URI sluift.debug = 1 sluift.with(sluift.new_client(jid, password), function() + options = { host=os.getenv("XMPP_HOST"), port=os.getenv("XMPP_PORT") } connect(options) reference = { ['_type'] = 'dom', @@ -63,6 +64,9 @@ sluift.with(sluift.new_client(jid, password), function() ['attributes'] = { { ['name'] = 'type', ['value'] = 'data' }, { ['name'] = 'uri', ['value'] = datauri }, + { ['name'] = 'mimeType', ['value'] = arg[4] }, + { ['name'] = 'begin', ['value'] = arg[5] }, + { ['name'] = 'end', ['value'] = arg[6] } }, } send_message{to=tojid, body="Check out this data!", payloads={reference}} diff --git a/Swift/QtUI/QtWebKitChatView.cpp b/Swift/QtUI/QtWebKitChatView.cpp index f3d23e7..6a7018e 100644 --- a/Swift/QtUI/QtWebKitChatView.cpp +++ b/Swift/QtUI/QtWebKitChatView.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2017 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ diff --git a/Swiften/Elements/DiscoInfo.cpp b/Swiften/Elements/DiscoInfo.cpp index 11f0623..701ed40 100644 --- a/Swiften/Elements/DiscoInfo.cpp +++ b/Swiften/Elements/DiscoInfo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2015 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -26,6 +26,7 @@ const std::string DiscoInfo::MessageDeliveryReceiptsFeature = std::string("urn:x const std::string DiscoInfo::WhiteboardFeature = std::string("http://swift.im/whiteboard"); const std::string DiscoInfo::BlockingCommandFeature = std::string("urn:xmpp:blocking"); const std::string DiscoInfo::MessageCarbonsFeature = std::string("urn:xmpp:carbons:2"); +const std::string DiscoInfo::ReferencesFeature = std::string("urn:xmpp:references:0"); bool DiscoInfo::Identity::operator<(const Identity& other) const { if (category_ == other.category_) { diff --git a/Swiften/Elements/DiscoInfo.h b/Swiften/Elements/DiscoInfo.h index c8009ee..713eaba 100644 --- a/Swiften/Elements/DiscoInfo.h +++ b/Swiften/Elements/DiscoInfo.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -37,6 +37,7 @@ namespace Swift { static const std::string WhiteboardFeature; static const std::string BlockingCommandFeature; static const std::string MessageCarbonsFeature; + static const std::string ReferencesFeature; class Identity { public: diff --git a/Swiften/Elements/ReferencePayload.cpp b/Swiften/Elements/ReferencePayload.cpp new file mode 100644 index 0000000..288f28f --- /dev/null +++ b/Swiften/Elements/ReferencePayload.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include + +namespace Swift { + +ReferencePayload::ReferencePayload() + : type_(Type::Data) { +} + +const ReferencePayload::Type& ReferencePayload::getType() const { + return type_; +} + +void ReferencePayload::setType(const ReferencePayload::Type& type) { + type_ = type; +} + +const boost::optional& ReferencePayload::getUri() const { + return uri_; +} + +void ReferencePayload::setUri(const boost::optional& uri) { + uri_ = uri; +} + +const boost::optional& ReferencePayload::getBegin() const { + return begin_; +} + +void ReferencePayload::setBegin(const boost::optional& begin) { + begin_ = begin; +} + +const boost::optional& ReferencePayload::getEnd() const { + return end_; +} + +void ReferencePayload::setEnd(const boost::optional& end) { + end_ = end; +} + +const boost::optional& ReferencePayload::getAnchor() const { + return anchor_; +} + +void ReferencePayload::setAnchor(const boost::optional& anchor) { + anchor_ = anchor; +} + +const std::vector>& ReferencePayload::getPayloads() const { + return payloads_; +} + +void ReferencePayload::addPayload(const std::shared_ptr& payload) { + payloads_.push_back(payload); +} + +} diff --git a/Swiften/Elements/ReferencePayload.h b/Swiften/Elements/ReferencePayload.h new file mode 100644 index 0000000..b9a394e --- /dev/null +++ b/Swiften/Elements/ReferencePayload.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +#include +#include + +#include + +#include +#include + +namespace Swift { + /** + * reference from XEP-0372 + */ + class SWIFTEN_API ReferencePayload : public Payload { + + public: + + typedef std::shared_ptr ref; + + enum class Type { + Data, + Mention, + PubSub, + Unknown + }; + + ReferencePayload(); + + const Type& getType() const; + const boost::optional& getUri() const; + const boost::optional& getBegin() const; + const boost::optional& getEnd() const; + const boost::optional& getAnchor() const; + + const std::vector>& getPayloads() const; + + void setType(const Type& type); + void setUri(const boost::optional& uri); + void setBegin(const boost::optional& begin); + void setEnd(const boost::optional& end); + void setAnchor(const boost::optional& anchor); + + void addPayload(const std::shared_ptr& payload); + + private: + + Type type_; + boost::optional uri_; + boost::optional begin_; + boost::optional end_; + boost::optional anchor_; + + std::vector> payloads_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp index 43c4ebb..9e56b63 100644 --- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp +++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp @@ -75,6 +75,7 @@ #include #include #include +#include #include #include #include @@ -187,6 +188,7 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() { factories_.push_back(std::make_shared >("sent", "urn:xmpp:carbons:2", this)); factories_.push_back(std::make_shared >("private", "urn:xmpp:carbons:2")); factories_.push_back(std::make_shared()); + factories_.push_back(std::make_shared >("reference", "urn:xmpp:reference:0", this)); for (auto& factory : factories_) { addFactory(factory.get()); diff --git a/Swiften/Parser/PayloadParsers/ReferencePayloadParser.cpp b/Swiften/Parser/PayloadParsers/ReferencePayloadParser.cpp new file mode 100644 index 0000000..a337a29 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ReferencePayloadParser.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include + +#include +#include + +#include +#include + +namespace Swift { + +ReferencePayloadParser::ReferencePayloadParser(PayloadParserFactoryCollection* factories) : factories_(factories) { +} + +ReferencePayload::Type ReferencePayloadParser::getTypeFromString(const std::string& typeString) const { + if (typeString == "data") { + return ReferencePayload::Type::Data; + } + else if (typeString == "mention") { + return ReferencePayload::Type::Mention; + } + else if (typeString == "pubsub") { + return ReferencePayload::Type::PubSub; + } + else { + return ReferencePayload::Type::Unknown; + } +} + +void ReferencePayloadParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level_ == topLevel_) { + if (element == "reference") { + getPayloadInternal()->setType(getTypeFromString(attributes.getAttribute("type"))); + getPayloadInternal()->setUri(attributes.getAttributeValue("uri")); + getPayloadInternal()->setBegin(attributes.getAttributeValue("begin")); + getPayloadInternal()->setEnd(attributes.getAttributeValue("end")); + getPayloadInternal()->setAnchor(attributes.getAttributeValue("anchor")); + } + } + else if (level_ == payloadLevel_) { + PayloadParserFactory* payloadParserFactory = factories_->getPayloadParserFactory(element, ns, attributes); + if (payloadParserFactory) { + currentPayloadParser_.reset(payloadParserFactory->createPayloadParser()); + } + } + + if (level_ >= payloadLevel_ && currentPayloadParser_) { + currentPayloadParser_->handleStartElement(element, ns, attributes); + } + + ++level_; +} + +void ReferencePayloadParser::handleEndElement(const std::string& element, const std::string& ns) { + --level_; + if (currentPayloadParser_) { + if (level_ >= payloadLevel_) { + currentPayloadParser_->handleEndElement(element, ns); + } + + if (level_ == payloadLevel_) { + getPayloadInternal()->addPayload(currentPayloadParser_->getPayload()); + currentPayloadParser_.reset(); + } + } +} + +void ReferencePayloadParser::handleCharacterData(const std::string& data) { + if (level_ > payloadLevel_ && currentPayloadParser_) { + currentPayloadParser_->handleCharacterData(data); + } +} + +} diff --git a/Swiften/Parser/PayloadParsers/ReferencePayloadParser.h b/Swiften/Parser/PayloadParsers/ReferencePayloadParser.h new file mode 100644 index 0000000..3afd181 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ReferencePayloadParser.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +#include +#include +#include + +namespace Swift { + + class PayloadParserFactoryCollection; + + class SWIFTEN_API ReferencePayloadParser : public GenericPayloadParser { + public: + + ReferencePayloadParser(PayloadParserFactoryCollection* factories); + + virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string& ns); + virtual void handleCharacterData(const std::string& data); + + private: + + ReferencePayload::Type getTypeFromString(const std::string& typeString) const; + int level_ = 0; + const int topLevel_ = 0; + const int payloadLevel_ = 1; + PayloadParserFactoryCollection* factories_; + std::shared_ptr currentPayloadParser_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/UnitTest/ReferencePayloadParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/ReferencePayloadParserTest.cpp new file mode 100644 index 0000000..ca7b280 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/ReferencePayloadParserTest.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include + +#include +#include +#include +#include +#include + +using namespace Swift; + +TEST(ReferencePayloadParserTest, testParse) { + PayloadsParserTester parser; + + ASSERT_TRUE(parser.parse( + "" + "")); + + auto payload = std::dynamic_pointer_cast(parser.getPayload()); + ASSERT_EQ(static_cast(ReferencePayload::Type::Data), static_cast(payload->getType())); + ASSERT_EQ(std::string("https://www.example.com/mindBlowingImage.jpeg"), *payload->getUri()); + ASSERT_EQ(std::string("11"), *payload->getBegin()); + ASSERT_EQ(std::string("22"), *payload->getEnd()); + ASSERT_EQ(std::string("xmpp:data@localhost.example.test"), *payload->getAnchor()); +} + +TEST(ReferencePayloadParserTest, testParseNoType) { + PayloadsParserTester parser; + + ASSERT_TRUE(parser.parse( + "" + "")); + + auto payload = std::dynamic_pointer_cast(parser.getPayload()); + ASSERT_EQ(static_cast(ReferencePayload::Type::Unknown), static_cast(payload->getType())); + ASSERT_EQ(std::string("https://www.example.com/mindBlowingImage.jpeg"), *payload->getUri()); + ASSERT_EQ(std::string("11"), *payload->getBegin()); + ASSERT_EQ(std::string("22"), *payload->getEnd()); + ASSERT_EQ(std::string("xmpp:data@localhost.example.test"), *payload->getAnchor()); +} + +TEST(ReferencePayloadParserTest, testParseEmbeddedPayloads) { + PayloadsParserTester parser; + + ASSERT_TRUE(parser.parse( + " " + "" + "" + "" + "boo" + "" + "")); + + auto payload = std::dynamic_pointer_cast(parser.getPayload()); + ASSERT_EQ(static_cast(ReferencePayload::Type::Data), static_cast(payload->getType())); + ASSERT_FALSE(payload->getUri()); + ASSERT_FALSE(payload->getBegin()); + ASSERT_FALSE(payload->getEnd()); + ASSERT_FALSE(payload->getAnchor()); + auto childPayloadList = payload->getPayloads(); + auto errorPayload = std::dynamic_pointer_cast(childPayloadList[0]); + ASSERT_TRUE(errorPayload); + ASSERT_EQ("boo", errorPayload->getText()); + auto delayPayload = std::dynamic_pointer_cast(errorPayload->getPayload()); + ASSERT_TRUE(delayPayload); +} + +TEST(ReferencePayloadParserTest, testParseEmbeddedPayloadWithText) { + PayloadsParserTester parser; + + ASSERT_TRUE(parser.parse( + " " + "Example Text" + "")); + + auto payload = std::dynamic_pointer_cast(parser.getPayload()); + auto childPayloadList = payload->getPayloads(); + auto bodyPayload = std::dynamic_pointer_cast(childPayloadList[0]); + ASSERT_EQ("Example Text", bodyPayload->getText()); +} + +TEST(ReferencePayloadParserTest, testParseRecursive) { + PayloadsParserTester parser; + + ASSERT_TRUE(parser.parse( + " " + " " + " " + " " + " " + "" + "")); + + auto payload = std::dynamic_pointer_cast(parser.getPayload()); + ASSERT_EQ(static_cast(ReferencePayload::Type::Data), static_cast(payload->getType())); + auto childPayloadList = payload->getPayloads(); + auto childPayloadA = std::dynamic_pointer_cast(childPayloadList[0]); + auto childPayloadB = std::dynamic_pointer_cast(childPayloadList[1]); + auto childPayloadC = std::dynamic_pointer_cast(childPayloadList[2]); + ASSERT_TRUE(childPayloadA); + ASSERT_TRUE(childPayloadB); + ASSERT_TRUE(childPayloadC); + ASSERT_EQ(static_cast(ReferencePayload::Type::Data), static_cast(childPayloadA->getType())); + ASSERT_EQ(static_cast(ReferencePayload::Type::Data), static_cast(childPayloadB->getType())); + ASSERT_EQ(static_cast(ReferencePayload::Type::Data), static_cast(childPayloadC->getType())); + ASSERT_EQ(std::string("https://download.montague.lit/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/summit.jpg"), *childPayloadA->getUri()); + ASSERT_EQ(std::string("xmpp:romeo@montague.lit/resource?jingle;id=9559976B-3FBF-4E7E-B457-2DAA225972BB"), *childPayloadB->getUri()); + ASSERT_FALSE(childPayloadC->getUri()); + ASSERT_FALSE(childPayloadC->getBegin()); + ASSERT_FALSE(childPayloadC->getEnd()); + ASSERT_FALSE(childPayloadC->getAnchor()); + auto grandChildPayloadList = childPayloadC->getPayloads(); + auto grandChildPayload = std::dynamic_pointer_cast(grandChildPayloadList[0]); + ASSERT_TRUE(grandChildPayload); + ASSERT_EQ(static_cast(ReferencePayload::Type::Data), static_cast(grandChildPayload->getType())); + ASSERT_EQ(std::string("https://www.example.com/mindBlowingImage.jpeg"), *grandChildPayload->getUri()); + ASSERT_FALSE(grandChildPayload->getBegin()); + ASSERT_FALSE(grandChildPayload->getEnd()); + ASSERT_FALSE(grandChildPayload->getAnchor()); +} diff --git a/Swiften/Parser/SConscript b/Swiften/Parser/SConscript index 30c61a7..4ac5aa4 100644 --- a/Swiften/Parser/SConscript +++ b/Swiften/Parser/SConscript @@ -53,6 +53,7 @@ sources = [ "PayloadParsers/PriorityParser.cpp", "PayloadParsers/PrivateStorageParser.cpp", "PayloadParsers/RawXMLPayloadParser.cpp", + "PayloadParsers/ReferencePayloadParser.cpp", "PayloadParsers/ResourceBindParser.cpp", "PayloadParsers/RosterItemExchangeParser.cpp", "PayloadParsers/RosterParser.cpp", diff --git a/Swiften/QA/TLSTest/SConscript b/Swiften/QA/TLSTest/SConscript index 7811b50..81e2471 100644 --- a/Swiften/QA/TLSTest/SConscript +++ b/Swiften/QA/TLSTest/SConscript @@ -24,4 +24,4 @@ if env["TEST"] : # Reenable if either http://www.tls-o-matic.com/ is fixed or we have setup a replacement. #"CertificateErrorTest.cpp" ]) - myenv.Test(tester, "system") \ No newline at end of file + myenv.Test(tester, "system") diff --git a/Swiften/SConscript b/Swiften/SConscript index 5fb3b47..db08225 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -142,6 +142,7 @@ if env["SCONS_STAGE"] == "build" : "Elements/PubSubPayload.cpp", "Elements/PubSubOwnerPayload.cpp", "Elements/PubSubEventPayload.cpp", + "Elements/ReferencePayload.cpp", "Elements/RosterItemExchangePayload.cpp", "Elements/RosterPayload.cpp", "Elements/SecurityLabel.cpp", @@ -225,6 +226,7 @@ if env["SCONS_STAGE"] == "build" : "Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.cpp", "Serializer/PayloadSerializers/MUCDestroyPayloadSerializer.cpp", "Serializer/PayloadSerializers/MUCInvitationPayloadSerializer.cpp", + "Serializer/PayloadSerializers/ReferencePayloadSerializer.cpp", "Serializer/PayloadSerializers/ResourceBindSerializer.cpp", "Serializer/PayloadSerializers/RosterItemExchangeSerializer.cpp", "Serializer/PayloadSerializers/RosterSerializer.cpp", @@ -437,6 +439,7 @@ if env["SCONS_STAGE"] == "build" : File("Parser/PayloadParsers/UnitTest/CommandParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/PriorityParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/RawXMLPayloadParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/ReferencePayloadParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/ResourceBindParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/RosterItemExchangeParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/RosterParserTest.cpp"), @@ -514,6 +517,7 @@ if env["SCONS_STAGE"] == "build" : File("Serializer/PayloadSerializers/UnitTest/ErrorSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/IBBSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/PrioritySerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/ReferencePayloadSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/ResourceBindSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/RosterItemExchangeSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/RosterSerializerTest.cpp"), diff --git a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp index 428ce76..31294f1 100644 --- a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp +++ b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp @@ -69,6 +69,7 @@ #include #include #include +#include #include #include #include @@ -186,6 +187,8 @@ FullPayloadSerializerCollection::FullPayloadSerializerCollection() { serializers_.push_back(new IsodeIQDelegationSerializer(this)); + serializers_.push_back(new ReferencePayloadSerializer(this)); + for (auto serializer : serializers_) { addSerializer(serializer); } diff --git a/Swiften/Serializer/PayloadSerializers/ReferencePayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/ReferencePayloadSerializer.cpp new file mode 100644 index 0000000..6e78a8d --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/ReferencePayloadSerializer.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include + +#include + +#include +#include +#include +#include + +namespace Swift { + +ReferencePayloadSerializer::ReferencePayloadSerializer(PayloadSerializerCollection* payloadSerializers) : GenericPayloadSerializer(), payloadSerializers_(payloadSerializers) { +} + +std::string ReferencePayloadSerializer::serializePayload(ReferencePayload::ref reference) const { + XMLElement element("reference", "urn:xmpp:reference:0"); + + auto type = reference->getType(); + if (type != ReferencePayload::Type::Unknown) { + element.setAttribute("type", getTypeString(type)); + + if (auto uri = reference->getUri()) { + element.setAttribute("uri", *uri); + } + if (auto begin = reference->getBegin()) { + element.setAttribute("begin", *begin); + } + if (auto end = reference->getEnd()) { + element.setAttribute("end", *end); + } + if (auto anchor = reference->getAnchor()) { + element.setAttribute("anchor", *anchor); + } + + std::string serializedPayloads; + for (const auto& payload : reference->getPayloads()) { + if (auto serializer = payloadSerializers_->getPayloadSerializer(payload)) { + element.addNode(std::make_shared(serializer->serialize(payload))); + } + else { + SWIFT_LOG(warning) << "Could not find serializer for " << typeid(*(payload.get())).name() << std::endl; + } + } + } + return element.serialize(); +} + +const std::string ReferencePayloadSerializer::getTypeString(const ReferencePayload::Type type) const { + switch(type) { + case ReferencePayload::Type::Data: return "data"; + case ReferencePayload::Type::Mention: return "mention"; + case ReferencePayload::Type::PubSub: return "pubsub"; + case ReferencePayload::Type::Unknown: return "unknown"; + } + return ""; +} + +} diff --git a/Swiften/Serializer/PayloadSerializers/ReferencePayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/ReferencePayloadSerializer.h new file mode 100644 index 0000000..2af6045 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/ReferencePayloadSerializer.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +#include +#include +#include + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API ReferencePayloadSerializer : public GenericPayloadSerializer { + public: + ReferencePayloadSerializer(PayloadSerializerCollection* payloadSerializers); + virtual std::string serializePayload(ReferencePayload::ref reference) const; + + private: + const std::string getTypeString(const ReferencePayload::Type type) const; + + PayloadSerializerCollection* payloadSerializers_; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/ReferencePayloadSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/ReferencePayloadSerializerTest.cpp new file mode 100644 index 0000000..82465d7 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/ReferencePayloadSerializerTest.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include + +#include + +#include +#include + +using namespace Swift; + +static FullPayloadSerializerCollection serializers; + +TEST(ReferencePayloadSerializerTest, testSerialize) { + ReferencePayloadSerializer testling(&serializers); + auto reference = std::make_shared(); + reference->setType(ReferencePayload::Type::Data); + reference->setUri(boost::optional("https://www.example.com/mindBlowingImage.jpeg")); + reference->setBegin(boost::optional("11")); + reference->setEnd(boost::optional("22")); + reference->setAnchor(boost::optional("xmpp:data@localhost.example.test")); + + std::string expectedResult = + ""; + + ASSERT_EQ(expectedResult, testling.serialize(reference)); +} + +TEST(ReferencePayloadSerializerTest, testSerializeNoType) { + ReferencePayloadSerializer testling(&serializers); + auto reference = std::make_shared(); + reference->setUri(boost::optional("https://www.example.com/mindBlowingImage.jpeg")); + reference->setBegin(boost::optional("11")); + reference->setEnd(boost::optional("22")); + reference->setAnchor(boost::optional("xmpp:data@localhost.example.test")); + + std::string expectedResult = + ""; + + ASSERT_EQ(expectedResult, testling.serialize(reference)); +} + +TEST(ReferencePayloadSerializerTest, testSerializeWithEmbeddedPayload) { + ReferencePayloadSerializer testling(&serializers); + auto reference = std::make_shared(); + reference->setUri(boost::optional("https://www.example.com/mindBlowingImage.jpeg")); + reference->setBegin(boost::optional("11")); + reference->setEnd(boost::optional("22")); + reference->setAnchor(boost::optional("xmpp:data@localhost.example.test")); + auto payload = std::make_shared(std::string("Look, I'm in a reference")); + reference->addPayload(payload); + + std::string expectedResult = + "" + "Look, I'm in a reference" + ""; + + ASSERT_EQ(expectedResult, testling.serialize(reference)); +} -- cgit v0.10.2-6-g49f6