kwin/autotests/integration/no_global_shortcuts_test.cpp
Vlad Zahorodnii 6d3f00e82c autotests: Remove QVERIFY(signalSpy.isValid())
We use the PMF syntax so the isValid() check is unnecessary as the
compiler will notify about wrong signal at compile time. It makes
writing autotests feel less boilerplaty.
2022-09-14 09:21:29 +00:00

268 lines
9.5 KiB
C++

/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2018 Martin Flöser <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "kwin_wayland_test.h"
#include "core/platform.h"
#include "cursor.h"
#include "input.h"
#include "keyboard_input.h"
#include "screenedge.h"
#include "wayland_server.h"
#include "workspace.h"
#include <KConfigGroup>
#include <KGlobalAccel>
#include <QDBusConnection>
#include <linux/input.h>
using namespace KWin;
using namespace KWayland::Client;
static const QString s_socketName = QStringLiteral("wayland_test_kwin_no_global_shortcuts-0");
static const QString s_serviceName = QStringLiteral("org.kde.KWin.Test.ModifierOnlyShortcut");
static const QString s_path = QStringLiteral("/Test");
Q_DECLARE_METATYPE(KWin::ElectricBorder)
/**
* This test verifies the NoGlobalShortcuts initialization flag
*/
class NoGlobalShortcutsTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void init();
void cleanup();
void testTrigger_data();
void testTrigger();
void testKGlobalAccel();
void testPointerShortcut();
void testAxisShortcut_data();
void testAxisShortcut();
void testScreenEdge();
};
class Target : public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.KWin.Test.ModifierOnlyShortcut")
public:
Target();
~Target() override;
public Q_SLOTS:
Q_SCRIPTABLE void shortcut();
Q_SIGNALS:
void shortcutTriggered();
};
Target::Target()
: QObject()
{
QDBusConnection::sessionBus().registerService(s_serviceName);
QDBusConnection::sessionBus().registerObject(s_path, s_serviceName, this, QDBusConnection::ExportScriptableSlots);
}
Target::~Target()
{
QDBusConnection::sessionBus().unregisterObject(s_path);
QDBusConnection::sessionBus().unregisterService(s_serviceName);
}
void Target::shortcut()
{
Q_EMIT shortcutTriggered();
}
void NoGlobalShortcutsTest::initTestCase()
{
qRegisterMetaType<KWin::ElectricBorder>("ElectricBorder");
QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024));
QVERIFY(waylandServer()->init(s_socketName, KWin::WaylandServer::InitializationFlag::NoGlobalShortcuts));
kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
qputenv("KWIN_XKB_DEFAULT_KEYMAP", "1");
qputenv("XKB_DEFAULT_RULES", "evdev");
kwinApp()->start();
QVERIFY(applicationStartedSpy.wait());
}
void NoGlobalShortcutsTest::init()
{
workspace()->setActiveOutput(QPoint(640, 512));
KWin::Cursors::self()->mouse()->setPos(QPoint(640, 512));
}
void NoGlobalShortcutsTest::cleanup()
{
}
void NoGlobalShortcutsTest::testTrigger_data()
{
QTest::addColumn<QStringList>("metaConfig");
QTest::addColumn<QStringList>("altConfig");
QTest::addColumn<QStringList>("controlConfig");
QTest::addColumn<QStringList>("shiftConfig");
QTest::addColumn<int>("modifier");
QTest::addColumn<QList<int>>("nonTriggeringMods");
const QStringList trigger = QStringList{s_serviceName, s_path, s_serviceName, QStringLiteral("shortcut")};
const QStringList e = QStringList();
QTest::newRow("leftMeta") << trigger << e << e << e << KEY_LEFTMETA << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT};
QTest::newRow("rightMeta") << trigger << e << e << e << KEY_RIGHTMETA << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT};
QTest::newRow("leftAlt") << e << trigger << e << e << KEY_LEFTALT << QList<int>{KEY_LEFTMETA, KEY_RIGHTMETA, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT};
QTest::newRow("rightAlt") << e << trigger << e << e << KEY_RIGHTALT << QList<int>{KEY_LEFTMETA, KEY_RIGHTMETA, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT};
QTest::newRow("leftControl") << e << e << trigger << e << KEY_LEFTCTRL << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_LEFTSHIFT, KEY_RIGHTSHIFT};
QTest::newRow("rightControl") << e << e << trigger << e << KEY_RIGHTCTRL << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_LEFTSHIFT, KEY_RIGHTSHIFT};
QTest::newRow("leftShift") << e << e << e << trigger << KEY_LEFTSHIFT << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTMETA, KEY_RIGHTMETA};
QTest::newRow("rightShift") << e << e << e << trigger << KEY_RIGHTSHIFT << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTMETA, KEY_RIGHTMETA};
}
void NoGlobalShortcutsTest::testTrigger()
{
// test based on ModifierOnlyShortcutTest::testTrigger
Target target;
QSignalSpy triggeredSpy(&target, &Target::shortcutTriggered);
KConfigGroup group = kwinApp()->config()->group("ModifierOnlyShortcuts");
QFETCH(QStringList, metaConfig);
QFETCH(QStringList, altConfig);
QFETCH(QStringList, shiftConfig);
QFETCH(QStringList, controlConfig);
group.writeEntry("Meta", metaConfig);
group.writeEntry("Alt", altConfig);
group.writeEntry("Shift", shiftConfig);
group.writeEntry("Control", controlConfig);
group.sync();
workspace()->slotReconfigure();
// configured shortcut should trigger
quint32 timestamp = 1;
QFETCH(int, modifier);
Test::keyboardKeyPressed(modifier, timestamp++);
Test::keyboardKeyReleased(modifier, timestamp++);
QCOMPARE(triggeredSpy.count(), 0);
// the other shortcuts should not trigger
QFETCH(QList<int>, nonTriggeringMods);
for (auto it = nonTriggeringMods.constBegin(), end = nonTriggeringMods.constEnd(); it != end; it++) {
Test::keyboardKeyPressed(*it, timestamp++);
Test::keyboardKeyReleased(*it, timestamp++);
QCOMPARE(triggeredSpy.count(), 0);
}
}
void NoGlobalShortcutsTest::testKGlobalAccel()
{
std::unique_ptr<QAction> action(new QAction(nullptr));
action->setProperty("componentName", QStringLiteral(KWIN_NAME));
action->setObjectName(QStringLiteral("globalshortcuts-test-meta-shift-w"));
QSignalSpy triggeredSpy(action.get(), &QAction::triggered);
KGlobalAccel::self()->setShortcut(action.get(), QList<QKeySequence>{Qt::META | Qt::SHIFT | Qt::Key_W}, KGlobalAccel::NoAutoloading);
input()->registerShortcut(Qt::META | Qt::SHIFT | Qt::Key_W, action.get());
// press meta+shift+w
quint32 timestamp = 0;
Test::keyboardKeyPressed(KEY_LEFTMETA, timestamp++);
QCOMPARE(input()->keyboardModifiers(), Qt::MetaModifier);
Test::keyboardKeyPressed(KEY_LEFTSHIFT, timestamp++);
QCOMPARE(input()->keyboardModifiers(), Qt::ShiftModifier | Qt::MetaModifier);
Test::keyboardKeyPressed(KEY_W, timestamp++);
Test::keyboardKeyReleased(KEY_W, timestamp++);
// release meta+shift
Test::keyboardKeyReleased(KEY_LEFTSHIFT, timestamp++);
Test::keyboardKeyReleased(KEY_LEFTMETA, timestamp++);
QVERIFY(!triggeredSpy.wait());
QCOMPARE(triggeredSpy.count(), 0);
}
void NoGlobalShortcutsTest::testPointerShortcut()
{
// based on LockScreenTest::testPointerShortcut
std::unique_ptr<QAction> action(new QAction(nullptr));
QSignalSpy actionSpy(action.get(), &QAction::triggered);
input()->registerPointerShortcut(Qt::MetaModifier, Qt::LeftButton, action.get());
// try to trigger the shortcut
quint32 timestamp = 1;
Test::keyboardKeyPressed(KEY_LEFTMETA, timestamp++);
Test::pointerButtonPressed(BTN_LEFT, timestamp++);
QCoreApplication::instance()->processEvents();
QCOMPARE(actionSpy.count(), 0);
Test::pointerButtonReleased(BTN_LEFT, timestamp++);
Test::keyboardKeyReleased(KEY_LEFTMETA, timestamp++);
QCoreApplication::instance()->processEvents();
QCOMPARE(actionSpy.count(), 0);
}
void NoGlobalShortcutsTest::testAxisShortcut_data()
{
QTest::addColumn<Qt::Orientation>("direction");
QTest::addColumn<int>("sign");
QTest::newRow("up") << Qt::Vertical << 1;
QTest::newRow("down") << Qt::Vertical << -1;
QTest::newRow("left") << Qt::Horizontal << 1;
QTest::newRow("right") << Qt::Horizontal << -1;
}
void NoGlobalShortcutsTest::testAxisShortcut()
{
// based on LockScreenTest::testAxisShortcut
std::unique_ptr<QAction> action(new QAction(nullptr));
QSignalSpy actionSpy(action.get(), &QAction::triggered);
QFETCH(Qt::Orientation, direction);
QFETCH(int, sign);
PointerAxisDirection axisDirection = PointerAxisUp;
if (direction == Qt::Vertical) {
axisDirection = sign > 0 ? PointerAxisUp : PointerAxisDown;
} else {
axisDirection = sign > 0 ? PointerAxisLeft : PointerAxisRight;
}
input()->registerAxisShortcut(Qt::MetaModifier, axisDirection, action.get());
// try to trigger the shortcut
quint32 timestamp = 1;
Test::keyboardKeyPressed(KEY_LEFTMETA, timestamp++);
if (direction == Qt::Vertical) {
Test::pointerAxisVertical(sign * 5.0, timestamp++);
} else {
Test::pointerAxisHorizontal(sign * 5.0, timestamp++);
}
QCoreApplication::instance()->processEvents();
QCOMPARE(actionSpy.count(), 0);
Test::keyboardKeyReleased(KEY_LEFTMETA, timestamp++);
QCoreApplication::instance()->processEvents();
QCOMPARE(actionSpy.count(), 0);
}
void NoGlobalShortcutsTest::testScreenEdge()
{
// based on LockScreenTest::testScreenEdge
QSignalSpy screenEdgeSpy(workspace()->screenEdges(), &ScreenEdges::approaching);
QCOMPARE(screenEdgeSpy.count(), 0);
quint32 timestamp = 1;
Test::pointerMotion({5, 5}, timestamp++);
QCOMPARE(screenEdgeSpy.count(), 0);
}
WAYLANDTEST_MAIN(NoGlobalShortcutsTest)
#include "no_global_shortcuts_test.moc"