File indexing completed on 2024-05-12 05:17:29
0001 /* 0002 SPDX-FileCopyrightText: 2017 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "calendarhandler.h" 0008 #include "extractorpostprocessor.h" 0009 #include "jsonlddocument.h" 0010 0011 #include <KCalendarCore/ICalFormat> 0012 #include <KCalendarCore/MemoryCalendar> 0013 0014 #include <QDebug> 0015 #include <QFile> 0016 #include <QJsonArray> 0017 #include <QJsonDocument> 0018 #include <QProcess> 0019 #include <QObject> 0020 #include <QTest> 0021 0022 using namespace KCalendarCore; 0023 using namespace KItinerary; 0024 0025 void initLocale() 0026 { 0027 qputenv("LC_ALL", "en_US.utf-8"); 0028 qputenv("TZ", "UTC"); 0029 } 0030 0031 Q_CONSTRUCTOR_FUNCTION(initLocale) 0032 0033 class CalendarHandlerTest : public QObject 0034 { 0035 Q_OBJECT 0036 private Q_SLOTS: 0037 void testCreateEvent_data() 0038 { 0039 QTest::addColumn<QString>("jsonFile"); 0040 QTest::addColumn<QString>("icalFile"); 0041 0042 QDir dir(QStringLiteral(SOURCE_DIR "/calendarhandlerdata")); 0043 const auto lst = dir.entryList(QStringList(QStringLiteral("*.json")), QDir::Files | QDir::Readable | QDir::NoSymLinks); 0044 for (const auto &file : lst) { 0045 const QString refFile = dir.path() + QLatin1Char('/') + file.left(file.size() - 4) + QStringLiteral("ics"); 0046 if (!QFile::exists(refFile)) { 0047 qDebug() << "reference file" << refFile << "does not exist, skipping test file" << file; 0048 continue; 0049 } 0050 QTest::newRow(file.toLatin1().constData()) << QString(dir.path() + QLatin1Char('/') + file) << refFile; 0051 } 0052 } 0053 0054 void testCreateEvent() 0055 { 0056 QFETCH(QString, jsonFile); 0057 QFETCH(QString, icalFile); 0058 0059 QFile f(jsonFile); 0060 QVERIFY(f.open(QFile::ReadOnly)); 0061 const auto inArray = QJsonDocument::fromJson(f.readAll()).array(); 0062 QVERIFY(!inArray.isEmpty()); 0063 const auto preData = JsonLdDocument::fromJson(inArray); 0064 QCOMPARE(inArray.size(), preData.size()); 0065 0066 ExtractorPostprocessor postproc; 0067 postproc.process(preData); 0068 const auto postData = postproc.result(); 0069 QVERIFY(std::all_of(postData.begin(), postData.end(), CalendarHandler::canCreateEvent)); 0070 QCOMPARE(inArray.size(), postData.size()); 0071 0072 MemoryCalendar::Ptr refCal(new MemoryCalendar(QTimeZone::systemTimeZone())); 0073 ICalFormat format; 0074 QVERIFY(format.load(refCal, icalFile)); 0075 0076 const auto refEvents = refCal->rawEvents(KCalendarCore::EventSortStartDate, KCalendarCore::SortDirectionAscending); 0077 QCOMPARE(refEvents.size(), 1); 0078 Event::Ptr newEvent(new Event); 0079 CalendarHandler::fillEvent(postData, newEvent); 0080 0081 // sync volatile fields, we only care for differences elsewhere 0082 const auto &refEvent = refEvents.at(0); 0083 newEvent->setUid(refEvent->uid()); 0084 newEvent->setLastModified(refEvent->lastModified()); 0085 newEvent->setCreated(refEvent->created()); 0086 // normalize the effect of CLDR 42 0087 newEvent->setDescription(newEvent->description().replace( 0088 QStringLiteral("\u202F"), QLatin1StringView(" "))); 0089 0090 if (*newEvent != *refEvent) { 0091 qDebug().noquote() << "Actual: " << format.toICalString(newEvent).remove(QLatin1Char('\r')); 0092 qDebug().noquote() << "Expected: " << format.toICalString(refEvent).remove(QLatin1Char('\r')); 0093 0094 QFile failFile(icalFile + QLatin1StringView(".fail")); 0095 QVERIFY(failFile.open(QFile::WriteOnly)); 0096 failFile.write(format.toICalString(newEvent).remove(QLatin1Char('\r')).toUtf8()); 0097 failFile.close(); 0098 0099 QProcess proc; 0100 proc.setProcessChannelMode(QProcess::ForwardedChannels); 0101 proc.start(QStringLiteral("diff"), {QStringLiteral("-u"), icalFile, failFile.fileName()}); 0102 QVERIFY(proc.waitForFinished()); 0103 } 0104 0105 QCOMPARE(newEvent->dtStart(), refEvent->dtStart()); 0106 QCOMPARE(newEvent->dtEnd(), refEvent->dtEnd()); 0107 QCOMPARE(newEvent->customProperty("KITINERARY", "RESERVATION"), refEvent->customProperty("KITINERARY", "RESERVATION")); 0108 QCOMPARE(newEvent->description(), refEvent->description()); 0109 QVERIFY(*newEvent == *refEvent); 0110 } 0111 0112 void testFindEvent_data() 0113 { 0114 QTest::addColumn<QString>("jsonFile"); 0115 QTest::addColumn<QString>("icalFile"); 0116 0117 QDir dir(QStringLiteral(SOURCE_DIR "/calendarhandlerdata")); 0118 const auto lst = dir.entryList(QStringList(QStringLiteral("*.json")), QDir::Files | QDir::Readable | QDir::NoSymLinks); 0119 for (const auto &file : lst) { 0120 const QString refFile = dir.path() + QLatin1Char('/') + file.left(file.size() - 4) + QStringLiteral("ics"); 0121 if (!QFile::exists(refFile)) { 0122 qDebug() << "reference file" << refFile << "does not exist, skipping test file" << file; 0123 continue; 0124 } 0125 QTest::newRow(file.toLatin1().constData()) << QString(dir.path() + QLatin1Char('/') + file) << refFile; 0126 } 0127 } 0128 0129 void testFindEvent() 0130 { 0131 QFETCH(QString, jsonFile); 0132 QFETCH(QString, icalFile); 0133 0134 QFile f(jsonFile); 0135 QVERIFY(f.open(QFile::ReadOnly)); 0136 const auto inArray = QJsonDocument::fromJson(f.readAll()).array(); 0137 QVERIFY(!inArray.isEmpty()); 0138 const auto preData = JsonLdDocument::fromJson(inArray); 0139 QCOMPARE(inArray.size(), preData.size()); 0140 0141 ExtractorPostprocessor postproc; 0142 postproc.process(preData); 0143 QCOMPARE(inArray.size(), postproc.result().size()); 0144 0145 MemoryCalendar::Ptr refCal(new MemoryCalendar(QTimeZone::systemTimeZone())); 0146 ICalFormat format; 0147 QVERIFY(format.load(refCal, icalFile)); 0148 0149 const auto events = CalendarHandler::findEvents(refCal, postproc.result().at(0)); 0150 QCOMPARE(events.size(), 1); 0151 QVERIFY(events[0]); 0152 } 0153 0154 void testFindEventForCancellation() 0155 { 0156 QFile f(QStringLiteral(SOURCE_DIR "/mergedata/cancellation.rhs.json")); 0157 QVERIFY(f.open(QFile::ReadOnly)); 0158 const auto in = JsonLdDocument::fromJson(QJsonDocument::fromJson(f.readAll()).array()); 0159 QCOMPARE(in.size(), 1); 0160 const auto cancel = in[0]; 0161 0162 MemoryCalendar::Ptr refCal(new MemoryCalendar(QTimeZone::systemTimeZone())); 0163 ICalFormat format; 0164 QVERIFY(format.load(refCal, QStringLiteral(SOURCE_DIR "/calendarhandlerdata/to-be-cancelled.ics"))); 0165 0166 const auto events = CalendarHandler::findEvents(refCal, cancel); 0167 QCOMPARE(events.size(), 2); 0168 QVERIFY(events[0]); 0169 QVERIFY(events[1]); 0170 } 0171 }; 0172 0173 QTEST_APPLESS_MAIN(CalendarHandlerTest) 0174 0175 #include "calendarhandlertest.moc"