File indexing completed on 2024-11-24 04:44:10
0001 /* 0002 * SPDX-FileCopyrightText: 2012 Christian Mollekopf <mollekopf@kolabsys.com> 0003 * 0004 * SPDX-License-Identifier: LGPL-3.0-or-later 0005 */ 0006 0007 #ifndef TESTUTILS_H 0008 #define TESTUTILS_H 0009 0010 #include <kolabevent.h> 0011 0012 #include "kolabformat/kolabobject.h" 0013 0014 #include <KMime/Message> 0015 0016 #include <QFile> 0017 #include <QRegularExpression> 0018 #include <QUuid> 0019 0020 Q_DECLARE_METATYPE(Kolab::ObjectType) 0021 Q_DECLARE_METATYPE(Kolab::Version) 0022 0023 #define KCOMPARE(actual, expected) \ 0024 do { \ 0025 if (!(actual == expected)) { \ 0026 qDebug() << __FILE__ << ':' << __LINE__ << "Actual: " #actual ": " << actual << "\nExpected: " #expected ": " << expected; \ 0027 return false; \ 0028 } \ 0029 } while (0) 0030 0031 #endif 0032 0033 #define DIFFCOMPARE(actual, expected) \ 0034 do { \ 0035 if (!(actual.simplified() == expected.simplified())) { \ 0036 qDebug() << "Content not the same."; \ 0037 qDebug() << "actual." << actual.simplified() << "\n"; \ 0038 qDebug() << "expected." << expected.simplified(); \ 0039 showDiff(expected, actual); \ 0040 QTest::qFail("Compared versions differ.", __FILE__, __LINE__); \ 0041 return; \ 0042 } \ 0043 } while (0) 0044 0045 #define TESTVALUE(type, name) *static_cast<type *>(QTest::qData(#name, ::qMetaTypeId<type>())) 0046 0047 const QString TESTFILEDIR = QString::fromLatin1(TEST_DATA_PATH "/testfiles/"); 0048 0049 QString getPath(const char *file) 0050 { 0051 return TESTFILEDIR + QString::fromLatin1(file); 0052 } 0053 0054 void showDiff(const QString &expected, const QString &converted) 0055 { 0056 if (expected.isEmpty() || converted.isEmpty()) { 0057 qWarning() << "files are empty"; 0058 return; 0059 } 0060 if (expected == converted) { 0061 qWarning() << "contents are the same"; 0062 return; 0063 } 0064 0065 qDebug() << "EXPECTED: " << expected; 0066 qDebug() << "CONVERTED: " << converted; 0067 } 0068 0069 KMime::Message::Ptr readMimeFile(const QString &fileName, bool &ok) 0070 { 0071 // qDebug() << fileName; 0072 QFile file(fileName); 0073 ok = file.open(QFile::ReadOnly); 0074 if (!ok) { 0075 qWarning() << "failed to open file: " << fileName; 0076 return {}; 0077 } 0078 const QByteArray data = file.readAll(); 0079 0080 KMime::Message::Ptr msg = KMime::Message::Ptr(new KMime::Message); 0081 msg->setContent(data); 0082 msg->parse(); 0083 0084 return msg; 0085 } 0086 0087 void normalizeMimemessage(QString &content) 0088 { 0089 content.replace(QRegularExpression(QStringLiteral("\\bLibkolab-\\d.\\d.\\d\\b")), QStringLiteral("Libkolab-x.x.x")); 0090 content.replace(QRegularExpression(QStringLiteral("\\bLibkolabxml-\\d.\\d.\\d\\b")), QStringLiteral("Libkolabxml-x.x.x")); 0091 content.replace(QRegularExpression(QStringLiteral("\\bLibkolab-\\d.\\d\\b")), QStringLiteral("Libkolab-x.x.x")); 0092 content.replace(QRegularExpression(QStringLiteral("\\bkdepim-runtime-\\d.\\d\\b")), QStringLiteral("Libkolab-x.x.x")); 0093 content.replace(QRegularExpression(QStringLiteral("\\bLibkolabxml-\\d.\\d\\b")), QStringLiteral("Libkolabxml-x.x.x")); 0094 0095 content.replace(QRegularExpression(QStringLiteral("<uri>cid:.*@kolab.resource.akonadi</uri>")), QStringLiteral("<uri>cid:id@kolab.resource.akonadi</uri>")); 0096 0097 content.replace(QRegularExpression(QStringLiteral("Content-ID: <.*@kolab.resource.akonadi>")), QStringLiteral("Content-ID: <id@kolab.resource.akonadi>")); 0098 0099 content.replace(QRegularExpression(QStringLiteral("<uri>mailto:.*</uri>")), QStringLiteral("<uri>mailto:</uri>")); 0100 content.replace(QRegularExpression(QStringLiteral("<cal-address>mailto:.*</cal-address>")), QStringLiteral("<cal-address>mailto:</cal-address>")); 0101 0102 content.replace(QRegularExpression(QStringLiteral("<uri>data:.*</uri>")), QStringLiteral("<uri>data:</uri>")); 0103 0104 content.replace(QRegularExpression(QStringLiteral("<last-modification-date>.*</last-modification-date>")), 0105 QStringLiteral("<last-modification-date></last-modification-date>")); 0106 // We no longer support pobox, so remove pobox lines 0107 content.remove(QRegularExpression(QStringLiteral("<pobox>.*</pobox>"))); 0108 0109 content.replace(QRegularExpression(QStringLiteral("<timestamp>.*</timestamp>")), QStringLiteral("<timestamp></timestamp>")); 0110 0111 // DotMatchesEverythingOption because <x-koblab-version> spans multiple lines 0112 content.replace(QRegularExpression(QStringLiteral("<x-kolab-version>.*</x-kolab-version>"), QRegularExpression::DotMatchesEverythingOption), 0113 QStringLiteral("<x-kolab-version></x-kolab-version>")); 0114 0115 content.replace(QRegularExpression(QStringLiteral("--nextPart\\S*")), QStringLiteral("--part")); 0116 content.replace(QRegularExpression(QStringLiteral("\\bboundary=\"nextPart[^\\n]*")), QStringLiteral("boundary")); 0117 0118 content.replace(QRegularExpression(QStringLiteral("Date[^\\n]*")), QStringLiteral("Date")); 0119 // The sort order of the attributes in kolabV2 is unpredictable 0120 content.replace(QRegularExpression(QStringLiteral("<x-custom.*/>")), QStringLiteral("<x-custom/>")); 0121 // quoted-printable encoding changes where the linebreaks are every now and then (an all are valid), so we remove the linebreaks 0122 content.remove(QLatin1StringView("=\n")); 0123 } 0124 0125 QString normalizeVCardMessage(QString content) 0126 { 0127 // The encoding changes every now and then 0128 content.replace(QRegularExpression(QStringLiteral("ENCODING=b;TYPE=png:.*")), QStringLiteral("ENCODING=b;TYPE=png:picturedata")); 0129 return content; 0130 } 0131 0132 // Normalize incidences for comparison 0133 void normalizeIncidence(KCalendarCore::Incidence::Ptr incidence) 0134 { 0135 // The UID is not persistent (it's just the internal pointer), therefore we clear it 0136 // TODO make sure that the UID does really not need to be persistent 0137 auto attendees = incidence->attendees(); 0138 for (auto &attendee : attendees) { 0139 attendee.setUid(attendee.email()); 0140 } 0141 incidence->setAttendees(attendees); 0142 0143 // FIXME even if hasDueDate can differ, it shouldn't because it breaks equality. Check why they differ in the first place. 0144 if (incidence->type() == KCalendarCore::IncidenceBase::TypeTodo) { 0145 KCalendarCore::Todo::Ptr todo = incidence.dynamicCast<KCalendarCore::Todo>(); 0146 Q_ASSERT(todo.data()); 0147 if (!todo->hasDueDate() && !todo->hasStartDate()) { 0148 todo->setAllDay(false); // all day has no meaning if there are no start and due dates but may differ nevertheless 0149 } 0150 } 0151 } 0152 0153 template<template<typename> class Op, typename T> 0154 static bool LexicographicalCompare(const T &_x, const T &_y) 0155 { 0156 T x(_x); 0157 x.setId(QString()); 0158 T y(_y); 0159 y.setId(QString()); 0160 Op<QString> op; 0161 return op(x.toString(), y.toString()); 0162 } 0163 0164 bool normalizePhoneNumbers(KContacts::Addressee &addressee, KContacts::Addressee &refAddressee) 0165 { 0166 KContacts::PhoneNumber::List phoneNumbers = addressee.phoneNumbers(); 0167 KContacts::PhoneNumber::List refPhoneNumbers = refAddressee.phoneNumbers(); 0168 if (phoneNumbers.size() != refPhoneNumbers.size()) { 0169 return false; 0170 } 0171 std::sort(phoneNumbers.begin(), phoneNumbers.end(), LexicographicalCompare<std::less, KContacts::PhoneNumber>); 0172 std::sort(refPhoneNumbers.begin(), refPhoneNumbers.end(), LexicographicalCompare<std::less, KContacts::PhoneNumber>); 0173 0174 for (int i = 0; i < phoneNumbers.size(); ++i) { 0175 KContacts::PhoneNumber phoneNumber = phoneNumbers.at(i); 0176 const KContacts::PhoneNumber refPhoneNumber = refPhoneNumbers.at(i); 0177 KCOMPARE(LexicographicalCompare<std::equal_to>(phoneNumber, refPhoneNumber), true); 0178 addressee.removePhoneNumber(phoneNumber); 0179 phoneNumber.setId(refPhoneNumber.id()); 0180 addressee.insertPhoneNumber(phoneNumber); 0181 // Make sure that both have the same sorted order 0182 refAddressee.removePhoneNumber(refPhoneNumber); 0183 refAddressee.insertPhoneNumber(refPhoneNumber); 0184 } 0185 // for ( int i = 0; i < phoneNumbers.size(); ++i ) { 0186 // qDebug() << "--------------------------------------"; 0187 // qDebug() << addressee.phoneNumbers().at(i).toString(); 0188 // qDebug() << refAddressee.phoneNumbers().at(i).toString(); 0189 // } 0190 0191 return true; 0192 } 0193 0194 bool normalizeAddresses(KContacts::Addressee &addressee, const KContacts::Addressee &refAddressee) 0195 { 0196 KContacts::Address::List addresses = addressee.addresses(); 0197 KContacts::Address::List refAddresses = refAddressee.addresses(); 0198 if (addresses.size() != refAddresses.size()) { 0199 return false; 0200 } 0201 std::sort(addresses.begin(), addresses.end(), LexicographicalCompare<std::less, KContacts::Address>); 0202 std::sort(refAddresses.begin(), refAddresses.end(), LexicographicalCompare<std::less, KContacts::Address>); 0203 0204 for (int i = 0; i < addresses.size(); ++i) { 0205 KContacts::Address address = addresses.at(i); 0206 const KContacts::Address refAddress = refAddresses.at(i); 0207 KCOMPARE(LexicographicalCompare<std::equal_to>(address, refAddress), true); 0208 addressee.removeAddress(address); 0209 address.setId(refAddress.id()); 0210 addressee.insertAddress(address); 0211 } 0212 0213 return true; 0214 } 0215 0216 void normalizeContact(KContacts::Addressee &addressee) 0217 { 0218 const KContacts::Address::List addresses = addressee.addresses(); 0219 0220 for (KContacts::Address a : addresses) { 0221 addressee.removeAddress(a); 0222 a.setPostOfficeBox(QString()); // Not supported anymore 0223 addressee.insertAddress(a); 0224 } 0225 addressee.setSound(KContacts::Sound()); // Sound is not supported 0226 0227 addressee.removeCustom(QStringLiteral("KOLAB"), QStringLiteral("CreationDate")); // The creation date is no longer existing 0228 0229 // Attachment names are no longer required because we identify the parts by cid and no longer by name 0230 addressee.removeCustom(QStringLiteral("KOLAB"), QStringLiteral("LogoAttachmentName")); 0231 addressee.removeCustom(QStringLiteral("KOLAB"), QStringLiteral("PictureAttachmentName")); 0232 addressee.removeCustom(QStringLiteral("KOLAB"), QStringLiteral("SoundAttachmentName")); 0233 } 0234 0235 Kolab::Event createEvent(const Kolab::cDateTime &start, const Kolab::cDateTime &end) 0236 { 0237 Kolab::Event event; 0238 event.setUid(QUuid::createUuid().toString().toStdString()); 0239 event.setStart(start); 0240 event.setEnd(end); 0241 return event; 0242 }