diff --git a/Modules/about-distro/CMakeLists.txt b/Modules/about-distro/CMakeLists.txt index 0a77d44..9d41c50 100644 --- a/Modules/about-distro/CMakeLists.txt +++ b/Modules/about-distro/CMakeLists.txt @@ -1,7 +1,11 @@ # KI18N Translation Domain for this library add_definitions(-DTRANSLATION_DOMAIN=\"kcm-about-distro\") add_subdirectory(src) +if(BUILD_TESTING) + add_subdirectory(autotests) +endif() + feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/Modules/about-distro/autotests/CMakeLists.txt b/Modules/about-distro/autotests/CMakeLists.txt new file mode 100644 index 0000000..47f3bbc --- /dev/null +++ b/Modules/about-distro/autotests/CMakeLists.txt @@ -0,0 +1,23 @@ +remove_definitions(-DQT_NO_CAST_FROM_ASCII) + +include(ECMAddTests) + +find_package(Qt5Test ${REQUIRED_QT_VERSION} CONFIG REQUIRED) + +# Include src to get access to the OSRelease.h +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../src) + +add_library(about-distro-test STATIC ../src/OSRelease.cpp) +target_link_libraries(about-distro-test + PUBLIC + KF5::CoreAddons +) + +ecm_add_tests( + OSReleaseTest.cpp + LINK_LIBRARIES + Qt5::Test + about-distro-test +) + +ecm_mark_nongui_executable(OSReleaseTest) diff --git a/Modules/about-distro/autotests/OSReleaseTest.cpp b/Modules/about-distro/autotests/OSReleaseTest.cpp new file mode 100644 index 0000000..074571e --- /dev/null +++ b/Modules/about-distro/autotests/OSReleaseTest.cpp @@ -0,0 +1,57 @@ +/* + Copyright (C) 2019 Harald Sitter + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License or (at your option) version 3 or any later version + accepted by the membership of KDE e.V. (or its successor approved + by the membership of KDE e.V.), which shall act as a proxy + defined in Section 14 of version 3 of the license. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include + +#include "OSRelease.h" + +class OSReleaseTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase() {} + + void testParse() + { + auto r = OSRelease(QFINDTESTDATA("data/os-release")); + QCOMPARE(r.name, "Name"); + QCOMPARE(r.version, "100.5"); + QCOMPARE(r.id, "theid"); + QCOMPARE(r.idLike, QStringList({"otherid", "otherotherid"})); + QCOMPARE(r.versionCodename, "versioncodename"); + QCOMPARE(r.versionId, "500.1"); + QCOMPARE(r.prettyName, "Pretty Name"); + QCOMPARE(r.ansiColor, "1;34"); + QCOMPARE(r.cpeName, "cpe:/o:foo:bar:100"); + QCOMPARE(r.homeUrl, "https://url.home"); + QCOMPARE(r.documentationUrl, "https://url.docs"); + QCOMPARE(r.supportUrl, "https://url.support"); + QCOMPARE(r.bugReportUrl, "https://url.bugs"); + QCOMPARE(r.privacyPolicyUrl, "https://url.privacy"); + QCOMPARE(r.buildId, "105.5"); + QCOMPARE(r.variant, "Test Edition"); + QCOMPARE(r.variantId, "test"); + QCOMPARE(r.logo, "start-here-test"); + } +}; + +QTEST_MAIN(OSReleaseTest) + +#include "OSReleaseTest.moc" diff --git a/Modules/about-distro/autotests/data/os-release b/Modules/about-distro/autotests/data/os-release new file mode 100644 index 0000000..e4cd548 --- /dev/null +++ b/Modules/about-distro/autotests/data/os-release @@ -0,0 +1,18 @@ +NAME="Name" +VERSION="100.5" +ID=theid +ID_LIKE="otherid otherotherid" +VERSION_CODENAME=versioncodename +VERSION_ID="500.1" +PRETTY_NAME="Pretty Name" +ANSI_COLOR="1;34" +CPE_NAME="cpe:/o:foo:bar:100" +HOME_URL="https://url.home" +DOCUMENTATION_URL="https://url.docs" +SUPPORT_URL="https://url.support" +BUG_REPORT_URL="https://url.bugs" +PRIVACY_POLICY_URL="https://url.privacy" +BUILD_ID="105.5" +VARIANT="Test Edition" +VARIANT_ID=test +LOGO=start-here-test diff --git a/Modules/about-distro/src/OSRelease.cpp b/Modules/about-distro/src/OSRelease.cpp index c2b4f0d..95c16b8 100644 --- a/Modules/about-distro/src/OSRelease.cpp +++ b/Modules/about-distro/src/OSRelease.cpp @@ -1,135 +1,145 @@ /* - Copyright (C) 2014 Harald Sitter + Copyright (C) 2014-2019 Harald Sitter This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "OSRelease.h" #include #include -#include #include static void setVar(QString *var, const QString &value) { // Values may contain quotation marks, strip them as we have no use for them. KShell::Errors error; QStringList args = KShell::splitArgs(value, KShell::NoOptions, &error); if (error != KShell::NoError) { // Failed to parse. return; } *var = args.join(QLatin1Char(' ')); } static void setVar(QStringList *var, const QString &value) { // Instead of passing the verbatim value we manually strip any initial quotes // and then run it through KShell. At this point KShell will actually split // by spaces giving us the final QStringList. // NOTE: Splitting like this does not actually allow escaped substrings to // be handled correctly, so "kitteh \"french fries\"" would result in // three list entries. I'd argue that if someone makes an id like that // they are at fault for the bogus parsing here though as id explicitly // is required to not contain spaces even if more advanced shell escaping // is also allowed... QString value_ = value; if (value_.at(0) == QLatin1Char('"') && value_.at(value_.size()-1) == QLatin1Char('"')) { value_.remove(0, 1); value_.remove(-1, 1); } KShell::Errors error; QStringList args = KShell::splitArgs(value_, KShell::NoOptions, &error); if (error != KShell::NoError) { // Failed to parse. return; } *var = args; } -OSRelease::OSRelease() +OSRelease::OSRelease(const QString &filePath) { // Set default values for non-optional fields. name = QStringLiteral("Linux"); id = QStringLiteral("linux"); prettyName = QStringLiteral("Linux"); - QString fileName; - - if (QFile::exists(QStringLiteral("/etc/os-release"))) { - fileName = QStringLiteral("/etc/os-release"); - } else if (QFile::exists(QStringLiteral("/usr/lib/os-release"))) { - fileName = QStringLiteral("/usr/lib/os-release"); - } else { + if (filePath.isEmpty()) { return; } - - QFile file(fileName); + QHash stringHash = { + { QStringLiteral("NAME"), &name }, + { QStringLiteral("VERSION"), &version }, + { QStringLiteral("ID"), &id }, + // idLike is not a QString, special handling below! + { QStringLiteral("VERSION_CODENAME"), &versionCodename }, + { QStringLiteral("VERSION_ID"), &versionId }, + { QStringLiteral("PRETTY_NAME"), &prettyName }, + { QStringLiteral("ANSI_COLOR"), &ansiColor }, + { QStringLiteral("CPE_NAME"), &cpeName }, + { QStringLiteral("HOME_URL"), &homeUrl }, + { QStringLiteral("DOCUMENTATION_URL"), &documentationUrl }, + { QStringLiteral("SUPPORT_URL"), &supportUrl }, + { QStringLiteral("BUG_REPORT_URL"), &bugReportUrl }, + { QStringLiteral("PRIVACY_POLICY_URL"), &privacyPolicyUrl }, + { QStringLiteral("BUILD_ID"), &buildId }, + { QStringLiteral("VARIANT"), &variant }, + { QStringLiteral("VARIANT_ID"), &variantId }, + { QStringLiteral("LOGO"), &logo } + }; + + QFile file(filePath); // NOTE: The os-release specification defines default values for specific // fields which means that even if we can not read the os-release file // we have sort of expected default values to use. // TODO: it might still be handy to indicate to the outside whether // fallback values are being used or not. file.open(QIODevice::ReadOnly | QIODevice::Text); QString line; QStringList comps; while (!file.atEnd()) { line = QString::fromLatin1(file.readLine()); if (line.startsWith(QLatin1Char('#'))) { // Comment line continue; } comps = line.split(QLatin1Char('=')); if (comps.size() != 2) { // Invalid line. continue; } QString key = comps.at(0); QString value = comps.at(1).trimmed(); - if (key == QLatin1String("NAME")) - setVar(&name, value); - else if (key == QLatin1String("VERSION")) - setVar(&version, value); - else if (key == QLatin1String("ID")) - setVar(&id, value); - else if (key == QLatin1String("ID_LIKE")) + + if (QString *var = stringHash.value(key, nullptr)) { + setVar(var, value); + } + + // ID_LIKE is a list and parsed as such (rather than a QString). + if (key == QLatin1String("ID_LIKE")) { setVar(&idLike, value); - else if (key == QLatin1String("VERSION_ID")) - setVar(&versionId, value); - else if (key == QLatin1String("PRETTY_NAME")) - setVar(&prettyName, value); - else if (key == QLatin1String("ANSI_COLOR")) - setVar(&ansiColor, value); - else if (key == QLatin1String("CPE_NAME")) - setVar(&cpeName, value); - else if (key == QLatin1String("HOME_URL")) - setVar(&homeUrl, value); - else if (key == QLatin1String("SUPPORT_URL")) - setVar(&supportUrl, value); - else if (key == QLatin1String("BUG_REPORT_URL")) - setVar(&bugReportUrl, value); - else if (key == QLatin1String("BUILD_ID")) - setVar(&buildId, value); + } + // os-release explicitly allows for vendor specific aditions. We have no // interest in those right now. } } + +QString OSRelease::defaultFilePath() +{ + if (QFile::exists(QStringLiteral("/etc/os-release"))) { + return QStringLiteral("/etc/os-release"); + } else if (QFile::exists(QStringLiteral("/usr/lib/os-release"))) { + return QStringLiteral("/usr/lib/os-release"); + } else { + return QString(); + } +} diff --git a/Modules/about-distro/src/OSRelease.h b/Modules/about-distro/src/OSRelease.h index 797b908..731ba51 100644 --- a/Modules/about-distro/src/OSRelease.h +++ b/Modules/about-distro/src/OSRelease.h @@ -1,47 +1,56 @@ /* - Copyright (C) 2014 Harald Sitter + Copyright (C) 2014-2019 Harald Sitter This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef OSRELEASE_H #define OSRELEASE_H #include #include class OSRelease { public: - OSRelease(); + OSRelease(const QString &filePath = defaultFilePath()); + + static QString defaultFilePath(); QString name; QString version; QString id; QStringList idLike; + QString versionCodename; QString versionId; QString prettyName; QString ansiColor; QString cpeName; // TODO: url struct or map? QString homeUrl; + QString documentationUrl; QString supportUrl; QString bugReportUrl; + QString privacyPolicyUrl; + QString buildId; + QString variant; + QString variantId; + QString logo; }; #endif // OSRELEASE_H