/*
 * Copyright (c) 2011 Tobias Markmann
 * Licensed under the simplified BSD license.
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 */

#include <boost/shared_ptr.hpp>
#include <boost/smart_ptr/make_shared.hpp>

#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>

#include <Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.h>
#include <Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.h>
#include <Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.h>
#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h>
#include <Swiften/Serializer/PayloadSerializers/RTPPayloadTypeSerializer.h>
#include <Swiften/Serializer/PayloadSerializers/JingleRTPDescriptionSerializer.h>
#include <Swiften/Serializer/PayloadSerializers/JingleRawUDPTransportPayloadSerializer.h>
#include <Swiften/Elements/JingleFileTransferDescription.h>
#include <Swiften/Elements/StreamInitiationFileInfo.h>
#include <Swiften/Elements/JingleIBBTransportPayload.h>
#include <Swiften/Elements/JingleS5BTransportPayload.h>
#include <Swiften/Elements/JingleFileTransferHash.h>
#include <Swiften/Elements/JinglePayload.h>
#include <Swiften/Elements/JingleFileTransferReceived.h>
#include <Swiften/Elements/RTPPayloadType.h>
#include <Swiften/Elements/JingleRTPDescription.h>
#include <Swiften/Elements/JingleRawUDPTransportPayload.h>
#include <Swiften/Base/DateTime.h>

using namespace Swift;

class JingleSerializersTest : public CppUnit::TestFixture {
		CPPUNIT_TEST_SUITE(JingleSerializersTest);

		CPPUNIT_TEST(testSerialize_StreamInitiationFileInfo);
		CPPUNIT_TEST(testSerialize_StreamInitiationFileInfoRange);
		
		CPPUNIT_TEST(testSerialize_Xep0166_Example8);

		CPPUNIT_TEST(testSerialize_Xep0261_Example1);
		CPPUNIT_TEST(testSerialize_Xep0261_Example9);
		CPPUNIT_TEST(testSerialize_Xep0261_Example13);
		
		CPPUNIT_TEST(testSerialize_Xep0234_Example1);
		CPPUNIT_TEST(testSerialize_Xep0234_Example3);
		CPPUNIT_TEST(testSerialize_Xep0234_Example5);
		CPPUNIT_TEST(testSerialize_Xep0234_Example8);
		CPPUNIT_TEST(testSerialize_Xep0234_Example10);
		CPPUNIT_TEST(testSerialize_Xep0234_Example13);

		CPPUNIT_TEST(testSerialize_Xep0260_Example1);

		CPPUNIT_TEST(testSerialize_RTPPayloadType_Simple);
		CPPUNIT_TEST(testSerialize_RTPPayloadType_WithSub);

		CPPUNIT_TEST(testSerialize_Xep0167_Example1);
		CPPUNIT_TEST(testSerialize_Xep0167_Example48);

		CPPUNIT_TEST(testSerialize_RawUDPTransportPayload);

		CPPUNIT_TEST(testSerialize_Xep0177_Example3);

		CPPUNIT_TEST_SUITE_END();
		
		 boost::shared_ptr<JinglePayloadSerializer> createTestling() {
			 return boost::make_shared<JinglePayloadSerializer>(&collection);
		}

		
	public:
		void testSerialize_StreamInitiationFileInfo() {
			std::string expected =	"<file"
							" date=\"1969-07-21T02:56:15Z\""
							" hash=\"552da749930852c69ae5d2141d3766b1\""
							" name=\"test.txt\""
							" size=\"1022\""
							" xmlns=\"http://jabber.org/protocol/si/profile/file-transfer\">"
							"<desc>This is a test. If this were a real file...</desc>"
							"<range/>"
						"</file>";
			
			StreamInitiationFileInfo::ref fileInfo = boost::make_shared<StreamInitiationFileInfo>();
			fileInfo->setDate(stringToDateTime("1969-07-21T02:56:15Z"));
			fileInfo->setHash("552da749930852c69ae5d2141d3766b1");
			fileInfo->setSize(1022);
			fileInfo->setName("test.txt");
			fileInfo->setDescription("This is a test. If this were a real file...");
			fileInfo->setSupportsRangeRequests(true);
			
			boost::shared_ptr<StreamInitiationFileInfoSerializer> serializer = boost::make_shared<StreamInitiationFileInfoSerializer>();
			CPPUNIT_ASSERT_EQUAL(expected, serializer->serializePayload(fileInfo));
		}
		
