/* * Copyright (C) 2008-2011 The QXmpp developers * * Authors: * Jeremy Lainé * Manjeet Dahiya * * Source: * http://code.google.com/p/qxmpp * * This file is a part of QXmpp library. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * */ #include #include #include #include #include #include #include "QXmppArchiveIq.h" #include "QXmppBindIq.h" #include "QXmppClient.h" #include "QXmppIncomingClient.h" #include "QXmppJingleIq.h" #include "QXmppMessage.h" #include "QXmppNonSASLAuth.h" #include "QXmppPresence.h" #include "QXmppPubSubIq.h" #include "QXmppRpcIq.h" #include "QXmppSaslAuth.h" #include "QXmppSessionIq.h" #include "QXmppServer.h" #include "QXmppStreamFeatures.h" #include "QXmppStun.h" #include "QXmppUtils.h" #include "QXmppVCardIq.h" #include "QXmppVersionIq.h" #include "QXmppGlobal.h" #include "QXmppEntityTimeIq.h" #include "tests.h" QString getImageType(const QByteArray &contents); void TestUtils::testCrc32() { quint32 crc = generateCrc32(QByteArray()); QCOMPARE(crc, 0u); crc = generateCrc32(QByteArray("Hi There")); QCOMPARE(crc, 0xDB143BBEu); } void TestUtils::testDigestMd5() { // empty QMap empty = QXmppSaslDigestMd5::parseMessage(QByteArray()); QCOMPARE(empty.size(), 0); QCOMPARE(QXmppSaslDigestMd5::serializeMessage(empty), QByteArray()); // non-empty const QByteArray bytes("number=12345,quoted_plain=\"quoted string\",quoted_quote=\"quoted\\\\slash\\\"quote\",string=string"); QMap map = QXmppSaslDigestMd5::parseMessage(bytes); QCOMPARE(map.size(), 4); QCOMPARE(map["number"], QByteArray("12345")); QCOMPARE(map["quoted_plain"], QByteArray("quoted string")); QCOMPARE(map["quoted_quote"], QByteArray("quoted\\slash\"quote")); QCOMPARE(map["string"], QByteArray("string")); QCOMPARE(QXmppSaslDigestMd5::serializeMessage(map), bytes); } void TestUtils::testHmac() { QByteArray hmac = generateHmacMd5(QByteArray(16, 0x0b), QByteArray("Hi There")); QCOMPARE(hmac, QByteArray::fromHex("9294727a3638bb1c13f48ef8158bfc9d")); hmac = generateHmacMd5(QByteArray("Jefe"), QByteArray("what do ya want for nothing?")); QCOMPARE(hmac, QByteArray::fromHex("750c783e6ab0b503eaa86e310a5db738")); hmac = generateHmacMd5(QByteArray(16, 0xaa), QByteArray(50, 0xdd)); QCOMPARE(hmac, QByteArray::fromHex("56be34521d144c88dbb8c733f0e8b3f6")); } void TestUtils::testJid() { QCOMPARE(jidToBareJid("foo@example.com/resource"), QLatin1String("foo@example.com")); QCOMPARE(jidToBareJid("foo@example.com"), QLatin1String("foo@example.com")); QCOMPARE(jidToBareJid("example.com"), QLatin1String("example.com")); QCOMPARE(jidToBareJid(QString()), QString()); QCOMPARE(jidToDomain("foo@example.com/resource"), QLatin1String("example.com")); QCOMPARE(jidToDomain("foo@example.com"), QLatin1String("example.com")); QCOMPARE(jidToDomain("example.com"), QLatin1String("example.com")); QCOMPARE(jidToDomain(QString()), QString()); QCOMPARE(jidToResource("foo@example.com/resource"), QLatin1String("resource")); QCOMPARE(jidToResource("foo@example.com"), QString()); QCOMPARE(jidToResource("example.com"), QString()); QCOMPARE(jidToResource(QString()), QString()); QCOMPARE(jidToUser("foo@example.com/resource"), QLatin1String("foo")); QCOMPARE(jidToUser("foo@example.com"), QLatin1String("foo")); QCOMPARE(jidToUser("example.com"), QString()); QCOMPARE(jidToUser(QString()), QString()); } static void testMimeType(const QString &fileName, const QString fileType) { // load file from resources QFile file(":/" + fileName); QCOMPARE(file.open(QIODevice::ReadOnly), true); QCOMPARE(getImageType(file.readAll()), fileType); file.close(); } void TestUtils::testMime() { testMimeType("test.bmp", "image/bmp"); testMimeType("test.gif", "image/gif"); testMimeType("test.jpg", "image/jpeg"); testMimeType("test.mng", "video/x-mng"); testMimeType("test.png", "image/png"); testMimeType("test.svg", "image/svg+xml"); testMimeType("test.xpm", "image/x-xpm"); } void TestUtils::testLibVersion() { QCOMPARE(QXmppVersion(), QString("0.3.0")); } void TestUtils::testTimezoneOffset() { // parsing QCOMPARE(timezoneOffsetFromString("Z"), 0); QCOMPARE(timezoneOffsetFromString("+00:00"), 0); QCOMPARE(timezoneOffsetFromString("-00:00"), 0); QCOMPARE(timezoneOffsetFromString("+01:30"), 5400); QCOMPARE(timezoneOffsetFromString("-01:30"), -5400); // serialization QCOMPARE(timezoneOffsetToString(0), QLatin1String("Z")); QCOMPARE(timezoneOffsetToString(5400), QLatin1String("+01:30")); QCOMPARE(timezoneOffsetToString(-5400), QLatin1String("-01:30")); } template static void parsePacket(T &packet, const QByteArray &xml) { //qDebug() << "parsing" << xml; QDomDocument doc; QCOMPARE(doc.setContent(xml, true), true); QDomElement element = doc.documentElement(); packet.parse(element); } template static void serializePacket(T &packet, const QByteArray &xml) { QBuffer buffer; buffer.open(QIODevice::ReadWrite); QXmlStreamWriter writer(&buffer); packet.toXml(&writer); qDebug() << "expect " << xml; qDebug() << "writing" << buffer.data(); QCOMPARE(buffer.data(), xml); } void TestPackets::testArchiveList() { const QByteArray xml( "" "" "" "30" "" "" ""); QXmppArchiveListIq iq; parsePacket(iq, xml); QCOMPARE(iq.type(), QXmppIq::Get); QCOMPARE(iq.id(), QLatin1String("list_1")); QCOMPARE(iq.with(), QLatin1String("juliet@capulet.com")); QCOMPARE(iq.start(), QDateTime(QDate(1469, 7, 21), QTime(2, 0, 0), Qt::UTC)); QCOMPARE(iq.end(), QDateTime(QDate(1479, 7, 21), QTime(4, 0, 0), Qt::UTC)); QCOMPARE(iq.max(), 30); serializePacket(iq, xml); } void TestPackets::testArchiveChat() { const QByteArray xml( "" "" "Art thou not Romeo, and a Montague?" "Neither, fair saint, if either thee dislike." "" ""); QXmppArchiveChatIq iq; parsePacket(iq, xml); QCOMPARE(iq.type(), QXmppIq::Result); QCOMPARE(iq.id(), QLatin1String("chat_1")); QCOMPARE(iq.chat().with(), QLatin1String("juliet@capulet.com")); QCOMPARE(iq.chat().messages().size(), 2); QCOMPARE(iq.chat().messages()[0].isReceived(), true); QCOMPARE(iq.chat().messages()[0].body(), QLatin1String("Art thou not Romeo, and a Montague?")); QCOMPARE(iq.chat().messages()[0].date(), QDateTime(QDate(1469, 7, 21), QTime(2, 56, 15), Qt::UTC)); QCOMPARE(iq.chat().messages()[1].isReceived(), false); QCOMPARE(iq.chat().messages()[1].date(), QDateTime(QDate(1469, 7, 21), QTime(2, 56, 26), Qt::UTC)); QCOMPARE(iq.chat().messages()[1].body(), QLatin1String("Neither, fair saint, if either thee dislike.")); serializePacket(iq, xml); } void TestPackets::testArchiveRetrieve() { const QByteArray xml( "" "" "" "30" "" "" ""); QXmppArchiveRetrieveIq iq; parsePacket(iq, xml); QCOMPARE(iq.type(), QXmppIq::Get); QCOMPARE(iq.id(), QLatin1String("retrieve_1")); QCOMPARE(iq.with(), QLatin1String("juliet@capulet.com")); QCOMPARE(iq.start(), QDateTime(QDate(1469, 7, 21), QTime(2, 0, 0), Qt::UTC)); QCOMPARE(iq.max(), 30); serializePacket(iq, xml); } void TestPackets::testBindNoResource() { const QByteArray xml( "" "" ""); QXmppBindIq bind; parsePacket(bind, xml); QCOMPARE(bind.type(), QXmppIq::Set); QCOMPARE(bind.id(), QString("bind_1")); QCOMPARE(bind.jid(), QString()); QCOMPARE(bind.resource(), QString()); serializePacket(bind, xml); } void TestPackets::testBindResource() { const QByteArray xml( "" "" "someresource" "" ""); QXmppBindIq bind; parsePacket(bind, xml); QCOMPARE(bind.type(), QXmppIq::Set); QCOMPARE(bind.id(), QString("bind_2")); QCOMPARE(bind.jid(), QString()); QCOMPARE(bind.resource(), QString("someresource")); serializePacket(bind, xml); } void TestPackets::testBindResult() { const QByteArray xml( "" "" "somenode@example.com/someresource" "" ""); QXmppBindIq bind; parsePacket(bind, xml); QCOMPARE(bind.type(), QXmppIq::Result); QCOMPARE(bind.id(), QString("bind_2")); QCOMPARE(bind.jid(), QString("somenode@example.com/someresource")); QCOMPARE(bind.resource(), QString()); serializePacket(bind, xml); } void TestPackets::testMessage() { const QByteArray xml( ""); QXmppMessage message; parsePacket(message, xml); QCOMPARE(message.to(), QString("foo@example.com/QXmpp")); QCOMPARE(message.from(), QString("bar@example.com/QXmpp")); serializePacket(message, xml); } void TestPackets::testMessageFull() { const QByteArray xml( "" "test subject" "test body & stuff" "test thread" "" ""); QXmppMessage message; parsePacket(message, xml); QCOMPARE(message.to(), QString("foo@example.com/QXmpp")); QCOMPARE(message.from(), QString("bar@example.com/QXmpp")); QCOMPARE(message.type(), QXmppMessage::Normal); QCOMPARE(message.body(), QString("test body & stuff")); QCOMPARE(message.subject(), QString("test subject")); QCOMPARE(message.thread(), QString("test thread")); QCOMPARE(message.state(), QXmppMessage::Composing); serializePacket(message, xml); } void TestPackets::testMessageDelay() { const QByteArray xml( "" "" ""); QXmppMessage message; parsePacket(message, xml); QCOMPARE(message.stamp(), QDateTime(QDate(2010, 06, 29), QTime(8, 23, 6), Qt::UTC)); serializePacket(message, xml); } void TestPackets::testMessageLegacyDelay() { const QByteArray xml( "" "" ""); QXmppMessage message; parsePacket(message, xml); QCOMPARE(message.stamp(), QDateTime(QDate(2010, 06, 29), QTime(8, 23, 6), Qt::UTC)); serializePacket(message, xml); } void TestPackets::testNonSaslAuth() { // Client Requests Authentication Fields from Server const QByteArray xml1( "" "" ""); QXmppNonSASLAuthIq iq1; parsePacket(iq1, xml1); serializePacket(iq1, xml1); // Client Provides Required Information (Plaintext) const QByteArray xml3( "" "" "bill" "Calli0pe" "globe" "" ""); QXmppNonSASLAuthIq iq3; parsePacket(iq3, xml3); QCOMPARE(iq3.username(), QLatin1String("bill")); QCOMPARE(iq3.digest(), QByteArray()); QCOMPARE(iq3.password(), QLatin1String("Calli0pe")); QCOMPARE(iq3.resource(), QLatin1String("globe")); serializePacket(iq3, xml3); // Client Provides Required Information (Plaintext) const QByteArray xml4( "" "" "bill" "48fc78be9ec8f86d8ce1c39c320c97c21d62334d" "globe" "" ""); QXmppNonSASLAuthIq iq4; parsePacket(iq4, xml4); QCOMPARE(iq4.username(), QLatin1String("bill")); QCOMPARE(iq4.digest(), QByteArray("\x48\xfc\x78\xbe\x9e\xc8\xf8\x6d\x8c\xe1\xc3\x9c\x32\x0c\x97\xc2\x1d\x62\x33\x4d")); QCOMPARE(iq4.password(), QString()); QCOMPARE(iq4.resource(), QLatin1String("globe")); serializePacket(iq4, xml4); } void TestPackets::testPresence() { const QByteArray xml( "" ""); QXmppPresence presence; parsePacket(presence, xml); QCOMPARE(presence.to(), QString("foo@example.com/QXmpp")); QCOMPARE(presence.from(), QString("bar@example.com/QXmpp")); QCOMPARE(presence.photoHash(), QByteArray("")); QCOMPARE(presence.vCardUpdateType(), QXmppPresence::VCardUpdateNotReady); serializePacket(presence, xml); } void TestPackets::testPresenceFull() { const QByteArray xml( "" "away" "In a meeting" "5" ""); QXmppPresence presence; parsePacket(presence, xml); QCOMPARE(presence.to(), QString("foo@example.com/QXmpp")); QCOMPARE(presence.from(), QString("bar@example.com/QXmpp")); QCOMPARE(presence.status().type(), QXmppPresence::Status::Away); QCOMPARE(presence.status().statusText(), QString("In a meeting")); QCOMPARE(presence.status().priority(), 5); QCOMPARE(presence.vCardUpdateType(), QXmppPresence::VCardUpdateNone); serializePacket(presence, xml); } void TestPackets::testPresenceWithVCardUpdate() { const QByteArray xml( "" "away" "In a meeting" "5" "" "73b908bc" "" ""); QXmppPresence presence; parsePacket(presence, xml); QCOMPARE(presence.to(), QString("foo@example.com/QXmpp")); QCOMPARE(presence.from(), QString("bar@example.com/QXmpp")); QCOMPARE(presence.status().type(), QXmppPresence::Status::Away); QCOMPARE(presence.status().statusText(), QString("In a meeting")); QCOMPARE(presence.status().priority(), 5); QCOMPARE(presence.photoHash(), QByteArray::fromHex("73b908bc")); QCOMPARE(presence.vCardUpdateType(), QXmppPresence::VCardUpdateValidPhoto); serializePacket(presence, xml); } void TestPackets::testPresenceWithCapability() { const QByteArray xml( "" "away" "In a meeting" "5" "" "73b908bc" "" "" ""); QXmppPresence presence; parsePacket(presence, xml); QCOMPARE(presence.to(), QString("foo@example.com/QXmpp")); QCOMPARE(presence.from(), QString("bar@example.com/QXmpp")); QCOMPARE(presence.status().type(), QXmppPresence::Status::Away); QCOMPARE(presence.status().statusText(), QString("In a meeting")); QCOMPARE(presence.status().priority(), 5); QCOMPARE(presence.photoHash(), QByteArray::fromHex("73b908bc")); QCOMPARE(presence.vCardUpdateType(), QXmppPresence::VCardUpdateValidPhoto); QCOMPARE(presence.capabilityHash(), QString("sha-1")); QCOMPARE(presence.capabilityNode(), QString("http://code.google.com/p/qxmpp")); QCOMPARE(presence.capabilityVer(), QByteArray::fromBase64("QgayPKawpkPSDYmwT/WM94uAlu0=")); serializePacket(presence, xml); } void TestPackets::testSession() { const QByteArray xml( "" "" ""); QXmppSessionIq session; parsePacket(session, xml); QCOMPARE(session.id(), QString("session_1")); QCOMPARE(session.to(), QString("example.com")); QCOMPARE(session.type(), QXmppIq::Set); serializePacket(session, xml); } void TestPackets::testStreamFeatures() { const QByteArray xml(""); QXmppStreamFeatures features; parsePacket(features, xml); QCOMPARE(features.bindMode(), QXmppStreamFeatures::Disabled); QCOMPARE(features.sessionMode(), QXmppStreamFeatures::Disabled); QCOMPARE(features.nonSaslAuthMode(), QXmppStreamFeatures::Disabled); QCOMPARE(features.tlsMode(), QXmppStreamFeatures::Disabled); QCOMPARE(features.authMechanisms(), QList()); QCOMPARE(features.compressionMethods(), QList()); serializePacket(features, xml); const QByteArray xml2("" "" "" "" "" "zlib" "PLAIN" ""); QXmppStreamFeatures features2; parsePacket(features2, xml2); QCOMPARE(features2.bindMode(), QXmppStreamFeatures::Enabled); QCOMPARE(features2.sessionMode(), QXmppStreamFeatures::Enabled); QCOMPARE(features2.nonSaslAuthMode(), QXmppStreamFeatures::Enabled); QCOMPARE(features2.tlsMode(), QXmppStreamFeatures::Enabled); QCOMPARE(features2.authMechanisms(), QList() << QXmppConfiguration::SASLPlain); QCOMPARE(features2.compressionMethods(), QList() << QXmppConfiguration::ZlibCompression); serializePacket(features2, xml2); } void TestPackets::testVCard() { const QByteArray xml( "" "" "1983-09-14" "foo.bar@example.com" "Foo Bar!" "FooBar" "FooWizBaz" "" "image/png" "" "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAIAAABLbSncAAAAAXNSR0IArs4c6QAAAAlwSFlzAAA" "UIgAAFCIBjw1HyAAAAAd0SU1FB9oIHQInNvuJovgAAAAiSURBVAjXY2TQ+s/AwMDAwPD/GiMDlP" "WfgYGBiQEHGJwSAK2BBQ1f3uvpAAAAAElFTkSuQmCC" "" "" "" ""); QXmppVCardIq vcard; parsePacket(vcard, xml); QCOMPARE(vcard.birthday(), QDate(1983, 9, 14)); QCOMPARE(vcard.email(), QLatin1String("foo.bar@example.com")); QCOMPARE(vcard.nickName(), QLatin1String("FooBar")); QCOMPARE(vcard.fullName(), QLatin1String("Foo Bar!")); QCOMPARE(vcard.firstName(), QLatin1String("Foo")); QCOMPARE(vcard.middleName(), QLatin1String("Baz")); QCOMPARE(vcard.lastName(), QLatin1String("Wiz")); QCOMPARE(vcard.photo(), QByteArray::fromBase64( "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAIAAABLbSncAAAAAXNSR0IArs4c6QAAAAlwSFlzAAA" "UIgAAFCIBjw1HyAAAAAd0SU1FB9oIHQInNvuJovgAAAAiSURBVAjXY2TQ+s/AwMDAwPD/GiMDlP" "WfgYGBiQEHGJwSAK2BBQ1f3uvpAAAAAElFTkSuQmCC")); QCOMPARE(vcard.photoType(), QLatin1String("image/png")); serializePacket(vcard, xml); } void TestPackets::testVersionGet() { const QByteArray xmlGet( "" ""); QXmppVersionIq verIqGet; parsePacket(verIqGet, xmlGet); QCOMPARE(verIqGet.id(), QLatin1String("version_1")); QCOMPARE(verIqGet.to(), QLatin1String("juliet@capulet.com/balcony")); QCOMPARE(verIqGet.from(), QLatin1String("romeo@montague.net/orchard")); QCOMPARE(verIqGet.type(), QXmppIq::Get); serializePacket(verIqGet, xmlGet); } void TestPackets::testVersionResult() { const QByteArray xmlResult( "" "" "qxmpp" "Windows-XP" "0.2.0" ""); QXmppVersionIq verIqResult; parsePacket(verIqResult, xmlResult); QCOMPARE(verIqResult.id(), QLatin1String("version_1")); QCOMPARE(verIqResult.to(), QLatin1String("romeo@montague.net/orchard")); QCOMPARE(verIqResult.from(), QLatin1String("juliet@capulet.com/balcony")); QCOMPARE(verIqResult.type(), QXmppIq::Result); QCOMPARE(verIqResult.name(), QString("qxmpp")); QCOMPARE(verIqResult.version(), QString("0.2.0")); QCOMPARE(verIqResult.os(), QString("Windows-XP")); serializePacket(verIqResult, xmlResult); } void TestPackets::testEntityTimeGet() { const QByteArray xml("" ""); QXmppEntityTimeIq entityTime; parsePacket(entityTime, xml); QCOMPARE(entityTime.id(), QLatin1String("time_1")); QCOMPARE(entityTime.to(), QLatin1String("juliet@capulet.com/balcony")); QCOMPARE(entityTime.from(), QLatin1String("romeo@montague.net/orchard")); QCOMPARE(entityTime.type(), QXmppIq::Get); serializePacket(entityTime, xml); } void TestPackets::testEntityTimeResult() { const QByteArray xml( "" "" ""); QXmppEntityTimeIq entityTime; parsePacket(entityTime, xml); QCOMPARE(entityTime.id(), QLatin1String("time_1")); QCOMPARE(entityTime.from(), QLatin1String("juliet@capulet.com/balcony")); QCOMPARE(entityTime.to(), QLatin1String("romeo@montague.net/orchard")); QCOMPARE(entityTime.type(), QXmppIq::Result); QCOMPARE(entityTime.tzo(), -21600); QCOMPARE(entityTime.utc(), QDateTime(QDate(2006, 12, 19), QTime(17, 58, 35), Qt::UTC)); serializePacket(entityTime, xml); } void TestJingle::testSession() { const QByteArray xml( "" "" "" "" "" "" "" ""); QXmppJingleIq session; parsePacket(session, xml); QCOMPARE(session.action(), QXmppJingleIq::SessionInitiate); QCOMPARE(session.initiator(), QLatin1String("romeo@montague.lit/orchard")); QCOMPARE(session.sid(), QLatin1String("a73sjjvkla37jfea")); QCOMPARE(session.content().creator(), QLatin1String("initiator")); QCOMPARE(session.content().name(), QLatin1String("this-is-a-stub")); QCOMPARE(session.reason().text(), QString()); QCOMPARE(session.reason().type(), QXmppJingleIq::Reason::None); serializePacket(session, xml); } void TestJingle::testTerminate() { const QByteArray xml( "" "" "" "" "" "" ""); QXmppJingleIq session; parsePacket(session, xml); QCOMPARE(session.action(), QXmppJingleIq::SessionTerminate); QCOMPARE(session.initiator(), QString()); QCOMPARE(session.sid(), QLatin1String("a73sjjvkla37jfea")); QCOMPARE(session.reason().text(), QString()); QCOMPARE(session.reason().type(), QXmppJingleIq::Reason::Success); serializePacket(session, xml); } void TestJingle::testPayloadType() { const QByteArray xml(""); QXmppJinglePayloadType payload; parsePacket(payload, xml); QCOMPARE(payload.id(), static_cast(103)); QCOMPARE(payload.name(), QLatin1String("L16")); QCOMPARE(payload.channels(), static_cast(2)); QCOMPARE(payload.clockrate(), 16000u); serializePacket(payload, xml); } void TestJingle::testRinging() { const QByteArray xml( "" "" "" "" ""); QXmppJingleIq iq; parsePacket(iq, xml); QCOMPARE(iq.ringing(), true); serializePacket(iq, xml); } void TestPubSub::testItems() { const QByteArray xml( "" "" "" "" ""); QXmppPubSubIq iq; parsePacket(iq, xml); QCOMPARE(iq.id(), QLatin1String("items1")); QCOMPARE(iq.to(), QLatin1String("pubsub.shakespeare.lit")); QCOMPARE(iq.from(), QLatin1String("francisco@denmark.lit/barracks")); QCOMPARE(iq.type(), QXmppIq::Get); QCOMPARE(iq.queryType(), QXmppPubSubIq::ItemsQuery); QCOMPARE(iq.queryJid(), QString()); QCOMPARE(iq.queryNode(), QLatin1String("storage:bookmarks")); serializePacket(iq, xml); } void TestPubSub::testItemsResponse() { const QByteArray xml( "" "" "" "" "" "" "JC" "" "" "" "" "" ""); QXmppPubSubIq iq; parsePacket(iq, xml); QCOMPARE(iq.id(), QLatin1String("items1")); QCOMPARE(iq.to(), QLatin1String("francisco@denmark.lit/barracks")); QCOMPARE(iq.from(), QLatin1String("pubsub.shakespeare.lit")); QCOMPARE(iq.type(), QXmppIq::Result); QCOMPARE(iq.queryType(), QXmppPubSubIq::ItemsQuery); QCOMPARE(iq.queryJid(), QString()); QCOMPARE(iq.queryNode(), QLatin1String("storage:bookmarks")); serializePacket(iq, xml); } void TestPubSub::testPublish() { const QByteArray xml( "" "" "" "" "" "" "JC" "" "" "" "" "" ""); QXmppPubSubIq iq; parsePacket(iq, xml); QCOMPARE(iq.id(), QLatin1String("items1")); QCOMPARE(iq.to(), QLatin1String("pubsub.shakespeare.lit")); QCOMPARE(iq.from(), QLatin1String("francisco@denmark.lit/barracks")); QCOMPARE(iq.type(), QXmppIq::Result); QCOMPARE(iq.queryType(), QXmppPubSubIq::PublishQuery); QCOMPARE(iq.queryJid(), QString()); QCOMPARE(iq.queryNode(), QLatin1String("storage:bookmarks")); serializePacket(iq, xml); } void TestPubSub::testSubscribe() { const QByteArray xml( "" "" "" "" ""); QXmppPubSubIq iq; parsePacket(iq, xml); QCOMPARE(iq.id(), QLatin1String("sub1")); QCOMPARE(iq.to(), QLatin1String("pubsub.shakespeare.lit")); QCOMPARE(iq.from(), QLatin1String("francisco@denmark.lit/barracks")); QCOMPARE(iq.type(), QXmppIq::Set); QCOMPARE(iq.queryType(), QXmppPubSubIq::SubscribeQuery); QCOMPARE(iq.queryJid(), QLatin1String("francisco@denmark.lit")); QCOMPARE(iq.queryNode(), QLatin1String("princely_musings")); serializePacket(iq, xml); } void TestPubSub::testSubscription() { const QByteArray xml( "" "" "" "" ""); QXmppPubSubIq iq; parsePacket(iq, xml); QCOMPARE(iq.id(), QLatin1String("sub1")); QCOMPARE(iq.to(), QLatin1String("francisco@denmark.lit/barracks")); QCOMPARE(iq.from(), QLatin1String("pubsub.shakespeare.lit")); QCOMPARE(iq.type(), QXmppIq::Result); QCOMPARE(iq.queryType(), QXmppPubSubIq::SubscriptionQuery); QCOMPARE(iq.queryJid(), QLatin1String("francisco@denmark.lit")); QCOMPARE(iq.queryNode(), QLatin1String("princely_musings")); QCOMPARE(iq.subscriptionId(), QLatin1String("ba49252aaa4f5d320c24d3766f0bdcade78c78d3")); serializePacket(iq, xml); } void TestPubSub::testSubscriptions() { const QByteArray xml( "" "" "" "" ""); QXmppPubSubIq iq; parsePacket(iq, xml); QCOMPARE(iq.id(), QLatin1String("subscriptions1")); QCOMPARE(iq.to(), QLatin1String("pubsub.shakespeare.lit")); QCOMPARE(iq.from(), QLatin1String("francisco@denmark.lit/barracks")); QCOMPARE(iq.type(), QXmppIq::Get); QCOMPARE(iq.queryType(), QXmppPubSubIq::SubscriptionsQuery); QCOMPARE(iq.queryJid(), QString()); QCOMPARE(iq.queryNode(), QString()); serializePacket(iq, xml); } class TestPasswordChecker : public QXmppPasswordChecker { public: TestPasswordChecker(const QString &username, const QString &password) : m_getPassword(true), m_username(username), m_password(password) { }; /// Retrieves the password for the given username. bool getPassword(const QString &username, const QString &domain, QString &password) { Q_UNUSED(domain); if (username == m_username) { password = m_password; return true; } else { return false; } }; void setGetPassword(bool getPassword) { m_getPassword = getPassword; } /// Returns true as we implemented getPassword(). bool hasGetPassword() const { return m_getPassword; }; private: bool m_getPassword; QString m_username; QString m_password; }; void TestServer::testConnect() { const QString testDomain("localhost"); const QString testPassword("testpwd"); const QString testUser("testuser"); const QHostAddress testHost(QHostAddress::LocalHost); const quint16 testPort = 12345; QXmppLogger logger; logger.setLoggingType(QXmppLogger::StdoutLogging); // prepare server TestPasswordChecker passwordChecker(testUser, testPassword); QXmppServer server; server.setDomain(testDomain); server.setLogger(&logger); server.setPasswordChecker(&passwordChecker); server.listenForClients(testHost, testPort); // prepare client QXmppClient client; client.setLogger(&logger); QEventLoop loop; connect(&client, SIGNAL(connected()), &loop, SLOT(quit())); connect(&client, SIGNAL(disconnected()), &loop, SLOT(quit())); QXmppConfiguration config; config.setDomain(testDomain); config.setHost(testHost.toString()); config.setUser(testUser); config.setPassword(testPassword); config.setPort(testPort); client.connectToServer(config); loop.exec(); QCOMPARE(client.isConnected(), true); } void TestStun::testFingerprint() { // without fingerprint QXmppStunMessage msg; msg.setType(0x0001); QCOMPARE(msg.encode(QByteArray(), false), QByteArray("\x00\x01\x00\x00\x21\x12\xA4\x42\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 20)); // with fingerprint QCOMPARE(msg.encode(QByteArray(), true), QByteArray("\x00\x01\x00\x08\x21\x12\xA4\x42\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x28\x00\x04\xB2\xAA\xF9\xF6", 28)); } void TestStun::testIntegrity() { QXmppStunMessage msg; msg.setType(0x0001); QCOMPARE(msg.encode(QByteArray("somesecret"), false), QByteArray("\x00\x01\x00\x18\x21\x12\xA4\x42\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x14\x96\x4B\x40\xD1\x84\x67\x6A\xFD\xB5\xE0\x7C\xC5\x1F\xFB\xBD\xA2\x61\xAF\xB1\x26", 44)); } void TestStun::testIPv4Address() { // encode QXmppStunMessage msg; msg.setType(0x0001); msg.mappedHost = QHostAddress("127.0.0.1"); msg.mappedPort = 12345; QByteArray packet = msg.encode(QByteArray(), false); QCOMPARE(packet, QByteArray("\x00\x01\x00\x0C\x21\x12\xA4\x42\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x08\x00\x01\x30\x39\x7F\x00\x00\x01", 32)); // decode QXmppStunMessage msg2; msg2.decode(packet); QCOMPARE(msg2.mappedHost, QHostAddress("127.0.0.1")); QCOMPARE(msg2.mappedPort, quint16(12345)); } void TestStun::testIPv6Address() { // encode QXmppStunMessage msg; msg.setType(0x0001); msg.mappedHost = QHostAddress("::1"); msg.mappedPort = 12345; const QByteArray packet = msg.encode(QByteArray(), false); QCOMPARE(packet, QByteArray("\x00\x01\x00\x18\x21\x12\xA4\x42\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x14\x00\x02\x30\x39\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 44)); // decode QXmppStunMessage msg2; msg2.decode(packet); QCOMPARE(msg2.mappedHost, QHostAddress("::1")); QCOMPARE(msg2.mappedPort, quint16(12345)); } void TestStun::testXorIPv4Address() { // encode QXmppStunMessage msg; msg.setType(0x0001); msg.xorMappedHost = QHostAddress("127.0.0.1"); msg.xorMappedPort = 12345; QByteArray packet = msg.encode(QByteArray(), false); QCOMPARE(packet, QByteArray("\x00\x01\x00\x0C\x21\x12\xA4\x42\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x08\x00\x01\x11\x2B\x5E\x12\xA4\x43", 32)); // decode QXmppStunMessage msg2; msg2.decode(packet); QCOMPARE(msg2.xorMappedHost, QHostAddress("127.0.0.1")); QCOMPARE(msg2.xorMappedPort, quint16(12345)); } void TestStun::testXorIPv6Address() { // encode QXmppStunMessage msg; msg.setType(0x0001); msg.xorMappedHost = QHostAddress("::1"); msg.xorMappedPort = 12345; const QByteArray packet = msg.encode(QByteArray(), false); QCOMPARE(packet, QByteArray("\x00\x01\x00\x18\x21\x12\xA4\x42\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x14\x00\x02\x11\x2B\x21\x12\xA4\x42\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 44)); // decode QXmppStunMessage msg2; msg2.decode(packet); QCOMPARE(msg2.xorMappedHost, QHostAddress("::1")); QCOMPARE(msg2.xorMappedPort, quint16(12345)); } static void checkVariant(const QVariant &value, const QByteArray &xml) { // serialise QBuffer buffer; buffer.open(QIODevice::ReadWrite); QXmlStreamWriter writer(&buffer); XMLRPC::marshall(&writer, value); qDebug() << "expect " << xml; qDebug() << "writing" << buffer.data(); QCOMPARE(buffer.data(), xml); // parse QDomDocument doc; QCOMPARE(doc.setContent(xml, true), true); QDomElement element = doc.documentElement(); QStringList errors; QVariant test = XMLRPC::demarshall(element, errors); if (!errors.isEmpty()) qDebug() << errors; QCOMPARE(errors, QStringList()); QCOMPARE(test, value); } void TestXmlRpc::testBase64() { checkVariant(QByteArray("\0\1\2\3", 4), QByteArray("AAECAw==")); } void TestXmlRpc::testBool() { checkVariant(false, QByteArray("0")); checkVariant(true, QByteArray("1")); } void TestXmlRpc::testDateTime() { checkVariant(QDateTime(QDate(1998, 7, 17), QTime(14, 8, 55)), QByteArray("1998-07-17T14:08:55")); } void TestXmlRpc::testDouble() { checkVariant(double(-12.214), QByteArray("-12.214")); } void TestXmlRpc::testInt() { checkVariant(int(-12), QByteArray("-12")); } void TestXmlRpc::testNil() { checkVariant(QVariant(), QByteArray("")); } void TestXmlRpc::testString() { checkVariant(QString("hello world"), QByteArray("hello world")); } void TestXmlRpc::testArray() { checkVariant(QVariantList() << QString("hello world") << double(-12.214), QByteArray("" "hello world" "-12.214" "")); } void TestXmlRpc::testStruct() { QMap map; map["bar"] = QString("hello world"); map["foo"] = double(-12.214); checkVariant(map, QByteArray("" "" "bar" "hello world" "" "" "foo" "-12.214" "" "")); } void TestXmlRpc::testInvoke() { const QByteArray xml( "" "" "" "examples.getStateName" "" "" "6" "" "" "" "" ""); QXmppRpcInvokeIq iq; parsePacket(iq, xml); QCOMPARE(iq.method(), QLatin1String("examples.getStateName")); QCOMPARE(iq.arguments(), QVariantList() << int(6)); serializePacket(iq, xml); } void TestXmlRpc::testResponse() { const QByteArray xml( "" "" "" "" "" "Colorado" "" "" "" "" ""); QXmppRpcResponseIq iq; parsePacket(iq, xml); QCOMPARE(iq.faultCode(), 0); QCOMPARE(iq.faultString(), QString()); QCOMPARE(iq.values(), QVariantList() << QString("Colorado")); serializePacket(iq, xml); } void TestXmlRpc::testResponseFault() { const QByteArray xml( "" "" "" "" "" "" "" "faultCode" "404" "" "" "faultString" "Not found" "" "" "" "" "" "" ""); QXmppRpcResponseIq iq; parsePacket(iq, xml); QCOMPARE(iq.faultCode(), 404); QCOMPARE(iq.faultString(), QLatin1String("Not found")); QCOMPARE(iq.values(), QVariantList()); serializePacket(iq, xml); } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); // run tests int errors = 0; TestUtils testUtils; errors += QTest::qExec(&testUtils); TestPackets testPackets; errors += QTest::qExec(&testPackets); TestJingle testJingle; errors += QTest::qExec(&testJingle); TestPubSub testPubSub; errors += QTest::qExec(&testPubSub); TestServer testServer; errors += QTest::qExec(&testServer); TestStun testStun; errors += QTest::qExec(&testStun); TestXmlRpc testXmlRpc; errors += QTest::qExec(&testXmlRpc); if (errors) { qWarning() << "Total failed tests:" << errors; return EXIT_FAILURE; } return EXIT_SUCCESS; };