-
Notifications
You must be signed in to change notification settings - Fork 196
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add unit test for AccountMigrationManager
- Loading branch information
Showing
2 changed files
with
344 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
343 changes: 343 additions & 0 deletions
343
tests/qxmppaccountmigrationmanager/tst_qxmppaccountmigrationmanager.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,343 @@ | ||
// SPDX-FileCopyrightText: 2023 Filipe Azevedo <pasnox@gmail.com> | ||
// | ||
// SPDX-License-Identifier: LGPL-2.1-or-later | ||
|
||
#include "QXmppAccountMigrationManager.h" | ||
#include "QXmppClient.h" | ||
#include "QXmppRosterManager.h" | ||
#include "QXmppUtils_p.h" | ||
#include "QXmppVCardIq.h" | ||
#include "QXmppVCardManager.h" | ||
|
||
#include "TestClient.h" | ||
#include "util.h" | ||
|
||
using Manager = QXmppAccountMigrationManager; | ||
using namespace QXmpp; | ||
using namespace QXmpp::Private; | ||
|
||
bool operator==(const QXmppRosterIq::Item &left, const QXmppRosterIq::Item &right) | ||
{ | ||
return left.bareJid() == right.bareJid() && left.groups() == right.groups() && left.name() == right.name() && left.subscriptionStatus() == right.subscriptionStatus() && left.subscriptionType() == right.subscriptionType() && left.isApproved() == right.isApproved() && left.isMixChannel() == right.isMixChannel() && left.mixParticipantId() == right.mixParticipantId(); | ||
} | ||
|
||
bool operator==(const QXmppRosterIq &left, const QXmppRosterIq &right) | ||
{ | ||
return left.version() == right.version() && left.items() == right.items() && | ||
left.mixAnnotate() == right.mixAnnotate(); | ||
} | ||
|
||
static QXmppRosterIq::Item newRosterItem(const QString &bareJid, const QString &name, const QSet<QString> &groups = {}) | ||
{ | ||
QXmppRosterIq::Item item; | ||
item.setBareJid(bareJid); | ||
item.setName(name); | ||
item.setGroups(groups); | ||
item.setSubscriptionType(QXmppRosterIq::Item::NotSet); | ||
return item; | ||
} | ||
|
||
static QXmppRosterIq newRoster(TestClient *client, int version, const std::optional<QString> &id, const std::optional<QXmppIq::Type> &type = {}) | ||
{ | ||
QXmppRosterIq roster; | ||
roster.setId(id.value_or(QString())); | ||
roster.setType(type.value_or(QXmppIq::Result)); | ||
|
||
if (roster.type() == QXmppIq::Get) { | ||
roster.setFrom(client->configuration().jid()); | ||
roster.setMixAnnotate(true); | ||
} | ||
|
||
if (roster.type() == QXmppIq::Result || roster.type() == QXmppIq::Set) { | ||
switch (version) { | ||
case 0: | ||
roster.addItem(newRosterItem(QStringLiteral("1@bare.com"), QStringLiteral("1 Bare"), { QStringLiteral("all") })); | ||
roster.addItem(newRosterItem(QStringLiteral("2@bare.com"), QStringLiteral("2 Bare"), { QStringLiteral("all") })); | ||
roster.addItem(newRosterItem(QStringLiteral("3@bare.com"), QStringLiteral("3 Bare"), { QStringLiteral("all") })); | ||
break; | ||
case 1: | ||
roster.addItem(newRosterItem(QStringLiteral("4@gamer.com"), QStringLiteral("4 Gamer"), { QStringLiteral("gamers") })); | ||
roster.addItem(newRosterItem(QStringLiteral("5@gamer.com"), QStringLiteral("5 Gamer"), { QStringLiteral("gamers") })); | ||
roster.addItem(newRosterItem(QStringLiteral("6@gamer.com"), QStringLiteral("6 Gamer"), { QStringLiteral("gamers") })); | ||
break; | ||
default: | ||
Q_UNREACHABLE(); | ||
} | ||
} | ||
|
||
return roster; | ||
} | ||
|
||
static QXmppVCardIq newClientVCard(TestClient *client, int version, const std::optional<QString> &id, const std::optional<QXmppIq::Type> &type = {}) | ||
{ | ||
Q_UNUSED(client) | ||
|
||
QXmppVCardIq vcard; | ||
vcard.setId(id.has_value() ? *id : QString()); | ||
vcard.setType(type.has_value() ? *type : QXmppIq::Result); | ||
|
||
if (vcard.type() == QXmppIq::Get) { | ||
} | ||
|
||
if (vcard.type() == QXmppIq::Result || vcard.type() == QXmppIq::Set) { | ||
switch (version) { | ||
case 0: | ||
vcard.setFirstName(QStringLiteral("Nox")); | ||
vcard.setLastName(QStringLiteral("PasNox")); | ||
vcard.setNickName(QStringLiteral("It is me PasNox")); | ||
break; | ||
case 1: | ||
vcard.setFirstName(QStringLiteral("Nox")); | ||
vcard.setLastName(QStringLiteral("Bookri")); | ||
vcard.setNickName(QStringLiteral("It is me Bookri")); | ||
break; | ||
default: | ||
Q_UNREACHABLE(); | ||
} | ||
} | ||
|
||
return vcard; | ||
} | ||
|
||
static std::unique_ptr<TestClient> newClient(bool withManagers) | ||
{ | ||
auto client = std::make_unique<TestClient>(); | ||
|
||
client->addNewExtension<QXmppAccountMigrationManager>(); | ||
client->configuration().setJid("pasnox@xmpp.example"); | ||
|
||
if (withManagers) { | ||
client->addNewExtension<QXmppVCardManager>(); | ||
client->addNewExtension<QXmppRosterManager>(client.get()); | ||
} | ||
|
||
return client; | ||
} | ||
|
||
class tst_QXmppAccountMigrationManager : public QObject | ||
{ | ||
Q_OBJECT | ||
|
||
private: | ||
Q_SLOT void testImportExport(); | ||
Q_SLOT void realImportExport(); | ||
Q_SLOT void serialization(); | ||
}; | ||
|
||
struct DataExtension { | ||
QString data; | ||
}; | ||
|
||
static auto parseDataExtension(const QDomElement &el) | ||
{ | ||
return Manager::Result<DataExtension>(DataExtension { el.text() }); | ||
} | ||
|
||
static auto serializeDataExtension(const DataExtension &ext, QXmlStreamWriter &w) | ||
{ | ||
w.writeStartElement("extension"); | ||
w.writeDefaultNamespace("org.qxmpp.tests"); | ||
w.writeCharacters(ext.data); | ||
w.writeEndElement(); | ||
} | ||
|
||
void tst_QXmppAccountMigrationManager::testImportExport() | ||
{ | ||
|
||
QXmppExportData::registerExtension<DataExtension, parseDataExtension, serializeDataExtension>(u"extension", u"org.qxmpp.tests"); | ||
|
||
auto client = newClient(false); | ||
auto *manager = client->findExtension<QXmppAccountMigrationManager>(); | ||
Q_ASSERT(manager); | ||
std::optional<DataExtension> currentState; | ||
|
||
manager->registerExportData<DataExtension>( | ||
[&](const DataExtension &data) { | ||
currentState = data; | ||
return makeReadyTask<Manager::Result<>>(Success()); | ||
}, | ||
[&]() { | ||
if (currentState) { | ||
return makeReadyTask<Manager::Result<DataExtension>>(*currentState); | ||
} | ||
return makeReadyTask<Manager::Result<DataExtension>>(QXmppError { "No data.", {} }); | ||
}); | ||
|
||
auto importTask = manager->importData(QXmppExportData {}); | ||
expectFutureVariant<Success>(importTask); | ||
|
||
// currently no data in 'currentState': expect error | ||
auto exportTask = manager->exportData(); | ||
expectFutureVariant<QXmppError>(exportTask); | ||
|
||
// set data and expect export to work | ||
currentState = { "Hello this is a test." }; | ||
exportTask = manager->exportData(); | ||
auto exportData = expectFutureVariant<QXmppExportData>(exportTask); | ||
|
||
// reset state and import data again | ||
currentState.reset(); | ||
importTask = manager->importData(exportData); | ||
QVERIFY(currentState); | ||
QCOMPARE(currentState->data, "Hello this is a test."); | ||
|
||
manager->unregisterExportData<DataExtension>(); | ||
|
||
// exporting/importing works without extensions | ||
// and import data with unknown extensions works | ||
exportTask = manager->exportData(); | ||
importTask = manager->importData(exportData); | ||
expectFutureVariant<QXmppExportData>(exportTask); | ||
expectFutureVariant<Success>(importTask); | ||
} | ||
|
||
void tst_QXmppAccountMigrationManager::realImportExport() | ||
{ | ||
auto client = newClient(true); | ||
auto *manager = client->findExtension<QXmppAccountMigrationManager>(); | ||
auto *rosterManager = client->findExtension<QXmppRosterManager>(); | ||
auto *vcardManager = client->findExtension<QXmppVCardManager>(); | ||
|
||
QVERIFY(manager); | ||
QVERIFY(rosterManager); | ||
QVERIFY(vcardManager); | ||
|
||
auto exportTask = manager->exportData(); | ||
QVERIFY(!exportTask.isFinished()); | ||
|
||
client->expect(QStringLiteral("<iq id='qxmpp2' from='pasnox@xmpp.example/QXmpp' type='get'>" | ||
"<query xmlns='jabber:iq:roster'>" | ||
"<annotate xmlns='urn:xmpp:mix:roster:0'/>" | ||
"</query>" | ||
"</iq>")); | ||
client->expect(QStringLiteral("<iq id='qxmpp3' to='pasnox@xmpp.example' type='get'>" | ||
"<vCard xmlns='vcard-temp'>" | ||
"<TITLE/>" | ||
"<ROLE/>" | ||
"</vCard>" | ||
"</iq>")); | ||
|
||
client->inject(packetToXml(newRoster(client.get(), 1, "qxmpp2", QXmppIq::Result))); | ||
client->inject(packetToXml(newClientVCard(client.get(), 1, "qxmpp3", QXmppIq::Result))); | ||
|
||
auto data = expectFutureVariant<QXmppExportData>(exportTask); | ||
|
||
// import exported data | ||
auto importTask = manager->importData(data); | ||
|
||
client->expect("<iq id='qxmpp3' to='pasnox@xmpp.example' type='set'>" | ||
"<vCard xmlns='vcard-temp'>" | ||
"<NICKNAME>It is me Bookri</NICKNAME>" | ||
"<N><GIVEN>Nox</GIVEN><FAMILY>Bookri</FAMILY></N>" | ||
"<TITLE/>" | ||
"<ROLE/>" | ||
"</vCard>" | ||
"</iq>"); | ||
client->expect("<iq id='qxmpp1' type='set'>" | ||
"<query xmlns='jabber:iq:roster'>" | ||
"<item jid='4@gamer.com' name='4 Gamer'>" | ||
"<group>gamers</group>" | ||
"</item>" | ||
"<item jid='5@gamer.com' name='5 Gamer'>" | ||
"<group>gamers</group>" | ||
"</item>" | ||
"<item jid='6@gamer.com' name='6 Gamer'>" | ||
"<group>gamers</group>" | ||
"</item>" | ||
"</query>" | ||
"</iq>"); | ||
client->inject(packetToXml(newClientVCard(client.get(), 1, "qxmpp3", QXmppIq::Result))); | ||
client->inject(packetToXml(newRoster(client.get(), 1, "qxmpp1", QXmppIq::Result))); | ||
|
||
expectFutureVariant<Success>(importTask); | ||
} | ||
|
||
void tst_QXmppAccountMigrationManager::serialization() | ||
{ | ||
auto client = newClient(true); | ||
auto *manager = client->findExtension<QXmppAccountMigrationManager>(); | ||
auto *rosterManager = client->findExtension<QXmppRosterManager>(); | ||
auto *vcardManager = client->findExtension<QXmppVCardManager>(); | ||
|
||
QVERIFY(manager); | ||
QVERIFY(rosterManager); | ||
QVERIFY(vcardManager); | ||
|
||
// generate export data | ||
auto exportTask = manager->exportData(); | ||
QVERIFY(!exportTask.isFinished()); | ||
|
||
client->expect(QStringLiteral("<iq id='qxmpp2' from='pasnox@xmpp.example/QXmpp' type='get'>" | ||
"<query xmlns='jabber:iq:roster'>" | ||
"<annotate xmlns='urn:xmpp:mix:roster:0'/>" | ||
"</query>" | ||
"</iq>")); | ||
client->expect(QStringLiteral("<iq id='qxmpp3' to='pasnox@xmpp.example' type='get'>" | ||
"<vCard xmlns='vcard-temp'>" | ||
"<TITLE/>" | ||
"<ROLE/>" | ||
"</vCard>" | ||
"</iq>")); | ||
|
||
client->inject(packetToXml(newRoster(client.get(), 1, "qxmpp2", QXmppIq::Result))); | ||
client->inject(packetToXml(newClientVCard(client.get(), 1, "qxmpp3", QXmppIq::Result))); | ||
|
||
// test serialize | ||
auto data = expectFutureVariant<QXmppExportData>(exportTask); | ||
auto xml1 = packetToXml(data); | ||
QByteArray xml2 = | ||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" | ||
"<account-data xmlns=\"org.qxmpp.export\" jid=\"pasnox@xmpp.example\">" | ||
"<vcard>" | ||
"<vCard xmlns=\"vcard-temp\">" | ||
"<NICKNAME>It is me Bookri</NICKNAME>" | ||
"<N><GIVEN>Nox</GIVEN><FAMILY>Bookri</FAMILY></N>" | ||
"<TITLE/><ROLE/>" | ||
"</vCard>" | ||
"</vcard>" | ||
"<roster>" | ||
"<item xmlns=\"jabber:iq:roster\" jid=\"4@gamer.com\" name=\"4 Gamer\"><group>gamers</group></item>" | ||
"<item xmlns=\"jabber:iq:roster\" jid=\"5@gamer.com\" name=\"5 Gamer\"><group>gamers</group></item>" | ||
"<item xmlns=\"jabber:iq:roster\" jid=\"6@gamer.com\" name=\"6 Gamer\"><group>gamers</group></item>" | ||
"</roster>" | ||
"</account-data>\n"; | ||
|
||
if (xml1 != xml2) { | ||
qDebug() << "Actual:\n" | ||
<< xml1; | ||
qDebug() << "Expected:\n" | ||
<< xml2; | ||
} | ||
QCOMPARE(xml1, xml2); | ||
|
||
// test parse (and re-serialize) | ||
auto parsedData = expectVariant<QXmppExportData>(QXmppExportData::fromDom(xmlToDom(xml2))); | ||
auto xml3 = packetToXml(parsedData); | ||
QByteArray xml4 = | ||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" | ||
"<account-data xmlns=\"org.qxmpp.export\" jid=\"pasnox@xmpp.example\">" | ||
"<roster>" | ||
"<item xmlns=\"jabber:iq:roster\" jid=\"4@gamer.com\" name=\"4 Gamer\"><group>gamers</group></item>" | ||
"<item xmlns=\"jabber:iq:roster\" jid=\"5@gamer.com\" name=\"5 Gamer\"><group>gamers</group></item>" | ||
"<item xmlns=\"jabber:iq:roster\" jid=\"6@gamer.com\" name=\"6 Gamer\"><group>gamers</group></item>" | ||
"</roster>" | ||
"<vcard>" | ||
"<vCard xmlns=\"vcard-temp\">" | ||
"<NICKNAME>It is me Bookri</NICKNAME>" | ||
"<N><GIVEN>Nox</GIVEN><FAMILY>Bookri</FAMILY></N>" | ||
"<TITLE/><ROLE/>" | ||
"</vCard>" | ||
"</vcard>" | ||
"</account-data>\n"; | ||
|
||
if (xml3 != xml4) { | ||
qDebug() << "Actual:\n" | ||
<< xml3; | ||
qDebug() << "Expected:\n" | ||
<< xml4; | ||
} | ||
QCOMPARE(xml3, xml4); | ||
} | ||
|
||
QTEST_MAIN(tst_QXmppAccountMigrationManager) | ||
#include "tst_qxmppaccountmigrationmanager.moc" |