From 93194a6720a75caca42da87e43c971446b892ebb Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Mon, 21 Dec 2020 13:01:38 +0200 Subject: [PATCH] autotests: Convert testScreens into an integration test At the moment, the Screens class is convoluted with ifdefs because of MockScreens. The goal of this change is to reduce the number of usages of the MockScreens class so it is possible to get rid of the ifdefs. --- autotests/CMakeLists.txt | 36 --- autotests/integration/CMakeLists.txt | 1 + autotests/integration/screens_test.cpp | 342 ++++++++++++++++++++++++ autotests/test_screens.cpp | 345 ------------------------- 4 files changed, 343 insertions(+), 381 deletions(-) create mode 100644 autotests/integration/screens_test.cpp delete mode 100644 autotests/test_screens.cpp diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index d553e44cf5..b75c5b8954 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -240,42 +240,6 @@ add_library(effectversionplugin MODULE fakeeffectplugin_version.cpp) set_target_properties(effectversionplugin PROPERTIES PREFIX "") target_link_libraries(effectversionplugin kwineffects) -######################################################## -# Test Screens -######################################################## -set(testScreens_SRCS - ../screens.cpp - ../cursor.cpp - ../x11eventfilter.cpp - mock_abstract_client.cpp - mock_screens.cpp - mock_workspace.cpp - mock_x11client.cpp - test_screens.cpp -) -kconfig_add_kcfg_files(testScreens_SRCS ../settings.kcfgc) - -add_executable(testScreens ${testScreens_SRCS}) -target_include_directories(testScreens BEFORE PRIVATE ./) -target_link_libraries(testScreens - Qt5::DBus - Qt5::Sensors - Qt5::Test - Qt5::Widgets - Qt5::X11Extras - - KF5::ConfigCore - KF5::ConfigGui - KF5::I18n - KF5::Notifications - KF5::WindowSystem - - XCB::XCB #for xcbutils.h -) - -add_test(NAME kwin_testScreens COMMAND testScreens) -ecm_mark_as_test(testScreens) - ######################################################## # Test ScreenEdges ######################################################## diff --git a/autotests/integration/CMakeLists.txt b/autotests/integration/CMakeLists.txt index 22437ed509..a1d1bbec05 100644 --- a/autotests/integration/CMakeLists.txt +++ b/autotests/integration/CMakeLists.txt @@ -96,6 +96,7 @@ integrationTest(WAYLAND_ONLY NAME testBufferSizeChange SRCS buffer_size_change_t integrationTest(WAYLAND_ONLY NAME testPlacement SRCS placement_test.cpp) integrationTest(WAYLAND_ONLY NAME testActivation SRCS activation_test.cpp) integrationTest(WAYLAND_ONLY NAME testInputMethod SRCS inputmethod_test.cpp) +integrationTest(WAYLAND_ONLY NAME testScreens SRCS screens_test.cpp) if (KWIN_BUILD_CMS) integrationTest(WAYLAND_ONLY NAME testNightColor SRCS nightcolor_test.cpp LIBS KWinNightColorPlugin) diff --git a/autotests/integration/screens_test.cpp b/autotests/integration/screens_test.cpp new file mode 100644 index 0000000000..1762776b3f --- /dev/null +++ b/autotests/integration/screens_test.cpp @@ -0,0 +1,342 @@ +/* + KWin - the KDE window manager + This file is part of the KDE project. + + SPDX-FileCopyrightText: 2014 Martin Gräßlin + + SPDX-License-Identifier: GPL-2.0-or-later +*/ +#include "kwin_wayland_test.h" +#include "abstract_client.h" +#include "cursor.h" +#include "platform.h" +#include "screens.h" +#include "wayland_server.h" +#include "workspace.h" + +#include +#include +#include + +namespace KWin +{ + +static const QString s_socketName = QStringLiteral("wayland_test_kwin_screens-0"); + +class ScreensTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void init(); + void cleanup(); + void testCurrentFollowsMouse(); + void testReconfigure_data(); + void testReconfigure(); + void testSize_data(); + void testSize(); + void testCount(); + void testIntersecting_data(); + void testIntersecting(); + void testCurrent_data(); + void testCurrent(); + void testCurrentClient(); + void testCurrentWithFollowsMouse_data(); + void testCurrentWithFollowsMouse(); + void testCurrentPoint_data(); + void testCurrentPoint(); +}; + +void ScreensTest::initTestCase() +{ + qRegisterMetaType(); + QSignalSpy applicationStartedSpy(kwinApp(), &Application::started); + QVERIFY(applicationStartedSpy.isValid()); + kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024)); + QVERIFY(waylandServer()->init(s_socketName)); + QMetaObject::invokeMethod(kwinApp()->platform(), "setVirtualOutputs", Qt::DirectConnection, Q_ARG(int, 2)); + + kwinApp()->start(); + QVERIFY(applicationStartedSpy.wait()); + QCOMPARE(screens()->count(), 2); + QCOMPARE(screens()->geometry(0), QRect(0, 0, 1280, 1024)); + QCOMPARE(screens()->geometry(1), QRect(1280, 0, 1280, 1024)); + waylandServer()->initWorkspace(); +} + +void ScreensTest::init() +{ + Screens::self()->setCurrent(0); + KWin::Cursors::self()->mouse()->setPos(QPoint(640, 512)); + + QVERIFY(Test::setupWaylandConnection()); +} + +static void purge(KConfig *config) +{ + const QStringList groups = config->groupList(); + for (const QString &group : groups) { + config->deleteGroup(group); + } +} + +void ScreensTest::cleanup() +{ + // Destroy the wayland connection of the test client. + Test::destroyWaylandConnection(); + + // Wipe the screens config clean. + auto config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); + purge(config.data()); + config->sync(); + screens()->setConfig(config); + screens()->reconfigure(); + + // Reset the screen layout of the test environment. + QMetaObject::invokeMethod(kwinApp()->platform(), "setVirtualOutputs", Qt::DirectConnection, Q_ARG(int, 2)); +} + +void ScreensTest::testCurrentFollowsMouse() +{ + QVERIFY(!screens()->isCurrentFollowsMouse()); + screens()->setCurrentFollowsMouse(true); + QVERIFY(screens()->isCurrentFollowsMouse()); + // setting to same should not do anything + screens()->setCurrentFollowsMouse(true); + QVERIFY(screens()->isCurrentFollowsMouse()); + + // setting back to other value + screens()->setCurrentFollowsMouse(false); + QVERIFY(!screens()->isCurrentFollowsMouse()); + // setting to same should not do anything + screens()->setCurrentFollowsMouse(false); + QVERIFY(!screens()->isCurrentFollowsMouse()); +} + +void ScreensTest::testReconfigure_data() +{ + QTest::addColumn("focusPolicy"); + QTest::addColumn("expectedDefault"); + QTest::addColumn("setting"); + + QTest::newRow("ClickToFocus") << QStringLiteral("ClickToFocus") << false << true; + QTest::newRow("FocusFollowsMouse") << QStringLiteral("FocusFollowsMouse") << true << false; + QTest::newRow("FocusUnderMouse") << QStringLiteral("FocusUnderMouse") << true << false; + QTest::newRow("FocusStrictlyUnderMouse") << QStringLiteral("FocusStrictlyUnderMouse") << true << false; +} + +void ScreensTest::testReconfigure() +{ + screens()->reconfigure(); + QVERIFY(!screens()->isCurrentFollowsMouse()); + + QFETCH(QString, focusPolicy); + + KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); + config->group("Windows").writeEntry("FocusPolicy", focusPolicy); + config->group("Windows").sync(); + config->sync(); + + screens()->setConfig(config); + screens()->reconfigure(); + QTEST(screens()->isCurrentFollowsMouse(), "expectedDefault"); + + QFETCH(bool, setting); + config->group("Windows").writeEntry("ActiveMouseScreen", setting); + config->sync(); + screens()->reconfigure(); + QCOMPARE(screens()->isCurrentFollowsMouse(), setting); +} + +void ScreensTest::testSize_data() +{ + QTest::addColumn>("geometries"); + QTest::addColumn("expectedSize"); + + QTest::newRow("empty") << QVector{{QRect()}} << QSize(0, 0); + QTest::newRow("cloned") << QVector{{QRect{0, 0, 200, 100}, QRect{0, 0, 200, 100}}} << QSize(200, 100); + QTest::newRow("adjacent") << QVector{{QRect{0, 0, 200, 100}, QRect{200, 100, 400, 300}}} << QSize(600, 400); + QTest::newRow("overlapping") << QVector{{QRect{-10, -20, 50, 100}, QRect{0, 0, 100, 200}}} << QSize(110, 220); + QTest::newRow("gap") << QVector{{QRect{0, 0, 10, 20}, QRect{20, 40, 10, 20}}} << QSize(30, 60); +} + +void ScreensTest::testSize() +{ + QSignalSpy sizeChangedSpy(screens(), &Screens::sizeChanged); + QVERIFY(sizeChangedSpy.isValid()); + + QFETCH(QVector, geometries); + QMetaObject::invokeMethod(kwinApp()->platform(), "setVirtualOutputs", Qt::QueuedConnection, + Q_ARG(int, geometries.count()), Q_ARG(QVector, geometries)); + + QVERIFY(sizeChangedSpy.wait()); + QTEST(screens()->size(), "expectedSize"); +} + +void ScreensTest::testCount() +{ + QSignalSpy countChangedSpy(screens(), &Screens::countChanged); + QVERIFY(countChangedSpy.isValid()); + + // the test environments has two outputs + QCOMPARE(screens()->count(), 2); + + // change to one screen + QMetaObject::invokeMethod(kwinApp()->platform(), "setVirtualOutputs", Qt::QueuedConnection, Q_ARG(int, 1)); + QVERIFY(countChangedSpy.wait()); + QCOMPARE(countChangedSpy.count(), 1); + QCOMPARE(screens()->count(), 1); + + // setting the same geometries shouldn't emit the signal, but we should get a changed signal + QSignalSpy changedSpy(screens(), &Screens::changed); + QVERIFY(changedSpy.isValid()); + QMetaObject::invokeMethod(kwinApp()->platform(), "setVirtualOutputs", Qt::QueuedConnection, Q_ARG(int, 1)); + QVERIFY(changedSpy.wait()); + QCOMPARE(countChangedSpy.count(), 1); +} + +void ScreensTest::testIntersecting_data() +{ + QTest::addColumn>("geometries"); + QTest::addColumn("testGeometry"); + QTest::addColumn("expectedCount"); + + QTest::newRow("null-rect") << QVector{{QRect{0, 0, 100, 100}}} << QRect() << 0; + QTest::newRow("non-overlapping") << QVector{{QRect{0, 0, 100, 100}}} << QRect(100, 0, 100, 100) << 0; + QTest::newRow("in-between") << QVector{{QRect{0, 0, 10, 20}, QRect{20, 40, 10, 20}}} << QRect(15, 0, 2, 2) << 0; + QTest::newRow("gap-overlapping") << QVector{{QRect{0, 0, 10, 20}, QRect{20, 40, 10, 20}}} << QRect(9, 10, 200, 200) << 2; + QTest::newRow("larger") << QVector{{QRect{0, 0, 100, 100}}} << QRect(-10, -10, 200, 200) << 1; + QTest::newRow("several") << QVector{{QRect{0, 0, 100, 100}, QRect{100, 0, 100, 100}, QRect{200, 100, 100, 100}, QRect{300, 100, 100, 100}}} << QRect(0, 0, 300, 300) << 3; +} + +void ScreensTest::testIntersecting() +{ + QSignalSpy changedSpy(screens(), &Screens::changed); + QVERIFY(changedSpy.isValid()); + + QFETCH(QVector, geometries); + QMetaObject::invokeMethod(kwinApp()->platform(), "setVirtualOutputs", Qt::QueuedConnection, + Q_ARG(int, geometries.count()), Q_ARG(QVector, geometries)); + QVERIFY(changedSpy.wait()); + + QFETCH(QRect, testGeometry); + QCOMPARE(screens()->count(), geometries.count()); + QTEST(screens()->intersecting(testGeometry), "expectedCount"); +} + +void ScreensTest::testCurrent_data() +{ + QTest::addColumn("current"); + QTest::addColumn("signal"); + + QTest::newRow("unchanged") << 0 << false; + QTest::newRow("changed") << 1 << true; +} + +void ScreensTest::testCurrent() +{ + QSignalSpy currentChangedSpy(screens(), &KWin::Screens::currentChanged); + QVERIFY(currentChangedSpy.isValid()); + + QFETCH(int, current); + screens()->setCurrent(current); + QCOMPARE(screens()->current(), current); + QTEST(!currentChangedSpy.isEmpty(), "signal"); +} + +void ScreensTest::testCurrentClient() +{ + QSignalSpy currentChangedSpy(screens(), &Screens::currentChanged); + QVERIFY(currentChangedSpy.isValid()); + + // create a test window + QScopedPointer surface(Test::createSurface()); + QScopedPointer shellSurface(Test::createXdgShellStableSurface(surface.data())); + AbstractClient *client = Test::renderAndWaitForShown(surface.data(), QSize(200, 100), Qt::red); + QVERIFY(client); + QVERIFY(client->isActive()); + + // if the window is sent to another screen, that screen will become current + client->sendToScreen(1); + QCOMPARE(currentChangedSpy.count(), 1); + QCOMPARE(screens()->current(), 1); + + // setting current with the same client again should not change + screens()->setCurrent(client); + QCOMPARE(currentChangedSpy.count(), 1); + + // and it should even still be on screen 1 if we make the client non-current again + workspace()->setActiveClient(nullptr); + client->setActive(false); + QCOMPARE(screens()->current(), 1); + + // it's not the active client, so changing won't work + screens()->setCurrent(client); + client->sendToScreen(0); + QCOMPARE(currentChangedSpy.count(), 1); + QCOMPARE(screens()->current(), 1); +} + +void ScreensTest::testCurrentWithFollowsMouse_data() +{ + QTest::addColumn>("geometries"); + QTest::addColumn("cursorPos"); + QTest::addColumn("expected"); + + QTest::newRow("empty") << QVector{{QRect()}} << QPoint(100, 100) << 0; + QTest::newRow("cloned") << QVector{{QRect{0, 0, 200, 100}, QRect{0, 0, 200, 100}}} << QPoint(50, 50) << 0; + QTest::newRow("adjacent-0") << QVector{{QRect{0, 0, 200, 100}, QRect{200, 100, 400, 300}}} << QPoint(199, 99) << 0; + QTest::newRow("adjacent-1") << QVector{{QRect{0, 0, 200, 100}, QRect{200, 100, 400, 300}}} << QPoint(200, 100) << 1; + QTest::newRow("gap") << QVector{{QRect{0, 0, 10, 20}, QRect{20, 40, 10, 20}}} << QPoint(15, 30) << 1; +} + +void ScreensTest::testCurrentWithFollowsMouse() +{ + QSignalSpy changedSpy(screens(), &Screens::changed); + QVERIFY(changedSpy.isValid()); + screens()->setCurrentFollowsMouse(true); + QCOMPARE(screens()->current(), 0); + + QFETCH(QVector, geometries); + QMetaObject::invokeMethod(kwinApp()->platform(), "setVirtualOutputs", Qt::QueuedConnection, + Q_ARG(int, geometries.count()), Q_ARG(QVector, geometries)); + QVERIFY(changedSpy.wait()); + + QFETCH(QPoint, cursorPos); + KWin::Cursors::self()->mouse()->setPos(cursorPos); + QTEST(screens()->current(), "expected"); +} + +void ScreensTest::testCurrentPoint_data() +{ + QTest::addColumn>("geometries"); + QTest::addColumn("cursorPos"); + QTest::addColumn("expected"); + + QTest::newRow("empty") << QVector{{QRect()}} << QPoint(100, 100) << 0; + QTest::newRow("cloned") << QVector{{QRect{0, 0, 200, 100}, QRect{0, 0, 200, 100}}} << QPoint(50, 50) << 0; + QTest::newRow("adjacent-0") << QVector{{QRect{0, 0, 200, 100}, QRect{200, 100, 400, 300}}} << QPoint(199, 99) << 0; + QTest::newRow("adjacent-1") << QVector{{QRect{0, 0, 200, 100}, QRect{200, 100, 400, 300}}} << QPoint(200, 100) << 1; + QTest::newRow("gap") << QVector{{QRect{0, 0, 10, 20}, QRect{20, 40, 10, 20}}} << QPoint(15, 30) << 1; +} + +void ScreensTest::testCurrentPoint() +{ + QSignalSpy changedSpy(screens(), &KWin::Screens::changed); + QVERIFY(changedSpy.isValid()); + + QFETCH(QVector, geometries); + QMetaObject::invokeMethod(kwinApp()->platform(), "setVirtualOutputs", Qt::QueuedConnection, + Q_ARG(int, geometries.count()), Q_ARG(QVector, geometries)); + QVERIFY(changedSpy.wait()); + + QFETCH(QPoint, cursorPos); + screens()->setCurrent(cursorPos); + QTEST(screens()->current(), "expected"); +} + +} // namespace KWin + +WAYLANDTEST_MAIN(KWin::ScreensTest) +#include "screens_test.moc" diff --git a/autotests/test_screens.cpp b/autotests/test_screens.cpp deleted file mode 100644 index 493600f745..0000000000 --- a/autotests/test_screens.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2014 Martin Gräßlin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#include "mock_workspace.h" -#include "../cursor.h" -#include "mock_screens.h" -#include "mock_x11client.h" -// frameworks -#include -// Qt -#include - -Q_LOGGING_CATEGORY(KWIN_CORE, "kwin_core") - -// Mock - -class TestScreens : public QObject -{ - Q_OBJECT -private Q_SLOTS: - void init(); - void testCurrentFollowsMouse(); - void testReconfigure_data(); - void testReconfigure(); - void testSize_data(); - void testSize(); - void testCount(); - void testIntersecting_data(); - void testIntersecting(); - void testCurrent_data(); - void testCurrent(); - void testCurrentClient(); - void testCurrentWithFollowsMouse_data(); - void testCurrentWithFollowsMouse(); - void testCurrentPoint_data(); - void testCurrentPoint(); -}; - -void TestScreens::init() -{ - KWin::Cursors::self()->setMouse(new KWin::Cursor(this)); -} - -void TestScreens::testCurrentFollowsMouse() -{ - KWin::MockWorkspace ws; - KWin::Screens *screens = KWin::Screens::create(&ws); - QVERIFY(!screens->isCurrentFollowsMouse()); - screens->setCurrentFollowsMouse(true); - QVERIFY(screens->isCurrentFollowsMouse()); - // setting to same should not do anything - screens->setCurrentFollowsMouse(true); - QVERIFY(screens->isCurrentFollowsMouse()); - - // setting back to other value - screens->setCurrentFollowsMouse(false); - QVERIFY(!screens->isCurrentFollowsMouse()); - // setting to same should not do anything - screens->setCurrentFollowsMouse(false); - QVERIFY(!screens->isCurrentFollowsMouse()); -} - -void TestScreens::testReconfigure_data() -{ - QTest::addColumn("focusPolicy"); - QTest::addColumn("expectedDefault"); - QTest::addColumn("setting"); - - QTest::newRow("ClickToFocus") << QStringLiteral("ClickToFocus") << false << true; - QTest::newRow("FocusFollowsMouse") << QStringLiteral("FocusFollowsMouse") << true << false; - QTest::newRow("FocusUnderMouse") << QStringLiteral("FocusUnderMouse") << true << false; - QTest::newRow("FocusStrictlyUnderMouse") << QStringLiteral("FocusStrictlyUnderMouse") << true << false; -} - -void TestScreens::testReconfigure() -{ - using namespace KWin; - MockWorkspace ws; - Screens::create(&ws); - screens()->reconfigure(); - QVERIFY(!screens()->isCurrentFollowsMouse()); - - QFETCH(QString, focusPolicy); - - KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); - config->group("Windows").writeEntry("FocusPolicy", focusPolicy); - config->group("Windows").sync(); - config->sync(); - - screens()->setConfig(config); - screens()->reconfigure(); - QTEST(screens()->isCurrentFollowsMouse(), "expectedDefault"); - - QFETCH(bool, setting); - config->group("Windows").writeEntry("ActiveMouseScreen", setting); - config->sync(); - screens()->reconfigure(); - QCOMPARE(screens()->isCurrentFollowsMouse(), setting); -} - -void TestScreens::testSize_data() -{ - QTest::addColumn< QList >("geometries"); - QTest::addColumn("expectedSize"); - - QTest::newRow("empty") << QList{{QRect()}} << QSize(0, 0); - QTest::newRow("cloned") << QList{{QRect{0, 0, 200, 100}, QRect{0, 0, 200, 100}}} << QSize(200, 100); - QTest::newRow("adjacent") << QList{{QRect{0, 0, 200, 100}, QRect{200, 100, 400, 300}}} << QSize(600, 400); - QTest::newRow("overlapping") << QList{{QRect{-10, -20, 50, 100}, QRect{0, 0, 100, 200}}} << QSize(110, 220); - QTest::newRow("gap") << QList{{QRect{0, 0, 10, 20}, QRect{20, 40, 10, 20}}} << QSize(30, 60); -} - -void TestScreens::testSize() -{ - using namespace KWin; - MockWorkspace ws; - MockScreens *mockScreens = static_cast(Screens::create(&ws)); - QSignalSpy sizeChangedSpy(screens(), &KWin::Screens::sizeChanged); - QVERIFY(sizeChangedSpy.isValid()); - - QCOMPARE(screens()->size(), QSize(100, 100)); - QFETCH(QList, geometries); - QVERIFY(!mockScreens->isChanging()); - mockScreens->setGeometries(geometries); - QVERIFY(mockScreens->isChanging()); - - QVERIFY(sizeChangedSpy.wait()); - QVERIFY(!mockScreens->isChanging()); - QTEST(screens()->size(), "expectedSize"); -} - -void TestScreens::testCount() -{ - using namespace KWin; - MockWorkspace ws; - MockScreens *mockScreens = static_cast(Screens::create(&ws)); - QSignalSpy countChangedSpy(screens(), &KWin::Screens::countChanged); - QVERIFY(countChangedSpy.isValid()); - - QCOMPARE(screens()->count(), 1); - - // change to two screens - QList geometries{{QRect{0, 0, 100, 200}, QRect{100, 0, 100, 200}}}; - mockScreens->setGeometries(geometries); - - QVERIFY(countChangedSpy.wait()); - QCOMPARE(countChangedSpy.count(), 1); - QCOMPARE(countChangedSpy.first().first().toInt(), 1); - QCOMPARE(countChangedSpy.first().last().toInt(), 2); - QCOMPARE(screens()->count(), 2); - - // go back to one screen - geometries.takeLast(); - mockScreens->setGeometries(geometries); - QVERIFY(countChangedSpy.wait()); - QCOMPARE(countChangedSpy.count(), 2); - QCOMPARE(countChangedSpy.last().first().toInt(), 2); - QCOMPARE(countChangedSpy.last().last().toInt(), 1); - QCOMPARE(screens()->count(), 1); - - // setting the same geometries shouldn't emit the signal, but we should get a changed signal - QSignalSpy changedSpy(screens(), &KWin::Screens::changed); - QVERIFY(changedSpy.isValid()); - mockScreens->setGeometries(geometries); - QVERIFY(changedSpy.wait()); - QCOMPARE(countChangedSpy.count(), 2); -} - -void TestScreens::testIntersecting_data() -{ - QTest::addColumn>("geometries"); - QTest::addColumn("testGeometry"); - QTest::addColumn("expectedCount"); - - QTest::newRow("null-rect") << QList{{QRect{0, 0, 100, 100}}} << QRect() << 0; - QTest::newRow("non-overlapping") << QList{{QRect{0, 0, 100, 100}}} << QRect(100, 0, 100, 100) << 0; - QTest::newRow("in-between") << QList{{QRect{0, 0, 10, 20}, QRect{20, 40, 10, 20}}} << QRect(15, 0, 2, 2) << 0; - QTest::newRow("gap-overlapping") << QList{{QRect{0, 0, 10, 20}, QRect{20, 40, 10, 20}}} << QRect(9, 10, 200, 200) << 2; - QTest::newRow("larger") << QList{{QRect{0, 0, 100, 100}}} << QRect(-10, -10, 200, 200) << 1; - QTest::newRow("several") << QList{{QRect{0, 0, 100, 100}, QRect{100, 0, 100, 100}, QRect{200, 100, 100, 100}, QRect{300, 100, 100, 100}}} << QRect(0, 0, 300, 300) << 3; -} - -void TestScreens::testIntersecting() -{ - using namespace KWin; - MockWorkspace ws; - MockScreens *mockScreens = static_cast(Screens::create(&ws)); - QSignalSpy changedSpy(screens(), &KWin::Screens::changed); - QVERIFY(changedSpy.isValid()); - QFETCH(QList, geometries); - mockScreens->setGeometries(geometries); - // first is before it's updated - QVERIFY(changedSpy.wait()); - // second is after it's updated - QVERIFY(changedSpy.wait()); - - QFETCH(QRect, testGeometry); - QCOMPARE(screens()->count(), geometries.count()); - QTEST(screens()->intersecting(testGeometry), "expectedCount"); -} - -void TestScreens::testCurrent_data() -{ - QTest::addColumn("current"); - QTest::addColumn("signal"); - - QTest::newRow("unchanged") << 0 << false; - QTest::newRow("changed") << 1 << true; -} - -void TestScreens::testCurrent() -{ - using namespace KWin; - MockWorkspace ws; - Screens::create(&ws); - QSignalSpy currentChangedSpy(screens(), &KWin::Screens::currentChanged); - QVERIFY(currentChangedSpy.isValid()); - - QFETCH(int, current); - screens()->setCurrent(current); - QCOMPARE(screens()->current(), current); - QTEST(!currentChangedSpy.isEmpty(), "signal"); -} - -void TestScreens::testCurrentClient() -{ - using namespace KWin; - MockWorkspace ws; - MockScreens *mockScreens = static_cast(Screens::create(&ws)); - QSignalSpy changedSpy(screens(), &KWin::Screens::changed); - QVERIFY(changedSpy.isValid()); - mockScreens->setGeometries(QList{{QRect{0, 0, 100, 100}, QRect{100, 0, 100, 100}}}); - // first is before it's updated - QVERIFY(changedSpy.wait()); - // second is after it's updated - QVERIFY(changedSpy.wait()); - - QSignalSpy currentChangedSpy(screens(), &KWin::Screens::currentChanged); - QVERIFY(currentChangedSpy.isValid()); - - // create a mock client - X11Client *client = new X11Client(&ws); - client->setScreen(1); - - // it's not the active client, so changing won't work - screens()->setCurrent(client); - QVERIFY(currentChangedSpy.isEmpty()); - QCOMPARE(screens()->current(), 0); - - // making the client active should affect things - client->setActive(true); - ws.setActiveClient(client); - - // first of all current should be changed just by the fact that there is an active client - QCOMPARE(screens()->current(), 1); - // but also calling setCurrent should emit the changed signal - screens()->setCurrent(client); - QCOMPARE(currentChangedSpy.count(), 1); - QCOMPARE(screens()->current(), 1); - - // setting current with the same client again should not change, though - screens()->setCurrent(client); - QCOMPARE(currentChangedSpy.count(), 1); - - // and it should even still be on screen 1 if we make the client non-current again - ws.setActiveClient(nullptr); - client->setActive(false); - QCOMPARE(screens()->current(), 1); -} - -void TestScreens::testCurrentWithFollowsMouse_data() -{ - QTest::addColumn< QList >("geometries"); - QTest::addColumn("cursorPos"); - QTest::addColumn("expected"); - - QTest::newRow("empty") << QList{{QRect()}} << QPoint(100, 100) << 0; - QTest::newRow("cloned") << QList{{QRect{0, 0, 200, 100}, QRect{0, 0, 200, 100}}} << QPoint(50, 50) << 0; - QTest::newRow("adjacent-0") << QList{{QRect{0, 0, 200, 100}, QRect{200, 100, 400, 300}}} << QPoint(199, 99) << 0; - QTest::newRow("adjacent-1") << QList{{QRect{0, 0, 200, 100}, QRect{200, 100, 400, 300}}} << QPoint(200, 100) << 1; - QTest::newRow("gap") << QList{{QRect{0, 0, 10, 20}, QRect{20, 40, 10, 20}}} << QPoint(15, 30) << 1; -} - -void TestScreens::testCurrentWithFollowsMouse() -{ - using namespace KWin; - MockWorkspace ws; - MockScreens *mockScreens = static_cast(Screens::create(&ws)); - QSignalSpy changedSpy(screens(), &KWin::Screens::changed); - QVERIFY(changedSpy.isValid()); - screens()->setCurrentFollowsMouse(true); - QCOMPARE(screens()->current(), 0); - - QFETCH(QList, geometries); - mockScreens->setGeometries(geometries); - // first is before it's updated - QVERIFY(changedSpy.wait()); - // second is after it's updated - QVERIFY(changedSpy.wait()); - - QFETCH(QPoint, cursorPos); - KWin::Cursors::self()->mouse()->setPos(cursorPos); - QTEST(screens()->current(), "expected"); -} - -void TestScreens::testCurrentPoint_data() -{ - QTest::addColumn< QList >("geometries"); - QTest::addColumn("cursorPos"); - QTest::addColumn("expected"); - - QTest::newRow("empty") << QList{{QRect()}} << QPoint(100, 100) << 0; - QTest::newRow("cloned") << QList{{QRect{0, 0, 200, 100}, QRect{0, 0, 200, 100}}} << QPoint(50, 50) << 0; - QTest::newRow("adjacent-0") << QList{{QRect{0, 0, 200, 100}, QRect{200, 100, 400, 300}}} << QPoint(199, 99) << 0; - QTest::newRow("adjacent-1") << QList{{QRect{0, 0, 200, 100}, QRect{200, 100, 400, 300}}} << QPoint(200, 100) << 1; - QTest::newRow("gap") << QList{{QRect{0, 0, 10, 20}, QRect{20, 40, 10, 20}}} << QPoint(15, 30) << 1; -} - -void TestScreens::testCurrentPoint() -{ - using namespace KWin; - MockWorkspace ws; - MockScreens *mockScreens = static_cast(Screens::create(&ws)); - QSignalSpy changedSpy(screens(), &KWin::Screens::changed); - QVERIFY(changedSpy.isValid()); - - QFETCH(QList, geometries); - mockScreens->setGeometries(geometries); - // first is before it's updated - QVERIFY(changedSpy.wait()); - // second is after it's updated - QVERIFY(changedSpy.wait()); - - QFETCH(QPoint, cursorPos); - screens()->setCurrent(cursorPos); - QTEST(screens()->current(), "expected"); -} - -QTEST_MAIN(TestScreens) -#include "test_screens.moc"