File indexing completed on 2024-04-28 03:53:14

0001 /*  This file is part of the KDE libraries
0002     SPDX-FileCopyrightText: 2010 Canonical Ltd
0003     SPDX-FileContributor: Aurélien Gâteau <aurelien.gateau@canonical.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 #include "test_kconf_update.h"
0008 
0009 #include <memory>
0010 
0011 // Qt
0012 #include <QDir>
0013 #include <QFile>
0014 #include <QProcess>
0015 #include <qglobal.h>
0016 #include <qstandardpaths.h>
0017 #include <qtemporaryfile.h>
0018 #include <qtest.h>
0019 #include <qtestcase.h>
0020 
0021 QTEST_GUILESS_MAIN(TestKConfUpdate)
0022 
0023 void TestKConfUpdate::initTestCase()
0024 {
0025     QStandardPaths::setTestModeEnabled(true);
0026 
0027     // Ensure it all works with spaces in paths (as happens more commonly on OSX where it's ~/Library/Application Support/)
0028     qputenv("XDG_DATA_HOME", "/tmp/a b");
0029 }
0030 
0031 static void writeFile(const QString &path, const QString &content)
0032 {
0033     QFile file(path);
0034     if (!file.open(QIODevice::WriteOnly)) {
0035         qFatal("Could not write to '%s'", qPrintable(path));
0036     }
0037     file.write(content.toUtf8());
0038 }
0039 
0040 static QString readFile(const QString &path)
0041 {
0042     QFile file(path);
0043     if (!file.open(QIODevice::ReadOnly)) {
0044         qFatal("Could not read '%s'", qPrintable(path));
0045     }
0046     QString ret = QString::fromUtf8(file.readAll());
0047 #ifdef Q_OS_WIN
0048     // KConfig always writes files with the native line ending, the test comparison uses \n
0049     ret.replace(QLatin1String{"\r\n"}, QLatin1String{"\n"});
0050 #endif
0051     return ret;
0052 }
0053 
0054 static std::unique_ptr<QTemporaryFile> writeUpdFile(const QString &content)
0055 {
0056     std::unique_ptr<QTemporaryFile> file{new QTemporaryFile(QDir::tempPath() + QLatin1String("/test_kconf_update_XXXXXX.upd"))};
0057     bool ok = file->open();
0058     Q_UNUSED(ok) // silence warnings
0059     Q_ASSERT(ok);
0060     file->write(content.toUtf8());
0061     file->flush();
0062     return file;
0063 }
0064 
0065 static void runKConfUpdate(const QString &updPath, const QString &expectedKConfOutputString)
0066 {
0067     const QString kconfUpdateExecutable = QFINDTESTDATA("kconf_update");
0068     QVERIFY(QFile::exists(kconfUpdateExecutable));
0069     QProcess p;
0070     p.start(kconfUpdateExecutable, QStringList{QStringLiteral("--testmode"), QStringLiteral("--debug"), updPath});
0071     QVERIFY(p.waitForFinished());
0072     QCOMPARE(p.exitCode(), 0);
0073     if (!expectedKConfOutputString.isEmpty()) {
0074         const QString out = QString::fromLocal8Bit(p.readAllStandardError());
0075         QVERIFY2(out.contains(expectedKConfOutputString),
0076                  qPrintable(QLatin1String("The string \"%1\" was not contained in putput \"%2\"").arg(expectedKConfOutputString, out)));
0077     }
0078 }
0079 
0080 void TestKConfUpdate::testScript_data()
0081 {
0082     QTest::addColumn<QString>("updContent");
0083     QTest::addColumn<QString>("updScript");
0084     QTest::addColumn<QString>("oldConfContent");
0085     QTest::addColumn<QString>("expectedNewConfContent");
0086     QTest::addColumn<QString>("expectedKConfOutputString");
0087 
0088 #ifdef Q_OS_FREEBSD
0089     // https://stackoverflow.com/a/69955786
0090     const QString sedCommand = QStringLiteral("sed -i '' ");
0091 #else
0092     const QString sedCommand = QStringLiteral("sed -i ");
0093 #endif
0094     const QString updVersionIdPrefix = QLatin1String("Version=6\nId=%1\n").arg(QLatin1String{QTest::currentDataTag()});
0095     const QString confPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1String{"/testrc"};
0096     const QString scriptContent = sedCommand + QLatin1String("'s/firstVal=abc/firstVal=xyz/' %1").arg(confPath);
0097 
0098     QTest::newRow("should reject script due to version missmatch")
0099         << QStringLiteral("Version=5\nId=12345") << scriptContent << QString() << QString() << QStringLiteral("defined Version=5 but Version=6 was expected");
0100 
0101     const QString updContent = updVersionIdPrefix + QLatin1String("Script=test.sh,sh\n");
0102     const QString configIn = QStringLiteral("[grp]\nfirstVal=abc\nsecondVal=xyz\n");
0103     const QString configOut = QStringLiteral("[grp]\nfirstVal=xyz\nsecondVal=xyz\n");
0104 
0105     QTest::newRow("should run command and modify file") << updContent << scriptContent << configIn << configOut << QString();
0106 
0107     const QString argScriptContent = sedCommand + QLatin1String("\"s/secondVal=$1/secondVal=abc/\" %1").arg(confPath);
0108     QTest::newRow("should run command with argument and modify file") << QStringLiteral("ScriptArguments=xyz\n") + updContent << argScriptContent << configIn
0109                                                                       << QStringLiteral("[grp]\nfirstVal=abc\nsecondVal=abc\n") << QString();
0110 
0111     QTest::newRow("should run command with arguments and modify file")
0112         << QStringLiteral("ScriptArguments=xyz abc\n") + updContent << sedCommand + QLatin1String("\"s/secondVal=$1/secondVal=$2/\" %1").arg(confPath)
0113         << configIn << QStringLiteral("[grp]\nfirstVal=abc\nsecondVal=abc\n") << QString();
0114 }
0115 
0116 void TestKConfUpdate::testScript()
0117 {
0118     if (QStandardPaths::findExecutable(QStringLiteral("sh")).isEmpty()) {
0119         QSKIP("Could not find sh executable, cannot run test");
0120         return;
0121     }
0122 
0123     QFETCH(QString, updContent);
0124     QFETCH(QString, updScript);
0125     QFETCH(QString, oldConfContent);
0126     QFETCH(QString, expectedNewConfContent);
0127     QFETCH(QString, expectedKConfOutputString);
0128 
0129     std::unique_ptr<QTemporaryFile> updFile(writeUpdFile(updContent));
0130 
0131     const QString scriptDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String{"/kconf_update"};
0132     QVERIFY(QDir().mkpath(scriptDir));
0133     const QString scriptPath = scriptDir + QLatin1String{"/test.sh"};
0134     writeFile(scriptPath, updScript);
0135     QCOMPARE(readFile(scriptPath), updScript);
0136 
0137     const QString confPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1String{"/testrc"};
0138     writeFile(confPath, oldConfContent);
0139     QCOMPARE(readFile(confPath), oldConfContent);
0140 
0141     runKConfUpdate(updFile->fileName(), expectedKConfOutputString);
0142 
0143     QCOMPARE(readFile(confPath), expectedNewConfContent);
0144 }
0145 
0146 #include "moc_test_kconf_update.cpp"