summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Burgess <pete.burgess@isode.com>2018-03-26 11:17:24 (GMT)
committerPeter Burgess <pete.burgess@isode.com>2018-03-27 12:58:17 (GMT)
commit860ef54501e8c32d91160f798c8f9ecf811f2501 (patch)
tree60e3621f634b10a64fcf5cb1c5da8279c08e78a3 /Swiften/Parser
parent92bba873587e0cfaf53aff6749d4537b13e275e8 (diff)
downloadswift-860ef54501e8c32d91160f798c8f9ecf811f2501.zip
swift-860ef54501e8c32d91160f798c8f9ecf811f2501.tar.bz2
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
Diffstat (limited to 'Swiften/Parser')
-rw-r--r--Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp2
-rw-r--r--Swiften/Parser/PayloadParsers/ReferencePayloadParser.cpp79
-rw-r--r--Swiften/Parser/PayloadParsers/ReferencePayloadParser.h35
-rw-r--r--Swiften/Parser/PayloadParsers/UnitTest/ReferencePayloadParserTest.cpp134
-rw-r--r--Swiften/Parser/SConscript1
5 files changed, 251 insertions, 0 deletions
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 <Swiften/Parser/PayloadParsers/PubSubOwnerPubSubParser.h>
#include <Swiften/Parser/PayloadParsers/PubSubParser.h>
#include <Swiften/Parser/PayloadParsers/RawXMLPayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/ReferencePayloadParser.h>
#include <Swiften/Parser/PayloadParsers/ReplaceParser.h>
#include <Swiften/Parser/PayloadParsers/ResourceBindParser.h>
#include <Swiften/Parser/PayloadParsers/ResultSetParser.h>
@@ -187,6 +188,7 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() {
factories_.push_back(std::make_shared<GenericPayloadParserFactory2<CarbonsSentParser> >("sent", "urn:xmpp:carbons:2", this));
factories_.push_back(std::make_shared<GenericPayloadParserFactory<CarbonsPrivateParser> >("private", "urn:xmpp:carbons:2"));
factories_.push_back(std::make_shared<MIXJoinParserFactory>());
+ factories_.push_back(std::make_shared<GenericPayloadParserFactory2<ReferencePayloadParser> >("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 <Swiften/Parser/PayloadParsers/ReferencePayloadParser.h>
+
+#include <cassert>
+#include <iostream>
+
+#include <Swiften/Parser/PayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParserFactoryCollection.h>
+
+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 <Swiften/Base/API.h>
+#include <Swiften/Elements/ReferencePayload.h>
+#include <Swiften/Parser/GenericPayloadParser.h>
+
+namespace Swift {
+
+ class PayloadParserFactoryCollection;
+
+ class SWIFTEN_API ReferencePayloadParser : public GenericPayloadParser<ReferencePayload> {
+ 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<PayloadParser> 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 <gtest/gtest.h>
+
+#include <Swiften/Elements/Body.h>
+#include <Swiften/Elements/Delay.h>
+#include <Swiften/Elements/ErrorPayload.h>
+#include <Swiften/Parser/PayloadParsers/ReferencePayloadParser.h>
+#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h>
+
+using namespace Swift;
+
+TEST(ReferencePayloadParserTest, testParse) {
+ PayloadsParserTester parser;
+
+ ASSERT_TRUE(parser.parse(
+ "<reference xmlns='urn:xmpp:reference:0' "
+ "type='data' "
+ "uri='https://www.example.com/mindBlowingImage.jpeg' "
+ "begin='11' "
+ "end='22' "
+ "anchor='xmpp:data@localhost.example.test'>"
+ "</reference>"));
+
+ auto payload = std::dynamic_pointer_cast<ReferencePayload>(parser.getPayload());
+ ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(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(
+ "<reference xmlns='urn:xmpp:reference:0' "
+ "uri='https://www.example.com/mindBlowingImage.jpeg' "
+ "begin='11' "
+ "end='22' "
+ "anchor='xmpp:data@localhost.example.test'>"
+ "</reference>"));
+
+ auto payload = std::dynamic_pointer_cast<ReferencePayload>(parser.getPayload());
+ ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Unknown), static_cast<int>(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(
+ "<reference xmlns='urn:xmpp:reference:0' type='data'> "
+ "<error type=\"modify\">"
+ "<bad-request xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"
+ "<delay xmlns='urn:xmpp:delay' from='juliet@capulet.com/balcony' stamp='2002-09-10T23:41:07Z'/>"
+ "<text xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\">boo</text>"
+ "</error>"
+ "</reference>"));
+
+ auto payload = std::dynamic_pointer_cast<ReferencePayload>(parser.getPayload());
+ ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(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<ErrorPayload>(childPayloadList[0]);
+ ASSERT_TRUE(errorPayload);
+ ASSERT_EQ("boo", errorPayload->getText());
+ auto delayPayload = std::dynamic_pointer_cast<Delay>(errorPayload->getPayload());
+ ASSERT_TRUE(delayPayload);
+}
+
+TEST(ReferencePayloadParserTest, testParseEmbeddedPayloadWithText) {
+ PayloadsParserTester parser;
+
+ ASSERT_TRUE(parser.parse(
+ "<reference xmlns='urn:xmpp:reference:0' type='data'> "
+ "<body>Example Text</body>"
+ "</reference>"));
+
+ auto payload = std::dynamic_pointer_cast<ReferencePayload>(parser.getPayload());
+ auto childPayloadList = payload->getPayloads();
+ auto bodyPayload = std::dynamic_pointer_cast<Body>(childPayloadList[0]);
+ ASSERT_EQ("Example Text", bodyPayload->getText());
+}
+
+TEST(ReferencePayloadParserTest, testParseRecursive) {
+ PayloadsParserTester parser;
+
+ ASSERT_TRUE(parser.parse(
+ "<reference xmlns='urn:xmpp:reference:0' type='data'> "
+ "<reference xmlns='urn:xmpp:reference:0' type='data' uri='https://download.montague.lit/4a771ac1-f0b2-4a4a-9700-f2a26fa2bb67/summit.jpg' /> "
+ "<reference xmlns='urn:xmpp:reference:0' type='data' uri='xmpp:romeo@montague.lit/resource?jingle;id=9559976B-3FBF-4E7E-B457-2DAA225972BB' /> "
+ "<reference xmlns='urn:xmpp:reference:0' type='data'> "
+ "<reference xmlns='urn:xmpp:reference:0' type='data' uri='https://www.example.com/mindBlowingImage.jpeg' /> "
+ "</reference>"
+ "</reference>"));
+
+ auto payload = std::dynamic_pointer_cast<ReferencePayload>(parser.getPayload());
+ ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(payload->getType()));
+ auto childPayloadList = payload->getPayloads();
+ auto childPayloadA = std::dynamic_pointer_cast<ReferencePayload>(childPayloadList[0]);
+ auto childPayloadB = std::dynamic_pointer_cast<ReferencePayload>(childPayloadList[1]);
+ auto childPayloadC = std::dynamic_pointer_cast<ReferencePayload>(childPayloadList[2]);
+ ASSERT_TRUE(childPayloadA);
+ ASSERT_TRUE(childPayloadB);
+ ASSERT_TRUE(childPayloadC);
+ ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(childPayloadA->getType()));
+ ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(childPayloadB->getType()));
+ ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(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<ReferencePayload>(grandChildPayloadList[0]);
+ ASSERT_TRUE(grandChildPayload);
+ ASSERT_EQ(static_cast<int>(ReferencePayload::Type::Data), static_cast<int>(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",