mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-10 22:24:13 +02:00
7866a37f14
tst_menubarkeyboard sends Alt+F and F10 right after the test window is exposed, then sleeps 300 ms and checks. Menu mnemonics and the F10 shortcut (a Qt::WindowShortcut) only fire in the active window, and being exposed does not mean being active: on a loaded Xvfb, or on macOS with another application in front, activation arrives later and the key is dropped. The sleep comes after the key and cannot help. This made shortcutOpensMenuBar fail on #1420's Linux CI ("F10 did not activate the menu bar") while the same base passed on #1421 and #1422, and made the Alt+F control fail in 1 of about 33 local runs with the cocoa platform. Every test now waits for the window to be active before pressing a key (qWaitForWindowActive, with its own failure message), and the two tests that expect a menu poll for it with QTRY_VERIFY2 instead of a fixed sleep. plainF10DoesNothingInQt keeps its 300 ms: it checks that nothing happens, which cannot be polled for; with the window now active first, that check can no longer pass merely because the key went nowhere. Test-only change. Checked: with a second window active, F10 sent to the exposed but inactive window does not activate its menu bar (offscreen and cocoa); once it is active, it does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
177 lines
5.9 KiB
C++
177 lines
5.9 KiB
C++
/*
|
|
Copyright 2006-2026 The QElectroTech Team
|
|
This file is part of QElectroTech.
|
|
|
|
QElectroTech is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
QElectroTech is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include <QtTest>
|
|
#include <QMainWindow>
|
|
#include <QMenu>
|
|
#include <QMenuBar>
|
|
#include <QShortcut>
|
|
|
|
#ifdef Q_OS_MACOS
|
|
// Exported from QtGui but declared in qkeysequence.h only for the
|
|
// documentation build; Qt's own docs say to declare it like this.
|
|
Q_GUI_EXPORT void qt_set_sequence_auto_mnemonic(bool b);
|
|
#endif
|
|
|
|
/*
|
|
F10 should open the menu bar, as it does in most applications and as
|
|
someone working without a mouse will expect. Qt provides this on Windows
|
|
but not on X11, so QElectroTech adds it (QETMainWindow::activateMenuBar).
|
|
|
|
These tests use QTest rather than driving a real X server. That is not a
|
|
convenience: xdotool on Xvfb delivers every function key with Alt held, so
|
|
the application receives Alt+F10 and never the plain key. Two rounds of
|
|
GUI automation gave confident, wrong answers about F10 before that was
|
|
understood. QTest posts the event directly to the widget, so the key
|
|
arrives exactly as written.
|
|
*/
|
|
class TstMenuBarKeyboard : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
private slots:
|
|
void initTestCase();
|
|
void altLetterOpensMenu(); // control -- must pass, or nothing below means anything
|
|
void plainF10DoesNothingInQt(); // the gap being filled
|
|
void shortcutOpensMenuBar(); // the mechanism QETMainWindow uses
|
|
};
|
|
|
|
namespace {
|
|
|
|
QMainWindow *makeWindow(QMenu **file_menu)
|
|
{
|
|
auto *w = new QMainWindow;
|
|
#ifdef Q_OS_MACOS
|
|
// A QMenuBar is native on macOS: its menus live in the system menu
|
|
// bar, outside the Qt widget tree, where QTest key events never reach
|
|
// them and QMenu::isVisible() stays false. The in-window bar runs the
|
|
// same QMenuBar code the other platforms use.
|
|
w->menuBar()->setNativeMenuBar(false);
|
|
#endif
|
|
*file_menu = w->menuBar()->addMenu(QStringLiteral("&File"));
|
|
(*file_menu)->addAction(QStringLiteral("Quit"));
|
|
w->menuBar()->addMenu(QStringLiteral("&Edit"))->addAction(QStringLiteral("Copy"));
|
|
w->resize(600, 400);
|
|
w->show();
|
|
w->activateWindow();
|
|
w->raise();
|
|
return w;
|
|
}
|
|
|
|
/*
|
|
Menu mnemonics and the F10 shortcut (a Qt::WindowShortcut) only fire
|
|
in the active window. Being exposed is not enough: on a loaded Xvfb or
|
|
with another application in front on macOS, activation arrives later,
|
|
and a key sent before it is dropped. Every test waits for activation
|
|
before pressing anything.
|
|
*/
|
|
bool waitForActiveWindow(QMainWindow *w)
|
|
{
|
|
return QTest::qWaitForWindowExposed(w) && QTest::qWaitForWindowActive(w);
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
macOS has no Alt+letter menu mnemonics, so Qt does not turn "&File"
|
|
into a shortcut there (qt_set_sequence_auto_mnemonic is off). The
|
|
control below needs one; switch mnemonics on for this process.
|
|
*/
|
|
void TstMenuBarKeyboard::initTestCase()
|
|
{
|
|
#ifdef Q_OS_MACOS
|
|
qt_set_sequence_auto_mnemonic(true);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
The control. Alt and a menu's letter is known to work, so if this fails
|
|
the environment cannot open menus at all and the other two tests are
|
|
measuring nothing.
|
|
*/
|
|
void TstMenuBarKeyboard::altLetterOpensMenu()
|
|
{
|
|
QMenu *file = nullptr;
|
|
QScopedPointer<QMainWindow> w(makeWindow(&file));
|
|
QVERIFY2(waitForActiveWindow(w.data()),
|
|
"the test window never became active");
|
|
|
|
QTest::keyClick(w.data(), Qt::Key_F, Qt::AltModifier);
|
|
|
|
QTRY_VERIFY2(file->isVisible(),
|
|
"control failed: Alt+F did not open a menu, so this environment "
|
|
"cannot judge any of the keyboard tests below");
|
|
}
|
|
|
|
/*
|
|
Records why the shortcut in QETMainWindow exists. If a future Qt starts
|
|
handling F10 on this platform, this test fails and the shortcut can go.
|
|
*/
|
|
void TstMenuBarKeyboard::plainF10DoesNothingInQt()
|
|
{
|
|
QMenu *file = nullptr;
|
|
QScopedPointer<QMainWindow> w(makeWindow(&file));
|
|
QVERIFY2(waitForActiveWindow(w.data()),
|
|
"the test window never became active");
|
|
|
|
QTest::keyClick(w.data(), Qt::Key_F10, Qt::NoModifier);
|
|
QTest::qWait(300);
|
|
|
|
QVERIFY2(!file->isVisible() && w->menuBar()->activeAction() == nullptr,
|
|
"Qt now handles F10 by itself -- QETMainWindow's shortcut is "
|
|
"redundant and can be removed");
|
|
}
|
|
|
|
/*
|
|
The mechanism QETMainWindow uses, exercised on a plain QMainWindow.
|
|
|
|
Worth being clear about what this does not cover: it repeats the shortcut
|
|
wiring rather than driving QETMainWindow itself, because
|
|
initCommonActions() calls QETApp::instance() and constructing that pulls
|
|
in the whole application -- element collections and all -- which does not
|
|
belong in a unit test. So this proves the approach works and would catch
|
|
it breaking in a future Qt; it does not prove QETMainWindow is wired up.
|
|
That last step needs someone to press F10 in a running QElectroTech.
|
|
*/
|
|
void TstMenuBarKeyboard::shortcutOpensMenuBar()
|
|
{
|
|
QMenu *file = nullptr;
|
|
QScopedPointer<QMainWindow> holder(makeWindow(&file));
|
|
QMainWindow *w = holder.data();
|
|
QVERIFY2(waitForActiveWindow(w), "the test window never became active");
|
|
|
|
auto *shortcut = new QShortcut(QKeySequence(Qt::Key_F10), w);
|
|
shortcut->setContext(Qt::WindowShortcut);
|
|
QObject::connect(shortcut, &QShortcut::activated, w, [w]() {
|
|
for (QAction *action : w->menuBar()->actions()) {
|
|
if (action->isVisible() && action->isEnabled() && action->menu()) {
|
|
w->menuBar()->setActiveAction(action);
|
|
return;
|
|
}
|
|
}
|
|
});
|
|
|
|
QTest::keyClick(w, Qt::Key_F10, Qt::NoModifier);
|
|
|
|
QTRY_VERIFY2(w->menuBar()->activeAction() != nullptr,
|
|
"F10 did not activate the menu bar");
|
|
QCOMPARE(w->menuBar()->activeAction()->text(), QStringLiteral("&File"));
|
|
}
|
|
|
|
QTEST_MAIN(TstMenuBarKeyboard)
|
|
#include "tst_menubarkeyboard.moc"
|