File indexing completed on 2024-05-19 15:45:21

0001 // SPDX-FileCopyrightText: 2022 Gleb Popov <arrowd@FreeBSD.org>
0002 // SPDX-License-Identifier: BSD-3-Clause
0003 
0004 #include "test_craftruntime.h"
0005 
0006 #include <QFile>
0007 #include <QProcess>
0008 #include <QStandardPaths>
0009 #include <QTest>
0010 
0011 #include <KIO/CopyJob>
0012 #include <KProcess>
0013 
0014 #include <tests/testcore.h>
0015 #include <tests/testhelpers.h>
0016 
0017 #include "../craftruntime.h"
0018 
0019 using namespace KDevelop;
0020 
0021 QTEST_MAIN(CraftRuntimeTest)
0022 
0023 class TempDirWrapper
0024 {
0025 public:
0026     TempDirWrapper() = default;
0027     TempDirWrapper(const QString& craftRoot, const QString& pythonExecutable)
0028         : m_tempCraftRoot(new QTemporaryDir())
0029     {
0030         QVERIFY(m_tempCraftRoot->isValid());
0031         copyCraftRoot(craftRoot);
0032         m_runtime = std::make_shared<CraftRuntime>(m_tempCraftRoot->path(), pythonExecutable);
0033     }
0034 
0035     QString path() const
0036     {
0037         QVERIFY_RETURN(m_tempCraftRoot, QString());
0038         return m_tempCraftRoot->path();
0039     }
0040 
0041     CraftRuntime* operator->() const
0042     {
0043         QVERIFY_RETURN(m_runtime, nullptr);
0044         return m_runtime.get();
0045     }
0046 
0047 private:
0048     void copyCraftRoot(const QString& oldRoot) const
0049     {
0050         const QLatin1String craftSettingsRelativePath("/etc/CraftSettings.ini");
0051         const QDir dest(m_tempCraftRoot->path());
0052 
0053         auto* job = KIO::copy(QUrl::fromLocalFile(oldRoot + QLatin1String("/craft")), QUrl::fromLocalFile(dest.path()));
0054         QVERIFY(job->exec());
0055 
0056         QVERIFY(dest.mkpath(QLatin1String("bin")));
0057         QVERIFY(dest.mkpath(QLatin1String("etc")));
0058 
0059         QVERIFY(QFile::copy(oldRoot + craftSettingsRelativePath, dest.path() + craftSettingsRelativePath));
0060     }
0061     std::shared_ptr<CraftRuntime> m_runtime;
0062     std::shared_ptr<QTemporaryDir> m_tempCraftRoot;
0063 };
0064 
0065 Q_DECLARE_METATYPE(TempDirWrapper)
0066 
0067 // When this test itself is ran under a Craft root, its environment gets in the way
0068 static void breakoutFromCraftRoot()
0069 {
0070     auto craftRoot = qgetenv("KDEROOT");
0071     if (craftRoot.isEmpty())
0072         return;
0073 
0074     auto paths = qgetenv("PATH").split(':');
0075     std::remove_if(paths.begin(), paths.end(), [craftRoot](const QByteArray& path) {
0076         return path.startsWith(craftRoot);
0077     });
0078     qputenv("PATH", paths.join(':'));
0079 
0080     qunsetenv("KDEROOT");
0081     qunsetenv("craftRoot");
0082 }
0083 
0084 void CraftRuntimeTest::initTestCase_data()
0085 {
0086     breakoutFromCraftRoot();
0087 
0088     const QString pythonExecutable = CraftRuntime::findPython();
0089     if (pythonExecutable.isEmpty())
0090         QSKIP("No python found, skipping kdevcraft tests.");
0091 
0092     QTest::addColumn<TempDirWrapper>("runtimeInstance");
0093 
0094     QTest::newRow("Mock") << TempDirWrapper(QStringLiteral(CRAFT_ROOT_MOCK), pythonExecutable);
0095 
0096     auto craftRoot = CraftRuntime::findCraftRoot(Path(QStringLiteral(".")));
0097     if (!craftRoot.isEmpty())
0098         QTest::newRow("Real") << TempDirWrapper(craftRoot, pythonExecutable);
0099 }
0100 
0101 void CraftRuntimeTest::testFindCraftRoot()
0102 {
0103     QFETCH_GLOBAL(TempDirWrapper, runtimeInstance);
0104     QCOMPARE(CraftRuntime::findCraftRoot(Path(runtimeInstance.path())), runtimeInstance.path());
0105     QCOMPARE(CraftRuntime::findCraftRoot(Path(runtimeInstance.path()).cd(QStringLiteral("bin"))),
0106              runtimeInstance.path());
0107 }
0108 
0109 void CraftRuntimeTest::testGetenv()
0110 {
0111     QFETCH_GLOBAL(TempDirWrapper, runtimeInstance);
0112 
0113     QVERIFY(!runtimeInstance->getenv("KDEROOT").isEmpty());
0114 
0115     QDir craftDir1 = QDir(QString::fromLocal8Bit(runtimeInstance->getenv("KDEROOT")));
0116     QDir craftDir2 = QDir(runtimeInstance.path());
0117     QCOMPARE(craftDir1.canonicalPath(), craftDir2.canonicalPath());
0118 
0119     QString pythonpathValue = QString::fromLocal8Bit(runtimeInstance->getenv("PYTHONPATH"));
0120     QVERIFY(!pythonpathValue.isEmpty());
0121     QDir craftPythonPathDir = QDir(pythonpathValue);
0122 
0123     QVERIFY(craftPythonPathDir.path().startsWith(craftDir1.path()));
0124 }
0125 
0126 void CraftRuntimeTest::testStartProcess()
0127 {
0128     QFETCH_GLOBAL(TempDirWrapper, runtimeInstance);
0129 
0130     QString envPath = QStandardPaths::findExecutable(QStringLiteral("env"));
0131     if (envPath.isEmpty())
0132         QSKIP("Skipping startProcess() test, no \"env\" executable found");
0133 
0134     QString envUnderCraftPath = runtimeInstance.path() + QStringLiteral("/bin/env");
0135     QVERIFY(QFile::copy(envPath, envUnderCraftPath));
0136 
0137     QProcess p;
0138     p.setProgram(QStringLiteral("env"));
0139     runtimeInstance->startProcess(&p);
0140 
0141     // test that CraftRuntime::startProcess prefers programs under Craft root
0142     QCOMPARE(QDir(p.program()).canonicalPath(), QDir(envUnderCraftPath).canonicalPath());
0143 
0144     p.waitForFinished();
0145     QVERIFY(QFile::remove(envUnderCraftPath));
0146 }
0147 
0148 void CraftRuntimeTest::testStartProcessEnv()
0149 {
0150     QFETCH_GLOBAL(TempDirWrapper, runtimeInstance);
0151 
0152     QString printenvPath = QStandardPaths::findExecutable(QStringLiteral("printenv"));
0153     if (printenvPath.isEmpty())
0154         QSKIP("Skipping startProcess() test, no \"printenv\" executable found");
0155 
0156     QString printenvUnderCraftPath = runtimeInstance.path() + QStringLiteral("/bin/printenv");
0157     QVERIFY(QFile::copy(printenvPath, printenvUnderCraftPath));
0158 
0159     KProcess p;
0160     p.setProgram(QStringLiteral("printenv"), QStringList{QStringLiteral("PYTHONPATH")});
0161     p.setOutputChannelMode(KProcess::OnlyStdoutChannel);
0162     runtimeInstance->startProcess(&p);
0163     p.waitForFinished();
0164 
0165     QVERIFY(p.readAllStandardOutput().contains("site-packages"));
0166 }
0167 
0168 #include "moc_test_craftruntime.cpp"