File indexing completed on 2025-07-13 04:57:37
0001 /* 0002 SPDX-FileCopyrightText: 2023 Natalie Clarius <natalie_clarius@yahoo.de> 0003 0004 SPDX-License-Identifier: LGPL-2.0-only 0005 */ 0006 0007 #include <KRunner/AbstractRunnerTest> 0008 0009 #include <QDateTime> 0010 #include <QTimeZone> 0011 0012 #include <qtestcase.h> 0013 0014 using namespace Qt::StringLiterals; 0015 using namespace KRunner; 0016 0017 class DateTimeRunnerTest : public AbstractRunnerTest 0018 { 0019 Q_OBJECT 0020 private Q_SLOTS: 0021 void initTestCase(); 0022 void testLocalTimeInfo(); 0023 void testRemoteTimeInfo(); 0024 void testFindTimezones_data(); 0025 void testFindTimezones(); 0026 void testConversion_data(); 0027 void testConversion(); 0028 }; 0029 0030 #ifndef Q_OS_WIN 0031 void initEnv() 0032 { 0033 setenv("LC_ALL", "en_US.UTF-8", 1); 0034 setenv("TZ", "GMT", 1); 0035 } 0036 Q_CONSTRUCTOR_FUNCTION(initEnv) 0037 #endif 0038 0039 void DateTimeRunnerTest::initTestCase() 0040 { 0041 initProperties(); 0042 } 0043 0044 void DateTimeRunnerTest::testLocalTimeInfo() 0045 { 0046 const QTime localTime = QDateTime::currentDateTime().time(); 0047 const QString timeStr = QLocale().toString(localTime); 0048 0049 launchQuery("time"); 0050 0051 QCOMPARE(manager->matches().count(), 1); 0052 QVERIFY(manager->matches().first().text().contains(timeStr)); 0053 } 0054 0055 void DateTimeRunnerTest::testRemoteTimeInfo() 0056 { 0057 // See the definition of GMT in https://data.iana.org/time-zones/releases/tzdata2023c.tar.gz -> etcetera 0058 // 0059 // Be consistent with POSIX TZ settings in the Zone names, 0060 // even though this is the opposite of what many people expect. 0061 // POSIX has positive signs west of Greenwich, but many people expect 0062 // positive signs east of Greenwich.For example, TZ = 'Etc/GMT+4' uses 0063 // the abbreviation "-04" and corresponds to 4 hours behind UT 0064 // (i.e.west of Greenwich) even though many people would expect it to 0065 // mean 4 hours ahead of UT(i.e.east of Greenwich). 0066 0067 const QTime remoteTime = QDateTime::currentDateTime().toTimeZone(QTimeZone("GMT-2")).time(); 0068 const QString timeStr = QLocale().toString(remoteTime, QLocale::ShortFormat); 0069 constexpr QLatin1String timeDiffStr{"2 hours later"}; 0070 0071 launchQuery("time gmt-2"); 0072 auto matches = manager->matches(); 0073 std::sort(matches.begin(), matches.end(), [](const KRunner::QueryMatch &a, const KRunner::QueryMatch &b) { 0074 return a.relevance() > b.relevance(); 0075 }); 0076 0077 QCOMPARE(manager->matches().count(), 1); 0078 QVERIFY2(manager->matches().first().text().contains(timeStr), 0079 QStringLiteral("first match: %1 timeStr: %2").arg(manager->matches().first().text(), timeStr).toUtf8().constData()); 0080 QVERIFY(manager->matches().first().text().contains(timeDiffStr)); 0081 } 0082 0083 void DateTimeRunnerTest::testFindTimezones() 0084 { 0085 QFETCH(QString, searchTerm); 0086 QFETCH(int, minMatchCount); 0087 QFETCH(QString, expectedTimezone); 0088 0089 launchQuery("time " + searchTerm); 0090 auto matches = manager->matches(); 0091 // Skip Daylight Saving Time for now, as it causes troubles in the test 0092 matches.erase(std::remove_if(matches.begin(), 0093 matches.end(), 0094 [](const QueryMatch &match) { 0095 return match.text().contains(QLatin1String("PST8PDT")); 0096 }), 0097 matches.end()); 0098 std::sort(matches.begin(), matches.end(), [](const KRunner::QueryMatch &a, const KRunner::QueryMatch &b) { 0099 return a.relevance() > b.relevance(); 0100 }); 0101 0102 QVERIFY2(matches.size() >= minMatchCount, 0103 QStringLiteral("searchTerm: %1, matches.size(): %2, minMatchCount: %3") 0104 .arg(searchTerm, QString::number(matches.size()), QString::number(minMatchCount)) 0105 .toUtf8() 0106 .constData()); 0107 QVERIFY2(matches.first().text().contains(expectedTimezone), 0108 QStringLiteral("first match: %1, expectedTimezone: %2").arg(matches.first().text(), expectedTimezone).toUtf8().constData()); 0109 } 0110 0111 void DateTimeRunnerTest::testFindTimezones_data() 0112 { 0113 QTest::addColumn<QString>("searchTerm"); 0114 QTest::addColumn<int>("minMatchCount"); 0115 QTest::addColumn<QString>("expectedTimezone"); 0116 0117 QTest::newRow("Should find time zones by city name") << "Harare" << 1 << "Harare"; 0118 QTest::newRow("Should find time zones by long name") << "Central Africa Time" << 1 << "Central Africa Time"; 0119 QTest::newRow("Should find time zones by short name") << "GMT+2" << 1 << "GMT+2"; 0120 QTest::newRow("Should find time zones by offset name") << "UTC+02:00" << 1 << "UTC+02:00"; 0121 QTest::newRow("Should find time zones by abbreviation, and show all time zones with that abbreviation") << "PST" << 1 << "(PST)"; 0122 QTest::newRow("Should find time zones by country name, and show all time zones in that country") << "Brazil" << 2 << "Brazil - "; 0123 QTest::newRow("Should find time zones with the 'in' keyword") << "in Harare" << 1 << "Harare"; 0124 } 0125 0126 void DateTimeRunnerTest::testConversion() 0127 { 0128 #if QT_VERSION < QT_VERSION_CHECK(6, 6, 0) 0129 QSKIP("CLDR 42 replaced plain ASCII space U+0020 with U+202F when formatting dates. It's fixed in Qt 6.6."); 0130 #endif 0131 QFETCH(QString, query); 0132 QFETCH(QString, expectedSourceTimezone); 0133 QFETCH(QString, expectedSourceTime); 0134 QFETCH(QString, expectedTargetTimezone); 0135 QFETCH(QString, expectedTargetTime); 0136 QFETCH(QString, expectedTimeDiff); 0137 0138 launchQuery(query); 0139 auto matches = manager->matches(); 0140 std::sort(matches.begin(), matches.end(), [](const KRunner::QueryMatch &a, const KRunner::QueryMatch &b) { 0141 return a.relevance() > b.relevance(); 0142 }); 0143 0144 QVERIFY(!matches.isEmpty()); 0145 qDebug() << matches.first().text(); 0146 const QString targetText = u"%1: %2"_s.arg(expectedTargetTimezone, expectedTargetTime); 0147 QVERIFY2(matches.first().text().contains(targetText), qUtf8Printable(targetText)); 0148 const QString sourceText = u"%1: %2"_s.arg(expectedSourceTimezone, expectedSourceTime); 0149 QVERIFY2(matches.first().text().contains(sourceText), qUtf8Printable(sourceText)); 0150 QVERIFY2(matches.first().text().contains(expectedTimeDiff), qUtf8Printable(expectedTimeDiff)); 0151 } 0152 0153 void DateTimeRunnerTest::testConversion_data() 0154 { 0155 const QTimeZone systemTimeZone = QTimeZone::systemTimeZone().isValid() ? QTimeZone::systemTimeZone() : QTimeZone::utc(); // needed for FreeBSD CI 0156 const QString systemTimeZoneName = systemTimeZone.abbreviation(QDateTime::currentDateTime()); 0157 0158 QTest::addColumn<QString>("query"); 0159 QTest::addColumn<QString>("expectedSourceTimezone"); 0160 QTest::addColumn<QString>("expectedSourceTime"); 0161 QTest::addColumn<QString>("expectedTargetTimezone"); 0162 QTest::addColumn<QString>("expectedTargetTime"); 0163 QTest::addColumn<QString>("expectedTimeDiff"); 0164 0165 QTest::newRow("Should convert from first to second time zone") << "12:00 PM gmt-2 in greenwich" 0166 << "GMT-2" << u"12:00 PM"_s << "Greenwich" << u"10:00 AM"_s << "2 hours earlier"; 0167 QTest::newRow("Should convert from first to second time zone with date") << "1/5/23 12:00 PM gmt-2 in greenwich" 0168 << "GMT-2" << u"12:00 PM"_s << "Greenwich" << u"10:00 AM"_s << "2 hours earlier"; 0169 QTest::newRow("Should convert from system time zone to second time zone") 0170 << "12:00 PM in gmt+2" << systemTimeZoneName << u"12:00 PM"_s << "GMT+2" << u"2:00 PM"_s << "2 hours later"; 0171 QTest::newRow("Should convert from first time zone to system time zone") 0172 << "12:00 PM gmt+2" 0173 << "GMT+2" << u"12:00 PM"_s << systemTimeZoneName << u"10:00 AM"_s << "2 hours earlier"; 0174 } 0175 0176 QTEST_MAIN(DateTimeRunnerTest) 0177 0178 #include "datetimerunnertest.moc"