		void testSerialize_StreamInitiationFileInfoRange() {
			std::string expected =	"<file hash=\"552da749930852c69ae5d2141d3766b1\""
							" xmlns=\"http://jabber.org/protocol/si/profile/file-transfer\">"
							"<range offset=\"270336\"/>"
						"</file>";
			
			StreamInitiationFileInfo::ref fileInfo = boost::make_shared<StreamInitiationFileInfo>();
			fileInfo->setHash("552da749930852c69ae5d2141d3766b1");
			fileInfo->setSupportsRangeRequests(true);
			fileInfo->setRangeOffset(270336);
			
			boost::shared_ptr<StreamInitiationFileInfoSerializer> serializer = boost::make_shared<StreamInitiationFileInfoSerializer>();
			CPPUNIT_ASSERT_EQUAL(expected, serializer->serializePayload(fileInfo));
		}
		
		// http://xmpp.org/extensions/xep-0166.html#example-8
		void testSerialize_Xep0166_Example8() {
			std::string expected =	
				"<jingle action=\"session-terminate\""
						" sid=\"a73sjjvkla37jfea\""
						" xmlns=\"urn:xmpp:jingle:1\">"
					"<reason>"
						"<success/>"
						"<text>Sorry, gotta go!</text>"
					"</reason>"
				"</jingle>";

			JinglePayload::ref payload = boost::make_shared<JinglePayload>();
			payload->setAction(JinglePayload::SessionTerminate);
			payload->setSessionID("a73sjjvkla37jfea");
			payload->setReason(JinglePayload::Reason(JinglePayload::Reason::Success, "Sorry, gotta go!"));

			CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload));
		}
		
		
		// IBB Transport Method Examples
		
		// http://xmpp.org/extensions/xep-0261.html#example-1
		void testSerialize_Xep0261_Example1() {
			std::string expected = 
				"<jingle action=\"session-initiate\""
					" initiator=\"romeo@montague.lit/orchard\""
					" sid=\"a73sjjvkla37jfea\""
					" xmlns=\"urn:xmpp:jingle:1\">"
					"<content creator=\"initiator\" name=\"ex\">"
						"<transport block-size=\"4096\""
							" sid=\"ch3d9s71\""
							" xmlns=\"urn:xmpp:jingle:transports:ibb:1\"/>"
					"</content>"
				"</jingle>";
			
			JinglePayload::ref payload = boost::make_shared<JinglePayload>();
			payload->setAction(JinglePayload::SessionInitiate);
			payload->setSessionID("a73sjjvkla37jfea");
			payload->setInitiator(JID("romeo@montague.lit/orchard"));
			
			JingleIBBTransportPayload::ref transport = boost::make_shared<JingleIBBTransportPayload>();
			transport->setBlockSize(4096);
			transport->setSessionID("ch3d9s71");
			
			JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>();
			content->setCreator(JingleContentPayload::InitiatorCreator);
			content->setName("ex");
			content->addTransport(transport);
			
			payload->addPayload(content);
			
			CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload));
		}
		
		// http://xmpp.org/extensions/xep-0261.html#example-9
		void testSerialize_Xep0261_Example9() {
			std::string expected =
				"<jingle action=\"transport-info\""
					" initiator=\"romeo@montague.lit/orchard\""
					" sid=\"a73sjjvkla37jfea\""
					" xmlns=\"urn:xmpp:jingle:1\">"
					"<content creator=\"initiator\" name=\"ex\">"
						"<transport block-size=\"2048\""
							" sid=\"bt8a71h6\""
							" xmlns=\"urn:xmpp:jingle:transports:ibb:1\"/>"
					"</content>"
				"</jingle>";
			
			JinglePayload::ref payload = boost::make_shared<JinglePayload>();
			payload->setAction(JinglePayload::TransportInfo);
			payload->setInitiator(JID("romeo@montague.lit/orchard"));
			payload->setSessionID("a73sjjvkla37jfea");
			
			JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>();
			content->setCreator(JingleContentPayload::InitiatorCreator);
			content->setName("ex");
			
			JingleIBBTransportPayload::ref transport = boost::make_shared<JingleIBBTransportPayload>();
			transport->setBlockSize(2048);
			transport->setSessionID("bt8a71h6");
			
			content->addTransport(transport);
			payload->addPayload(content);
			
			CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload));
		}
		
		// http://xmpp.org/extensions/xep-0261.html#example-13
		void testSerialize_Xep0261_Example13() {
			std::string expected =
				"<jingle action=\"session-terminate\""
					" initiator=\"romeo@montague.lit/orchard\""
					" sid=\"a73sjjvkla37jfea\""
					" xmlns=\"urn:xmpp:jingle:1\">"
					"<reason><success/></reason>"
				"</jingle>";
			
			JinglePayload::ref payload = boost::make_shared<JinglePayload>();
			payload->setAction(JinglePayload::SessionTerminate);
			payload->setInitiator(JID("romeo@montague.lit/orchard"));
			payload->setSessionID("a73sjjvkla37jfea");
			payload->setReason(JinglePayload::Reason(JinglePayload::Reason::Success));
			
			CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload));
		}
		
		// http://xmpp.org/extensions/xep-0234.html#example-1
		void testSerialize_Xep0234_Example1() {
			std::string expected =	"<description xmlns=\"urn:xmpp:jingle:apps:file-transfer:3\">"
							"<offer>"
								"<file"
									" date=\"1969-07-21T02:56:15Z\""
									" hash=\"552da749930852c69ae5d2141d3766b1\""
									" name=\"test.txt\""
									" size=\"1022\""
									" xmlns=\"http://jabber.org/protocol/si/profile/file-transfer\">"
									"<desc>This is a test. If this were a real file...</desc>"
									"<range/>"
								"</file>"
							"</offer>"
						"</description>";
			JingleFileTransferDescription::ref desc = boost::make_shared<JingleFileTransferDescription>();
			StreamInitiationFileInfo fileInfo;
			
			fileInfo.setDate(stringToDateTime("1969-07-21T02:56:15Z"));
			fileInfo.setHash("552da749930852c69ae5d2141d3766b1");
			fileInfo.setSize(1022);
			fileInfo.setName("test.txt");
			fileInfo.setDescription("This is a test. If this were a real file...");
			fileInfo.setSupportsRangeRequests(true);
			
			desc->addOffer(fileInfo);
			
			CPPUNIT_ASSERT_EQUAL(expected, boost::make_shared<JingleFileTransferDescriptionSerializer>()->serialize(desc));
		}
		
		// http://xmpp.org/extensions/xep-0234.html#example-3
		void testSerialize_Xep0234_Example3() {
			std::string expected =
				"<jingle action=\"session-accept\""
					" initiator=\"romeo@montague.lit/orchard\""
					" sid=\"851ba2\""
					" xmlns=\"urn:xmpp:jingle:1\">"
					"<content creator=\"initiator\" name=\"a-file-offer\">"
						"<description xmlns=\"urn:xmpp:jingle:apps:file-transfer:3\">"
							"<offer>"
								"<file"
									" date=\"1969-07-21T02:56:15Z\""
									" hash=\"552da749930852c69ae5d2141d3766b1\""
									" name=\"test.txt\""
									" size=\"1022\""
									" xmlns=\"http://jabber.org/protocol/si/profile/file-transfer\">"
									"<desc>This is a test. If this were a real file...</desc>"
									"<range/>"
								"</file>"
							"</offer>"
						"</description>"
						/*"<transport xmlns=\"urn:xmpp:jingle:transports:s5b:1\""
							" mode=\"tcp\""
							" sid=\"vj3hs98y\">"
							"<candidate cid=\"ht567dq\""
								" host=\"192.169.1.10\""
								" jid=\"juliet@capulet.lit/balcony\""
								" port=\"6539\""
								" priority=\"8257636\""
								" type=\"direct\"/>"
							"<candidate cid=\"hr65dqyd\""
								" host=\"134.102.201.180\""
								" jid=\"juliet@capulet.lit/balcony\""
								" port=\"16453\""
								" priority=\"7929856\""
								" type=\"assisted\"/>"
							"<candidate cid=\"grt654q2\""
								" host=\"2001:638:708:30c9:219:d1ff:fea4:a17d\""
								" jid=\"juliet@capulet.lit/balcony\""
								" port=\"6539\""
								" priority=\"8257606\""
								" type=\"direct\"/>"
						"</transport>"*/
					"</content>"
				"</jingle>";
			
			JinglePayload::ref payload = boost::make_shared<JinglePayload>();
			payload->setAction(JinglePayload::SessionAccept);
			payload->setInitiator(JID("romeo@montague.lit/orchard"));
			payload->setSessionID("851ba2");
			
			JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>();
			content->setCreator(JingleContentPayload::InitiatorCreator);
			content->setName("a-file-offer");
			
			JingleFileTransferDescription::ref description = boost::make_shared<JingleFileTransferDescription>();
			StreamInitiationFileInfo fileInfo;
			fileInfo.setName("test.txt");
			fileInfo.setSize(1022);
			fileInfo.setHash("552da749930852c69ae5d2141d3766b1");
			fileInfo.setDate(stringToDateTime("1969-07-21T02:56:15Z"));
			fileInfo.setDescription("This is a test. If this were a real file...");
			fileInfo.setSupportsRangeRequests(true);
			
			description->addOffer(fileInfo);
			content->addDescription(description);
			payload->addPayload(content);
			
			CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload));
		}
		
		// http://xmpp.org/extensions/xep-0234.html#example-5
		void testSerialize_Xep0234_Example5() {
			std::string expected = 
				"<jingle"
					" action=\"transport-info\""
					" initiator=\"romeo@montague.lit/orchard\""
					" sid=\"a73sjjvkla37jfea\""
					" xmlns=\"urn:xmpp:jingle:1\">"
					"<content creator=\"initiator\" name=\"ex\"/>"
						/*"<transport"
							" sid=\"vj3hs98y\""
							" xmlns=\"urn:xmpp:jingle:transports:s5b:1\">"
							"<candidate-used cid=\"hr65dqyd\"/>"
						"</transport>"*/
					//"</content>"
				"</jingle>";

			JinglePayload::ref payload = boost::make_shared<JinglePayload>();
			payload->setAction(JinglePayload::TransportInfo);
			payload->setInitiator(JID("romeo@montague.lit/orchard"));
			payload->setSessionID("a73sjjvkla37jfea");
			
			JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>();
			content->setCreator(JingleContentPayload::InitiatorCreator);
			content->setName("ex");
			payload->addPayload(content);
			
			CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload));
		}
		
		// http://xmpp.org/extensions/xep-0234.html#example-8
		void testSerialize_Xep0234_Example8() {
			std::string expected = 
				"<jingle"
					" action=\"session-info\""
					" initiator=\"romeo@montague.lit/orchard\""
					" sid=\"a73sjjvkla37jfea\""
					" xmlns=\"urn:xmpp:jingle:1\">"
					"<checksum xmlns=\"urn:xmpp:jingle:apps:file-transfer:3\">"
						"<file>"
							"<hashes xmlns=\"urn:xmpp:hashes:0\">"
								"<hash algo=\"sha-1\">552da749930852c69ae5d2141d3766b1</hash>"
							"</hashes>"
						"</file>"
					"</checksum>"
				"</jingle>";
			
			JinglePayload::ref payload = boost::make_shared<JinglePayload>();
			payload->setAction(JinglePayload::SessionInfo);
			payload->setInitiator(JID("romeo@montague.lit/orchard"));
			payload->setSessionID("a73sjjvkla37jfea");
			
			JingleFileTransferHash::ref hash = boost::make_shared<JingleFileTransferHash>();
			hash->setHash("sha-1", "552da749930852c69ae5d2141d3766b1");
			
			payload->addPayload(hash);
			
			CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload));
		}
		
		// http://xmpp.org/extensions/xep-0234.html#example-10
		void testSerialize_Xep0234_Example10() {
			std::string expected = 
				"<jingle"
					" action=\"session-initiate\""
					" initiator=\"romeo@montague.lit/orchard\""
					" sid=\"uj3b2\""
					" xmlns=\"urn:xmpp:jingle:1\">"
					"<content creator=\"initiator\" name=\"a-file-request\">"
						"<description"
							" xmlns=\"urn:xmpp:jingle:apps:file-transfer:3\">"
							"<request>"
								"<file"
									" hash=\"552da749930852c69ae5d2141d3766b1\""
									" xmlns=\"http://jabber.org/protocol/si/profile/file-transfer\">"
									"<range offset=\"270336\"/>"
								"</file>"
							"</request>"
						"</description>"
						/*"<transport"
							" mode=\"tcp\""
							" sid=\"xig361fj\""
							" xmlns=\"urn:xmpp:jingle:transports:s5b:1\">"
							"<candidate"
								" cid=\"ht567dq\""
								" host=\"192.169.1.10\""
								" jid=\"juliet@capulet.lit/balcony\""
								" port=\"6539\""
								" priority=\"8257636\""
								" type=\"direct\"/>"
							"<candidate"
								" cid=\"hr65dqyd\""
								" host=\"134.102.201.180\""
								" jid=\"juliet@capulet.lit/balcony\""
								" port=\"16453\""
								" priority=\"7929856\""
								" type=\"assisted\"/>"
							"<candidate"
								" cid=\"grt654q2\""
								" host=\"2001:638:708:30c9:219:d1ff:fea4:a17d\""
								" jid=\"juliet@capulet.lit/balcony\""
								" port=\"6539\""
								" priority=\"8257606\""
								" type=\"direct\"/>"
						"</transport>"*/
					"</content>"
				"</jingle>";
			
			JinglePayload::ref payload = boost::make_shared<JinglePayload>();
			payload->setAction(JinglePayload::SessionInitiate);
			payload->setInitiator(JID("romeo@montague.lit/orchard"));
			payload->setSessionID("uj3b2");
			
			StreamInitiationFileInfo fileInfo;
			fileInfo.setHash("552da749930852c69ae5d2141d3766b1");
			fileInfo.setRangeOffset(270336);
			
			JingleFileTransferDescription::ref desc = boost::make_shared<JingleFileTransferDescription>();
			desc->addRequest(fileInfo);
			
			JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>();
			content->setCreator(JingleContentPayload::InitiatorCreator);
			content->setName("a-file-request");
			content->addDescription(desc);
			
			payload->addPayload(content);
			
			CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload));
		}

		// http://xmpp.org/extensions/xep-0234.html#example-10
		void testSerialize_Xep0234_Example13() {
			std::string expected =
				"<jingle"
					" action=\"session-info\""
					" initiator=\"romeo@montague.lit/orchard\""
					" sid=\"a73sjjvkla37jfea\""
					" xmlns=\"urn:xmpp:jingle:1\">"
					"<received xmlns=\"urn:xmpp:jingle:apps:file-transfer:3\">"
						"<file"
							" hash=\"a749930852c69ae5d2141d3766b1552d\""
							" xmlns=\"http://jabber.org/protocol/si/profile/file-transfer\"/>"
					"</received>"
				"</jingle>";

			JinglePayload::ref payload = boost::make_shared<JinglePayload>();
			payload->setAction(JinglePayload::SessionInfo);
			payload->setInitiator(JID("romeo@montague.lit/orchard"));
			payload->setSessionID("a73sjjvkla37jfea");

			JingleFileTransferReceived::ref received = boost::make_shared<JingleFileTransferReceived>();

			StreamInitiationFileInfo fileInfo;
			fileInfo.setHash("a749930852c69ae5d2141d3766b1552d");

			received->setFileInfo(fileInfo);
			payload->addPayload(received);

			CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload));
		}

		// http://xmpp.org/extensions/xep-0260.html#example-1
		void testSerialize_Xep0260_Example1() {
			std::string expected =
				"<jingle"
					" action=\"session-initiate\""
					" initiator=\"romeo@montague.lit/orchard\""
					" sid=\"a73sjjvkla37jfea\""
					" xmlns=\"urn:xmpp:jingle:1\">"
					"<content creator=\"initiator\" name=\"ex\">"
						"<transport"
							" mode=\"tcp\""
							" sid=\"vj3hs98y\""
							" xmlns=\"urn:xmpp:jingle:transports:s5b:1\">"
							"<candidate cid=\"hft54dqy\""
								" host=\"192.168.4.1\""
								" jid=\"romeo@montague.lit/orchard\""
								" port=\"5086\""
								" priority=\"8257636\""
								" type=\"direct\"/>"
							"<candidate cid=\"hutr46fe\""
								" host=\"24.24.24.1\""
								" jid=\"romeo@montague.lit/orchard\""
								" port=\"5087\""
								" priority=\"8258636\""
								" type=\"direct\"/>"
						"</transport>"
					"</content>"
				"</jingle>";

			JinglePayload::ref payload = boost::make_shared<JinglePayload>();
			payload->setAction(JinglePayload::SessionInitiate);
			payload->setInitiator(JID("romeo@montague.lit/orchard"));
			payload->setSessionID("a73sjjvkla37jfea");

			JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>();
			content->setCreator(JingleContentPayload::InitiatorCreator);
			content->setName("ex");

			JingleS5BTransportPayload::ref transport = boost::make_shared<JingleS5BTransportPayload>();
			transport->setMode(JingleS5BTransportPayload::TCPMode);
			transport->setSessionID("vj3hs98y");

			JingleS5BTransportPayload::Candidate candidate1;
			candidate1.cid = "hft54dqy";
			candidate1.hostPort = HostAddressPort(HostAddress("192.168.4.1"), 5086);
			candidate1.jid = JID("romeo@montague.lit/orchard");
			candidate1.priority = 8257636;
			candidate1.type = JingleS5BTransportPayload::Candidate::DirectType;
			transport->addCandidate(candidate1);

			JingleS5BTransportPayload::Candidate candidate2;
			candidate2.cid = "hutr46fe";
			candidate2.hostPort = HostAddressPort(HostAddress("24.24.24.1"), 5087);
			candidate2.jid = JID("romeo@montague.lit/orchard");
			candidate2.priority = 8258636;
			candidate2.type = JingleS5BTransportPayload::Candidate::DirectType;
			transport->addCandidate(candidate2);

			content->addTransport(transport);

			payload->addPayload(content);

			CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload));
		}

		void testSerialize_RTPPayloadType_Simple() {
			std::string expected =	"<payload-type clockrate=\"16000\" id=\"96\" name=\"speex\"/>";
			
			RTPPayloadType::ref payloadType = boost::make_shared<RTPPayloadType>(96);
			payloadType->setName("speex");
			payloadType->setClockrate(16000);
			
			boost::shared_ptr<RTPPayloadTypeSerializer> serializer = boost::make_shared<RTPPayloadTypeSerializer>();
			CPPUNIT_ASSERT_EQUAL(expected, serializer->serializePayload(payloadType));
		}
			
		void testSerialize_RTPPayloadType_WithSub() {
			std::string expected =	"<payload-type clockrate=\"90000\" id=\"98\" name=\"theora\">"
										"<parameter name=\"configuration\" value=\"somebase16string\"/>"
										"<parameter name=\"delivery-method\" value=\"inline\"/>"
										"<parameter name=\"height\" value=\"600\"/>"
										"<parameter name=\"sampling\" value=\"YCbCr-4:2:2\"/>"
										"<parameter name=\"width\" value=\"800\"/>"
									"</payload-type>";
			
			RTPPayloadType::ref payloadType = boost::make_shared<RTPPayloadType>(98);
			payloadType->setName("theora");
			payloadType->setClockrate(90000);
			payloadType->addParameter("height", "600");
			payloadType->addParameter("width", "800");
			payloadType->addParameter("delivery-method", "inline");
			payloadType->addParameter("configuration", "somebase16string");
			payloadType->addParameter("sampling", "YCbCr-4:2:2");
			
			boost::shared_ptr<RTPPayloadTypeSerializer> serializer = boost::make_shared<RTPPayloadTypeSerializer>();
			CPPUNIT_ASSERT_EQUAL(expected, serializer->serializePayload(payloadType));
		}

		// http://xmpp.org/extensions/xep-0167.html#example-1
		void testSerialize_Xep0167_Example1() {
			std::string expected =
				"<jingle action=\"session-initiate\""
						" initiator=\"romeo@montague.lit/orchard\""
						" sid=\"a73sjjvkla37jfea\""
						" xmlns=\"urn:xmpp:jingle:1\">"
					"<content creator=\"initiator\" name=\"voice\">"
						"<description media=\"audio\" xmlns=\"urn:xmpp:jingle:apps:rtp:1\">"
							"<payload-type clockrate=\"16000\" id=\"96\" name=\"speex\"/>"
							"<payload-type clockrate=\"8000\" id=\"97\" name=\"speex\"/>"
							"<payload-type id=\"18\" name=\"G729\"/>"
							"<payload-type id=\"0\" name=\"PCMU\"/>"
							"<payload-type channels=\"2\" clockrate=\"16000\" id=\"103\" name=\"L16\"/>"
							"<payload-type clockrate=\"8000\" id=\"98\" name=\"x-ISAC\"/>"
						"</description>"
						//"<transport [...] >"
					"</content>"
				"</jingle>";

			JinglePayload::ref payload = boost::make_shared<JinglePayload>();
			payload->setAction(JinglePayload::SessionInitiate);
			payload->setInitiator(JID("romeo@montague.lit/orchard"));
			payload->setSessionID("a73sjjvkla37jfea");

			JingleRTPDescription::ref desc = boost::make_shared<JingleRTPDescription>(JingleRTPDescription::Audio);
			desc->addPayloadType(RTPPayloadType(96, "speex", 16000));
			desc->addPayloadType(RTPPayloadType(97, "speex", 8000));
			desc->addPayloadType(RTPPayloadType(18, "G729"));
			desc->addPayloadType(RTPPayloadType(0, "PCMU"));
			desc->addPayloadType(RTPPayloadType(103, "L16", 16000, 2));
			desc->addPayloadType(RTPPayloadType(98, "x-ISAC", 8000));

			JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>();
			content->setCreator(JingleContentPayload::InitiatorCreator);
			content->setName("voice");
			content->addDescription(desc);

			payload->addPayload(content);

			CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload));
		}

		// http://xmpp.org/extensions/xep-0167.html#example-48
		void testSerialize_Xep0167_Example48() {
			std::string expected =
				"<jingle action=\"content-accept\""
						" initiator=\"romeo@montague.lit/orchard\""
						" sid=\"a73sjjvkla37jfea\""
						" xmlns=\"urn:xmpp:jingle:1\">"
					"<content creator=\"initiator\" name=\"webcam\">"
						"<description media=\"video\" xmlns=\"urn:xmpp:jingle:apps:rtp:1\">"
							"<payload-type clockrate=\"90000\" id=\"98\" name=\"theora\">"
								"<parameter name=\"configuration\" value=\"somebase16string\"/>"
								"<parameter name=\"delivery-method\" value=\"inline\"/>"
								"<parameter name=\"height\" value=\"600\"/>"
								"<parameter name=\"sampling\" value=\"YCbCr-4:2:2\"/>"
								"<parameter name=\"width\" value=\"800\"/>"
							"</payload-type>"
							"<bandwidth type=\"AS\">128</bandwidth>"
						"</description>"
						//"<transport xmlns=\"urn:xmpp:jingle:transports:ice-udp:0\"/>"
					"</content>"
				"</jingle>";

			JinglePayload::ref payload = boost::make_shared<JinglePayload>();
			payload->setAction(JinglePayload::ContentAccept);
			payload->setInitiator(JID("romeo@montague.lit/orchard"));
			payload->setSessionID("a73sjjvkla37jfea");

			JingleRTPDescription::ref desc = boost::make_shared<JingleRTPDescription>(JingleRTPDescription::Video);
			RTPPayloadType payloadType(98, "theora", 90000);
			payloadType.addParameter("configuration", "somebase16string");
			payloadType.addParameter("delivery-method", "inline");
			payloadType.addParameter("height", "600");
			payloadType.addParameter("sampling", "YCbCr-4:2:2");
			payloadType.addParameter("width", "800");
			desc->addPayloadType(payloadType);
			desc->setBandwidth("AS", "128");

			JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>();
			content->setCreator(JingleContentPayload::InitiatorCreator);
			content->setName("webcam");
			content->addDescription(desc);

			payload->addPayload(content);

			CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload));
		}

		void testSerialize_RawUDPTransportPayload() {
			std::string expected =
				"<transport xmlns=\"urn:xmpp:jingle:transports:raw-udp:1\">"
					"<candidate component=\"1\""
						" generation=\"0\""
						" id=\"a9j3mnbtu1\""
						" ip=\"10.1.1.104\""
						" port=\"13540\""
						" type=\"srflx\"/>"
				"</transport>";

			JingleRawUDPTransportPayload::ref transport = boost::make_shared<JingleRawUDPTransportPayload>();

			JingleRawUDPTransportPayload::Candidate candidate;
			candidate.component = 1;
			candidate.generation = 0;
			candidate.cid = "a9j3mnbtu1";
			candidate.hostAddressPort = HostAddressPort(HostAddress("10.1.1.104"), 13540);
			candidate.type = JingleRawUDPTransportPayload::Candidate::ServerReflected;
			transport->addCandidate(candidate);

			boost::shared_ptr<JingleRawUDPTransportPayloadSerializer> serializer = boost::make_shared<JingleRawUDPTransportPayloadSerializer>();
			CPPUNIT_ASSERT_EQUAL(expected, serializer->serialize(transport));
		}

		// http://xmpp.org/extensions/xep-0177.html#example-3
		void testSerialize_Xep0177_Example3() {
			std::string expected =
				"<jingle action=\"session-accept\""
						" initiator=\"romeo@montague.lit/orchard\""
						" responder=\"juliet@capulet.lit/balcony\""
						" sid=\"a73sjjvkla37jfea\""
						" xmlns=\"urn:xmpp:jingle:1\">"
					"<content creator=\"initiator\" name=\"voice\">"
						"<description media=\"audio\" xmlns=\"urn:xmpp:jingle:apps:rtp:1\">"
							"<payload-type id=\"18\" name=\"G729\"/>"
						"</description>"
						"<transport xmlns=\"urn:xmpp:jingle:transports:raw-udp:1\">"
							"<candidate component=\"1\""
									" generation=\"0\""
									" id=\"z7sdjb01hf\""
									" ip=\"208.68.163.214\""
									" port=\"9876\"/>"
							"<candidate component=\"2\""
									" generation=\"0\""
									" id=\"hg92lsn10b\""
									" ip=\"208.68.163.214\""
									" port=\"9877\"/>"
						"</transport>"
					"</content>"
				"</jingle>";

			JinglePayload::ref payload = boost::make_shared<JinglePayload>();
			payload->setAction(JinglePayload::SessionAccept);
			payload->setInitiator(JID("romeo@montague.lit/orchard"));
			payload->setResponder(JID("juliet@capulet.lit/balcony"));
			payload->setSessionID("a73sjjvkla37jfea");

			JingleRTPDescription::ref desc = boost::make_shared<JingleRTPDescription>(JingleRTPDescription::Audio);
			RTPPayloadType payloadType(18, "G729");
			desc->addPayloadType(payloadType);

			JingleRawUDPTransportPayload::ref transport = boost::make_shared<JingleRawUDPTransportPayload>();

			JingleRawUDPTransportPayload::Candidate candidate1;
			candidate1.component = 1;
			candidate1.generation = 0;
			candidate1.cid = "z7sdjb01hf";
			candidate1.hostAddressPort = HostAddressPort(HostAddress("208.68.163.214"), 9876);
			transport->addCandidate(candidate1);

			JingleRawUDPTransportPayload::Candidate candidate2;
			candidate2.component = 2;
			candidate2.generation = 0;
			candidate2.cid = "hg92lsn10b";
			candidate2.hostAddressPort = HostAddressPort(HostAddress("208.68.163.214"), 9877);
			transport->addCandidate(candidate2);

			JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>();
			content->setCreator(JingleContentPayload::InitiatorCreator);
			content->setName("voice");
			content->addDescription(desc);
			content->addTransport(transport);

			payload->addPayload(content);

			CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload));
		}

	private:
		FullPayloadSerializerCollection collection;
};

CPPUNIT_TEST_SUITE_REGISTRATION(JingleSerializersTest);