File indexing completed on 2024-04-14 15:37:32

0001 /*
0002  *  SPDX-FileCopyrightText: 2012 Alejandro Fiestas Olivares <afiestas@kde.org>
0003  *
0004  *  SPDX-License-Identifier: LGPL-2.1-or-later
0005  */
0006 
0007 #include <QObject>
0008 #include <QtTest>
0009 
0010 #include "../src/backendmanager_p.h"
0011 #include "../src/config.h"
0012 #include "../src/getconfigoperation.h"
0013 #include "../src/mode.h"
0014 #include "../src/output.h"
0015 #include "../src/screen.h"
0016 #include "../src/setconfigoperation.h"
0017 
0018 using namespace KScreen;
0019 
0020 class testScreenConfig : public QObject
0021 {
0022     Q_OBJECT
0023 
0024 private:
0025     KScreen::ConfigPtr getConfig();
0026 
0027 private Q_SLOTS:
0028     void initTestCase();
0029     void singleOutput();
0030     void singleOutputWithoutPreferred();
0031     void multiOutput();
0032     void clonesOutput();
0033     void configCanBeApplied();
0034     void supportedFeatures();
0035     void testInvalidMode();
0036     void cleanupTestCase();
0037     void testOutputPositionNormalization();
0038 };
0039 
0040 ConfigPtr testScreenConfig::getConfig()
0041 {
0042     qputenv("KSCREEN_BACKEND_INPROCESS", "1");
0043     auto *op = new GetConfigOperation();
0044     if (!op->exec()) {
0045         qWarning("ConfigOperation error: %s", qPrintable(op->errorString()));
0046         BackendManager::instance()->shutdownBackend();
0047         return ConfigPtr();
0048     }
0049 
0050     BackendManager::instance()->shutdownBackend();
0051 
0052     return op->config();
0053 }
0054 
0055 void testScreenConfig::initTestCase()
0056 {
0057     qputenv("KSCREEN_LOGGING", "false");
0058     qputenv("KSCREEN_BACKEND", "Fake");
0059 }
0060 
0061 void testScreenConfig::cleanupTestCase()
0062 {
0063     BackendManager::instance()->shutdownBackend();
0064 }
0065 
0066 void testScreenConfig::singleOutput()
0067 {
0068     // json file for the fake backend
0069     KScreen::BackendManager::instance()->setBackendArgs(
0070         {{QStringLiteral("TEST_DATA"), TEST_DATA "singleoutput.json"},
0071          {QStringLiteral("SUPPORTED_FEATURES"), QVariant::fromValue(KScreen::Config::Feature::PerOutputScaling)}});
0072 
0073     //     QVERIFY2(kscreen, KScreen::errorString().toLatin1());
0074 
0075     //     QVERIFY2(!kscreen->backend().isEmpty(), "No backend loaded");
0076 
0077     const ConfigPtr config = getConfig();
0078     QVERIFY(!config.isNull());
0079     const ScreenPtr screen = config->screen();
0080     QVERIFY(!screen.isNull());
0081 
0082     QCOMPARE(screen->minSize(), QSize(320, 200));
0083     QCOMPARE(screen->maxSize(), QSize(8192, 8192));
0084     QCOMPARE(screen->currentSize(), QSize(1280, 800));
0085 
0086     QCOMPARE(config->outputs().count(), 1);
0087 
0088     const OutputPtr output = config->outputs().take(1);
0089     QVERIFY(!output.isNull());
0090 
0091     QCOMPARE(output->name(), QLatin1String("LVDS1"));
0092     QCOMPARE(output->type(), Output::Panel);
0093     QCOMPARE(output->modes().count(), 3);
0094     QCOMPARE(output->pos(), QPoint(0, 0));
0095     QCOMPARE(output->geometry(), QRect(0, 0, 1280, 800));
0096     QCOMPARE(output->currentModeId(), QLatin1String("3"));
0097     QCOMPARE(output->preferredModeId(), QLatin1String("3"));
0098     QCOMPARE(output->rotation(), Output::None);
0099     QCOMPARE(output->scale(), 1.0);
0100     QCOMPARE(output->isConnected(), true);
0101     QCOMPARE(output->isEnabled(), true);
0102     QCOMPARE(output->isPrimary(), true);
0103     // QCOMPARE(output->isEmbedded(), true);
0104     QVERIFY2(output->clones().isEmpty(), "In singleOutput is impossible to have clones");
0105 
0106     const ModePtr mode = output->currentMode();
0107     QCOMPARE(mode->size(), QSize(1280, 800));
0108     QCOMPARE(mode->refreshRate(), (float)59.9);
0109 }
0110 
0111 void testScreenConfig::singleOutputWithoutPreferred()
0112 {
0113     KScreen::BackendManager::instance()->setBackendArgs({{QStringLiteral("TEST_DATA"), TEST_DATA "singleOutputWithoutPreferred.json"}});
0114 
0115     const ConfigPtr config = getConfig();
0116     QVERIFY(!config.isNull());
0117     const OutputPtr output = config->outputs().take(1);
0118     QVERIFY(!output.isNull());
0119 
0120     QVERIFY(output->preferredModes().isEmpty());
0121     QCOMPARE(output->preferredModeId(), QLatin1String("3"));
0122 }
0123 
0124 void testScreenConfig::multiOutput()
0125 {
0126     KScreen::BackendManager::instance()->setBackendArgs(
0127         {{QStringLiteral("TEST_DATA"), TEST_DATA "multipleoutput.json"},
0128          {QStringLiteral("SUPPORTED_FEATURES"), QVariant::fromValue(KScreen::Config::Feature::PerOutputScaling)}});
0129 
0130     const ConfigPtr config = getConfig();
0131     QVERIFY(!config.isNull());
0132     const ScreenPtr screen = config->screen();
0133     QVERIFY(!screen.isNull());
0134 
0135     QCOMPARE(screen->minSize(), QSize(320, 200));
0136     QCOMPARE(screen->maxSize(), QSize(8192, 8192));
0137     QCOMPARE(screen->currentSize(), QSize(3200, 1880));
0138 
0139     QCOMPARE(config->outputs().count(), 2);
0140 
0141     const OutputPtr output = config->outputs().take(2);
0142     QVERIFY(!output.isNull());
0143 
0144     QCOMPARE(output->name(), QStringLiteral("HDMI1"));
0145     QCOMPARE(output->type(), Output::HDMI);
0146     QCOMPARE(output->modes().count(), 4);
0147     QCOMPARE(output->pos(), QPoint(1280, 0));
0148     QCOMPARE(output->geometry(), QRect(1280, 0, 1920 / 1.4, 1080 / 1.4));
0149     QCOMPARE(output->currentModeId(), QLatin1String("4"));
0150     QCOMPARE(output->preferredModeId(), QLatin1String("4"));
0151     QCOMPARE(output->rotation(), Output::None);
0152     QCOMPARE(output->scale(), 1.4);
0153     QCOMPARE(output->isConnected(), true);
0154     QCOMPARE(output->isEnabled(), true);
0155     QCOMPARE(output->isPrimary(), false);
0156     QVERIFY2(output->clones().isEmpty(), "This simulates extended output, no clones");
0157 
0158     const ModePtr mode = output->currentMode();
0159     QVERIFY(!mode.isNull());
0160     QCOMPARE(mode->size(), QSize(1920, 1080));
0161     QCOMPARE(mode->refreshRate(), (float)60.0);
0162 }
0163 
0164 void testScreenConfig::clonesOutput()
0165 {
0166     KScreen::BackendManager::instance()->setBackendArgs({{QStringLiteral("TEST_DATA"), TEST_DATA "multipleclone.json"}});
0167 
0168     const ConfigPtr config = getConfig();
0169     QVERIFY(!config.isNull());
0170     const ScreenPtr screen = config->screen();
0171     QVERIFY(!screen.isNull());
0172 
0173     QCOMPARE(screen->minSize(), QSize(320, 200));
0174     QCOMPARE(screen->maxSize(), QSize(8192, 8192));
0175     QCOMPARE(screen->currentSize(), QSize(1024, 768));
0176 
0177     const OutputPtr one = config->outputs()[1];
0178     const OutputPtr two = config->outputs()[2];
0179 
0180     QCOMPARE(one->currentMode()->size(), two->currentMode()->size());
0181     QCOMPARE(one->clones().count(), 1);
0182     QCOMPARE(one->clones().first(), two->id());
0183     QVERIFY2(two->clones().isEmpty(), "Output two should have no clones");
0184 }
0185 
0186 void testScreenConfig::configCanBeApplied()
0187 {
0188     KScreen::BackendManager::instance()->setBackendArgs({{QStringLiteral("TEST_DATA"), TEST_DATA "singleoutputBroken.json"}});
0189 
0190     const ConfigPtr brokenConfig = getConfig();
0191 
0192     KScreen::BackendManager::instance()->setBackendArgs({{QStringLiteral("TEST_DATA"), TEST_DATA "singleoutput.json"}});
0193 
0194     const ConfigPtr currentConfig = getConfig();
0195     QVERIFY(!currentConfig.isNull());
0196     const OutputPtr primaryBroken = brokenConfig->outputs()[2];
0197     QVERIFY(!primaryBroken.isNull());
0198     const OutputPtr currentPrimary = currentConfig->outputs()[1];
0199     QVERIFY(!currentPrimary.isNull());
0200 
0201     QVERIFY(!Config::canBeApplied(brokenConfig));
0202     primaryBroken->setId(currentPrimary->id());
0203     QVERIFY(!Config::canBeApplied(brokenConfig));
0204     primaryBroken->setConnected(currentPrimary->isConnected());
0205     QVERIFY(!Config::canBeApplied(brokenConfig));
0206     primaryBroken->setCurrentModeId(QStringLiteral("42"));
0207     QVERIFY(!Config::canBeApplied(brokenConfig));
0208     primaryBroken->setCurrentModeId(currentPrimary->currentModeId());
0209     QVERIFY(!Config::canBeApplied(brokenConfig));
0210     qDebug() << "brokenConfig.modes" << primaryBroken->mode(QStringLiteral("3"));
0211     primaryBroken->mode(QStringLiteral("3"))->setSize(QSize(1280, 800));
0212     qDebug() << "brokenConfig.modes" << primaryBroken->mode(QStringLiteral("3"));
0213     QVERIFY(Config::canBeApplied(brokenConfig));
0214 
0215     KScreen::BackendManager::instance()->setBackendArgs({{QStringLiteral("TEST_DATA"), TEST_DATA "tooManyOutputs.json"}});
0216 
0217     const ConfigPtr brokenConfig2 = getConfig();
0218     QVERIFY(!brokenConfig2.isNull());
0219 
0220     int enabledOutputsCount = 0;
0221     for (const OutputPtr &output : brokenConfig2->outputs()) {
0222         if (output->isEnabled()) {
0223             ++enabledOutputsCount;
0224         }
0225     }
0226     QVERIFY(brokenConfig2->screen()->maxActiveOutputsCount() < enabledOutputsCount);
0227     QVERIFY(!Config::canBeApplied(brokenConfig2));
0228 
0229     const ConfigPtr nulllConfig;
0230     QVERIFY(!Config::canBeApplied(nulllConfig));
0231 }
0232 
0233 void testScreenConfig::supportedFeatures()
0234 {
0235     ConfigPtr config = getConfig();
0236 
0237     QVERIFY(config->supportedFeatures().testFlag(KScreen::Config::Feature::None));
0238     QVERIFY(!config->supportedFeatures().testFlag(KScreen::Config::Feature::Writable));
0239     QVERIFY(!config->supportedFeatures().testFlag(KScreen::Config::Feature::PrimaryDisplay));
0240     QVERIFY(!config->supportedFeatures().testFlag(KScreen::Config::Feature::PerOutputScaling));
0241 
0242     config->setSupportedFeatures(KScreen::Config::Feature::Writable | KScreen::Config::Feature::PrimaryDisplay);
0243     QVERIFY(config->supportedFeatures().testFlag(KScreen::Config::Feature::Writable));
0244     QVERIFY(config->supportedFeatures().testFlag(KScreen::Config::Feature::PrimaryDisplay));
0245 
0246     config->setSupportedFeatures(KScreen::Config::Feature::None);
0247     QVERIFY(config->supportedFeatures().testFlag(KScreen::Config::Feature::None));
0248 
0249     config->setSupportedFeatures(KScreen::Config::Feature::PerOutputScaling | KScreen::Config::Feature::Writable);
0250     QVERIFY(!config->supportedFeatures().testFlag(KScreen::Config::Feature::None));
0251     QVERIFY(config->supportedFeatures().testFlag(KScreen::Config::Feature::Writable));
0252     QVERIFY(config->supportedFeatures().testFlag(KScreen::Config::Feature::PerOutputScaling));
0253 
0254     config->setSupportedFeatures(KScreen::Config::Feature::PerOutputScaling | KScreen::Config::Feature::Writable | KScreen::Config::Feature::PrimaryDisplay);
0255     QVERIFY(!config->supportedFeatures().testFlag(KScreen::Config::Feature::None));
0256     QVERIFY(config->supportedFeatures().testFlag(KScreen::Config::Feature::Writable));
0257     QVERIFY(config->supportedFeatures().testFlag(KScreen::Config::Feature::PrimaryDisplay));
0258     QVERIFY(config->supportedFeatures().testFlag(KScreen::Config::Feature::PerOutputScaling));
0259 }
0260 
0261 void testScreenConfig::testInvalidMode()
0262 {
0263     ModeList modes;
0264     ModePtr invalidMode = modes.value(QStringLiteral("99"));
0265     QVERIFY(invalidMode.isNull());
0266 
0267     auto output = new KScreen::Output();
0268     auto currentMode = output->currentMode();
0269     QVERIFY(currentMode.isNull());
0270     QVERIFY(!currentMode);
0271     delete output;
0272 }
0273 
0274 void testScreenConfig::testOutputPositionNormalization()
0275 {
0276     KScreen::BackendManager::instance()->setBackendArgs({{QStringLiteral("TEST_DATA"), TEST_DATA "multipleoutput.json"}});
0277 
0278     const ConfigPtr config = getConfig();
0279     QVERIFY(!config.isNull());
0280     auto left = config->outputs().first();
0281     auto right = config->outputs().last();
0282     QVERIFY(!left.isNull());
0283     QVERIFY(!right.isNull());
0284     left->setPos(QPoint(-5000, 700));
0285     right->setPos(QPoint(-3720, 666));
0286     QCOMPARE(left->pos(), QPoint(-5000, 700));
0287     QCOMPARE(right->pos(), QPoint(-3720, 666));
0288 
0289     // start a set operation to fix up the positions
0290     {
0291         auto setop = new SetConfigOperation(config);
0292         setop->exec();
0293     }
0294     QCOMPARE(left->pos(), QPoint(0, 34));
0295     QCOMPARE(right->pos(), QPoint(1280, 0));
0296 
0297     // make sure it doesn't touch a valid config
0298     {
0299         auto setop = new SetConfigOperation(config);
0300         setop->exec();
0301     }
0302     QCOMPARE(left->pos(), QPoint(0, 34));
0303     QCOMPARE(right->pos(), QPoint(1280, 0));
0304 
0305     // positions of single outputs should be at 0, 0
0306     left->setEnabled(false);
0307     {
0308         auto setop = new SetConfigOperation(config);
0309         setop->exec();
0310     }
0311     QCOMPARE(right->pos(), QPoint());
0312 }
0313 
0314 QTEST_MAIN(testScreenConfig)
0315 
0316 #include "testscreenconfig.moc"