From 8b3082e5fa56540714f3ce9b72f87965a62b5d14 Mon Sep 17 00:00:00 2001
From: Tarun Gupta <tarun1995gupta@gmail.com>
Date: Sat, 24 Jun 2017 23:42:41 +0530
Subject: Add MIXPayload, its Parser and Serializer

License:
This patch is BSD-licensed, see Documentation/Licenses/BSD-simplified.txt for details.

Test-Information:
Added tests for MIXPayload Parser and Serializer based on examples in XEP 0369, which passes.
Tested on Ubuntu 16.04 LTS.

Change-Id: I45da05d6fe57b4be7ed8534dd84cbf0fd31ced1a

diff --git a/Swiften/Elements/MIXPayload.h b/Swiften/Elements/MIXPayload.h
new file mode 100644
index 0000000..3989c18
--- /dev/null
+++ b/Swiften/Elements/MIXPayload.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017 Tarun Gupta
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include <boost/optional.hpp>
+
+#include <Swiften/Base/API.h>
+#include <Swiften/Elements/Payload.h>
+#include <Swiften/JID/JID.h>
+
+namespace Swift {
+    class SWIFTEN_API MIXPayload : public Payload {
+        public:
+            using ref = std::shared_ptr<MIXPayload>;
+
+        public:
+
+            MIXPayload() {}
+
+            const boost::optional<std::string>& getNick() const {
+                return nick_;
+            }
+
+            void setNick(const std::string& nick) {
+                nick_ = nick;
+            }
+
+            const boost::optional<JID>& getJID() const {
+                return jid_;
+            }
+
+            void setJID(const JID& jid) {
+                jid_ = jid;
+            }
+
+            const boost::optional<std::string>& getSubmissionID() const {
+                return submissionId_;
+            }
+
+            void setSubmissionID(const std::string& submissionId) {
+                submissionId_ = submissionId;
+            }
+
+        private:
+            boost::optional<JID> jid_;
+            boost::optional<std::string> nick_;
+            boost::optional<std::string> submissionId_;
+    };
+}
diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp
index c5304a6..17fb478 100644
--- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp
+++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp
@@ -55,6 +55,7 @@
 #include <Swiften/Parser/PayloadParsers/MIXCreateParser.h>
 #include <Swiften/Parser/PayloadParsers/MIXDestroyParser.h>
 #include <Swiften/Parser/PayloadParsers/MIXJoinParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/MIXPayloadParserFactory.h>
 #include <Swiften/Parser/PayloadParsers/MIXUserPreferenceParser.h>
 #include <Swiften/Parser/PayloadParsers/MIXLeaveParser.h>
 #include <Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.h>
@@ -139,6 +140,7 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() {
     factories_.push_back(std::make_shared<GenericPayloadParserFactory<MIXDestroyParser> >("destroy", "urn:xmpp:mix:0"));
     factories_.push_back(std::make_shared<GenericPayloadParserFactory<MIXCreateParser> >("create", "urn:xmpp:mix:0"));
     factories_.push_back(std::make_shared<GenericPayloadParserFactory<MIXUserPreferenceParser> >("user-preference", "urn:xmpp:mix:0"));
+    factories_.push_back(std::make_shared<MIXPayloadParserFactory>());
     factories_.push_back(std::make_shared<GenericPayloadParserFactory<MIXLeaveParser> >("leave", "urn:xmpp:mix:0"));
     factories_.push_back(std::make_shared<MUCUserPayloadParserFactory>(this));
     factories_.push_back(std::make_shared<MUCOwnerPayloadParserFactory>(this));
diff --git a/Swiften/Parser/PayloadParsers/MIXPayloadParser.cpp b/Swiften/Parser/PayloadParsers/MIXPayloadParser.cpp
new file mode 100644
index 0000000..51ef584
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/MIXPayloadParser.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2017 Tarun Gupta
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <Swiften/Parser/PayloadParsers/MIXPayloadParser.h>
+
+namespace Swift {
+
+void MIXPayloadParser::handleTree(ParserElement::ref root) {
+    for (const auto& child : root->getAllChildren()) {
+        if (child->getName() == "nick" && child->getNamespace() == root->getNamespace()) {
+            getPayloadInternal()->setNick(child->getText());
+        } else if (child->getName() == "jid" && child->getNamespace() == root->getNamespace()) {
+            if (boost::optional<JID> jid = JID::parse(child->getText())) {
+                getPayloadInternal()->setJID(*jid);
+            }
+        } else if (child->getName() == "submission-id" && child->getNamespace() == root->getNamespace()) {
+            getPayloadInternal()->setSubmissionID(child->getText());
+        }
+    }
+}
+
+}
diff --git a/Swiften/Parser/PayloadParsers/MIXPayloadParser.h b/Swiften/Parser/PayloadParsers/MIXPayloadParser.h
new file mode 100644
index 0000000..0225b3b
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/MIXPayloadParser.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2017 Tarun Gupta
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/API.h>
+#include <Swiften/Base/Override.h>
+#include <Swiften/Elements/MIXPayload.h>
+#include <Swiften/Parser/GenericPayloadTreeParser.h>
+
+namespace Swift {
+    class SWIFTEN_API MIXPayloadParser : public GenericPayloadTreeParser<MIXPayload> {
+        public:
+            MIXPayloadParser() {}
+            virtual void handleTree(ParserElement::ref root) SWIFTEN_OVERRIDE;
+    };
+}
diff --git a/Swiften/Parser/PayloadParsers/MIXPayloadParserFactory.h b/Swiften/Parser/PayloadParsers/MIXPayloadParserFactory.h
new file mode 100644
index 0000000..066d2f0
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/MIXPayloadParserFactory.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017 Tarun Gupta
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/API.h>
+#include <Swiften/Parser/GenericPayloadParserFactory.h>
+#include <Swiften/Parser/PayloadParsers/MIXPayloadParser.h>
+
+namespace Swift {
+    class SWIFTEN_API MIXPayloadParserFactory : public PayloadParserFactory {
+        public:
+            MIXPayloadParserFactory() {
+            }
+
+            virtual bool canParse(const std::string& element, const std::string& ns, const AttributeMap&) const SWIFTEN_OVERRIDE {
+                return element == "mix" && ns == "urn:xmpp:mix:0";
+            }
+
+            virtual PayloadParser* createPayloadParser() SWIFTEN_OVERRIDE {
+                return new MIXPayloadParser();
+            }
+    };
+}
diff --git a/Swiften/Parser/PayloadParsers/UnitTest/MIXPayloadParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/MIXPayloadParserTest.cpp
new file mode 100644
index 0000000..920aca7
--- /dev/null
+++ b/Swiften/Parser/PayloadParsers/UnitTest/MIXPayloadParserTest.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017 Tarun Gupta
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <gtest/gtest.h>
+
+#include <Swiften/Elements/MIXPayload.h>
+#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h>
+
+using namespace Swift;
+
+TEST(MIXPayloadParserTest, WithNick) {
+    PayloadsParserTester parser;
+    ASSERT_TRUE(parser.parse(
+                "<mix xmlns=\"urn:xmpp:mix:0\"> <nick>thirdwitch</nick> </mix>"
+                ));
+
+    auto payload = parser.getPayload<MIXPayload>();
+    ASSERT_TRUE(payload);
+
+    ASSERT_TRUE(payload->getNick());
+    std::string nick = *payload->getNick();
+    ASSERT_EQ("thirdwitch", nick);
+
+    ASSERT_FALSE(payload->getJID());
+    ASSERT_FALSE(payload->getSubmissionID());
+}
+
+TEST(MIXPayloadParserTest, WithJID) {
+    PayloadsParserTester parser;
+    ASSERT_TRUE(parser.parse(
+                "<mix xmlns=\"urn:xmpp:mix:0\"> <jid>hecate@mix.shakespeare.example</jid> </mix>"
+                ));
+
+    auto payload = parser.getPayload<MIXPayload>();
+    ASSERT_TRUE(payload);
+
+    ASSERT_TRUE(payload->getJID());
+    JID jid = *payload->getJID();
+    ASSERT_EQ("hecate@mix.shakespeare.example", jid.toString());
+
+    ASSERT_FALSE(payload->getNick());
+    ASSERT_FALSE(payload->getSubmissionID());
+}
+
+TEST(MIXPayloadParserTest, WithAll) {
+    PayloadsParserTester parser;
+    ASSERT_TRUE(parser.parse(
+                "<mix xmlns=\"urn:xmpp:mix:0\">"
+                    "<nick>thirdwitch</nick>"
+                    "<jid>hecate@mix.shakespeare.example</jid>"
+                    "<submission-id>92vax143g</submission-id>"
+                "</mix>"
+                ));
+
+    auto payload = parser.getPayload<MIXPayload>();
+    ASSERT_TRUE(payload);
+
+    ASSERT_TRUE(payload->getNick());
+    std::string nick = *payload->getNick();
+    ASSERT_EQ("thirdwitch", nick);
+
+    ASSERT_TRUE(payload->getJID());
+    JID jid = *payload->getJID();
+    ASSERT_EQ("hecate@mix.shakespeare.example", jid.toString());
+
+    ASSERT_TRUE(payload->getSubmissionID());
+    std::string subID = *payload->getSubmissionID();
+    ASSERT_EQ("92vax143g", subID);
+}
+
+TEST(MIXPayloadParserTest, Empty) {
+    PayloadsParserTester parser;
+    ASSERT_TRUE(parser.parse(
+                "<mix xmlns=\"urn:xmpp:mix:0\"/>"
+                ));
+
+    auto payload = parser.getPayload<MIXPayload>();
+    ASSERT_TRUE(payload);
+    ASSERT_FALSE(payload->getNick());
+    ASSERT_FALSE(payload->getJID());
+    ASSERT_FALSE(payload->getSubmissionID());
+}
diff --git a/Swiften/Parser/SConscript b/Swiften/Parser/SConscript
index c7113df..20dc3f4 100644
--- a/Swiften/Parser/SConscript
+++ b/Swiften/Parser/SConscript
@@ -70,6 +70,7 @@ sources = [
         "PayloadParsers/MIXParticipantParser.cpp",
         "PayloadParsers/MIXDestroyParser.cpp",
         "PayloadParsers/MIXCreateParser.cpp",
+        "PayloadParsers/MIXPayloadParser.cpp",
         "PayloadParsers/MIXLeaveParser.cpp",
         "PayloadParsers/MIXJoinParser.cpp",
         "PayloadParsers/MIXSubscribeParser.cpp",
diff --git a/Swiften/SConscript b/Swiften/SConscript
index 36b1dd8..100f717 100644
--- a/Swiften/SConscript
+++ b/Swiften/SConscript
@@ -210,6 +210,7 @@ if env["SCONS_STAGE"] == "build" :
             "Serializer/PayloadSerializers/MIXParticipantSerializer.cpp",
             "Serializer/PayloadSerializers/MIXDestroySerializer.cpp",
             "Serializer/PayloadSerializers/MIXCreateSerializer.cpp",
+            "Serializer/PayloadSerializers/MIXPayloadSerializer.cpp",
             "Serializer/PayloadSerializers/MIXUserPreferenceSerializer.cpp",
             "Serializer/PayloadSerializers/MIXLeaveSerializer.cpp",
             "Serializer/PayloadSerializers/MIXJoinSerializer.cpp",
@@ -438,6 +439,7 @@ if env["SCONS_STAGE"] == "build" :
             File("Parser/PayloadParsers/UnitTest/InBandRegistrationPayloadParserTest.cpp"),
             File("Parser/PayloadParsers/UnitTest/JingleParserTest.cpp"),
             File("Parser/PayloadParsers/UnitTest/MIXParticipantParserTest.cpp"),
+            File("Parser/PayloadParsers/UnitTest/MIXPayloadParserTest.cpp"),
             File("Parser/PayloadParsers/UnitTest/MIXDestroyParserTest.cpp"),
             File("Parser/PayloadParsers/UnitTest/MIXLeaveParserTest.cpp"),
             File("Parser/PayloadParsers/UnitTest/MIXCreateParserTest.cpp"),
@@ -525,6 +527,7 @@ if env["SCONS_STAGE"] == "build" :
             File("Serializer/PayloadSerializers/UnitTest/MIXParticipantSerializerTest.cpp"),
             File("Serializer/PayloadSerializers/UnitTest/MIXDestroySerializerTest.cpp"),
             File("Serializer/PayloadSerializers/UnitTest/MIXCreateSerializerTest.cpp"),
+            File("Serializer/PayloadSerializers/UnitTest/MIXPayloadSerializerTest.cpp"),
             File("Serializer/PayloadSerializers/UnitTest/MIXUserPreferenceSerializerTest.cpp"),
             File("Serializer/PayloadSerializers/UnitTest/MIXLeaveSerializerTest.cpp"),
             File("Serializer/PayloadSerializers/UnitTest/JingleSerializersTest.cpp"),
diff --git a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp
index c0ee620..1a04435 100644
--- a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp
+++ b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp
@@ -49,6 +49,7 @@
 #include <Swiften/Serializer/PayloadSerializers/MIXDestroySerializer.h>
 #include <Swiften/Serializer/PayloadSerializers/MIXParticipantSerializer.h>
 #include <Swiften/Serializer/PayloadSerializers/MIXCreateSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/MIXPayloadSerializer.h>
 #include <Swiften/Serializer/PayloadSerializers/MIXUserPreferenceSerializer.h>
 #include <Swiften/Serializer/PayloadSerializers/MIXLeaveSerializer.h>
 #include <Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.h>
@@ -162,6 +163,7 @@ FullPayloadSerializerCollection::FullPayloadSerializerCollection() {
     serializers_.push_back(new ForwardedSerializer(this));
     serializers_.push_back(new MIXParticipantSerializer());
     serializers_.push_back(new MIXCreateSerializer());
+    serializers_.push_back(new MIXPayloadSerializer());
     serializers_.push_back(new MIXUserPreferenceSerializer());
     serializers_.push_back(new MIXLeaveSerializer());
     serializers_.push_back(new MIXJoinSerializer());
diff --git a/Swiften/Serializer/PayloadSerializers/MIXPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/MIXPayloadSerializer.cpp
new file mode 100644
index 0000000..843270a
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/MIXPayloadSerializer.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2017 Tarun Gupta
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <Swiften/Serializer/PayloadSerializers/MIXPayloadSerializer.h>
+
+#include <memory>
+
+#include <Swiften/Serializer/XML/XMLElement.h>
+#include <Swiften/Serializer/XML/XMLRawTextNode.h>
+#include <Swiften/Serializer/XML/XMLTextNode.h>
+
+namespace Swift {
+
+MIXPayloadSerializer::MIXPayloadSerializer() : GenericPayloadSerializer<MIXPayload>() {
+}
+
+std::string MIXPayloadSerializer::serializePayload(std::shared_ptr<MIXPayload> payload)  const {
+    XMLElement mixElement("mix", "urn:xmpp:mix:0");
+
+    if (payload->getNick()) {
+        std::shared_ptr<XMLElement> nickElement = std::make_shared<XMLElement>("nick");
+        nickElement->addNode(std::make_shared<XMLTextNode>(*payload->getNick()));
+        mixElement.addNode(nickElement);
+    }
+
+    if (payload->getJID()) {
+        std::shared_ptr<XMLElement> jidElement = std::make_shared<XMLElement>("jid");
+        jidElement->addNode(std::make_shared<XMLTextNode>(*payload->getJID()));
+        mixElement.addNode(jidElement);
+    }
+
+    if (payload->getSubmissionID()) {
+        std::shared_ptr<XMLElement> subIDElement = std::make_shared<XMLElement>("submission-id");
+        subIDElement->addNode(std::make_shared<XMLTextNode>(*payload->getSubmissionID()));
+        mixElement.addNode(subIDElement);
+    }
+
+    return mixElement.serialize();
+}
+
+}
diff --git a/Swiften/Serializer/PayloadSerializers/MIXPayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/MIXPayloadSerializer.h
new file mode 100644
index 0000000..3481ca8
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/MIXPayloadSerializer.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2017 Tarun Gupta
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/Base/API.h>
+#include <Swiften/Base/Override.h>
+#include <Swiften/Elements/MIXPayload.h>
+#include <Swiften/Serializer/GenericPayloadSerializer.h>
+
+namespace Swift {
+    class SWIFTEN_API MIXPayloadSerializer : public GenericPayloadSerializer<MIXPayload> {
+        public:
+            MIXPayloadSerializer();
+
+            virtual std::string serializePayload(std::shared_ptr<MIXPayload> payload) const SWIFTEN_OVERRIDE;
+    };
+}
diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/MIXPayloadSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/MIXPayloadSerializerTest.cpp
new file mode 100644
index 0000000..266b066
--- /dev/null
+++ b/Swiften/Serializer/PayloadSerializers/UnitTest/MIXPayloadSerializerTest.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017 Tarun Gupta
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <gtest/gtest.h>
+
+#include <Swiften/Serializer/PayloadSerializers/MIXPayloadSerializer.h>
+#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h>
+
+using namespace Swift;
+
+TEST(MIXPayloadSerializerTest, testSerializeEmpty) {
+    MIXPayloadSerializer testling;
+
+    auto mix = std::shared_ptr<MIXPayload>(new MIXPayload());
+
+    std::string expectedResult = "<mix xmlns=\"urn:xmpp:mix:0\"/>";
+    ASSERT_EQ(expectedResult, testling.serialize(mix));
+}
+
+TEST(MIXPayloadSerializerTest, testSerializeNick) {
+    MIXPayloadSerializer testling;
+
+    auto mix = std::shared_ptr<MIXPayload>(new MIXPayload());
+    mix->setNick("thirdwitch");
+
+    std::string expectedResult = "<mix xmlns=\"urn:xmpp:mix:0\">"
+                                    "<nick>thirdwitch</nick>"
+                                  "</mix>";
+    ASSERT_EQ(expectedResult, testling.serialize(mix));
+}
+
+TEST(MIXPayloadSerializerTest, testSerializeJID) {
+    MIXPayloadSerializer testling;
+
+    auto mix = std::shared_ptr<MIXPayload>(new MIXPayload());
+    mix->setJID(JID("hecate@mix.shakespeare.example"));
+
+    std::string expectedResult = "<mix xmlns=\"urn:xmpp:mix:0\">"
+                                    "<jid>hecate@mix.shakespeare.example</jid>"
+                                  "</mix>";
+    ASSERT_EQ(expectedResult, testling.serialize(mix));
+}
+
+TEST(MIXPayloadSerializerTest, testSerializeAll) {
+    MIXPayloadSerializer testling;
+
+    auto mix = std::shared_ptr<MIXPayload>(new MIXPayload());
+    mix->setNick("thirdwitch");
+    mix->setJID(JID("hecate@mix.shakespeare.example"));
+    mix->setSubmissionID("92vax143g");
+
+    std::string expectedResult = "<mix xmlns=\"urn:xmpp:mix:0\">"
+                      "<nick>thirdwitch</nick>"
+                      "<jid>hecate@mix.shakespeare.example</jid>"
+                      "<submission-id>92vax143g</submission-id>"
+                  "</mix>";
+    ASSERT_EQ(expectedResult, testling.serialize(mix));
+}
-- 
cgit v0.10.2-6-g49f6