test: gate tray test hooks behind build flag (#184)

This commit is contained in:
Dave Lane authored and GitHub committed 2026-09-06 11:18:22 -04:00
1 parent 9f6672c961
commit dbacfbe8c3
7 files changed
+50 -12

No files matched your search

+3
View File
@@ -95,6 +95,9 @@ endif()
add_library(${PROJECT_NAME} STATIC ${TRAY_SOURCES})
set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 99)
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 17)
if(TRAY_IS_TOP_LEVEL AND BUILD_TESTS)
target_compile_definitions(${PROJECT_NAME} PRIVATE TRAY_ENABLE_TEST_HOOKS)
endif()
target_include_directories(${PROJECT_NAME}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
+24 -7
View File
@@ -3,18 +3,25 @@
* @brief Definitions for Qt tray menu implemenation
*/
// standard includes
#include <chrono>
#include <filesystem>
#include <thread>
// qt includes
#include <QApplication>
#include <QCursor>
#include <QDebug>
#include <QMouseEvent>
#include <QScreen>
#include <QStyle>
// conditional includes
#ifdef TRAY_ENABLE_TEST_HOOKS
// standard
#include <chrono>
#include <thread>
// qt
#include <QCursor>
#include <QScreen>
#endif
// local includes
#include "QtTrayMenu.h"
@@ -23,6 +30,7 @@
#endif
namespace {
#ifdef TRAY_ENABLE_TEST_HOOKS
constexpr int DEFAULT_PANEL_THICKNESS = 24;
constexpr int CURSOR_POSITION_POLL_INTERVAL_MS = 10;
constexpr int CURSOR_POSITION_TIMEOUT_MS = 500;
@@ -61,20 +69,27 @@ namespace {
if (topInset > 0) {
*position = QPoint(screenGeometry.right() - (topInset / 2), screenGeometry.top() + (topInset / 2));
} else if (bottomInset > 0) {
#if defined(__linux__)
// Plasma's default bottom panel places the system tray three quarters across the screen.
// Its far-right control is Peek at Desktop, rather than a tray icon.
*position = QPoint(screenGeometry.left() + ((screenGeometry.width() * 3) / 4), screenGeometry.bottom() - (bottomInset / 2));
#else
*position = QPoint(screenGeometry.right() - (bottomInset / 2), screenGeometry.bottom() - (bottomInset / 2));
#endif
} else if (rightInset > 0) {
*position = QPoint(screenGeometry.right() - (rightInset / 2), screenGeometry.bottom() - (rightInset / 2));
} else if (leftInset > 0) {
*position = QPoint(screenGeometry.left() + (leftInset / 2), screenGeometry.bottom() - (leftInset / 2));
} else {
#if defined(_WIN32)
#if defined(_WIN32)
*position = QPoint(screenGeometry.right() - (DEFAULT_PANEL_THICKNESS / 2), screenGeometry.bottom() - (DEFAULT_PANEL_THICKNESS / 2));
#else
#else
*position = QPoint(screenGeometry.right() - (DEFAULT_PANEL_THICKNESS / 2), screenGeometry.top() + (DEFAULT_PANEL_THICKNESS / 2));
#endif
#endif
}
return true;
}
#endif
} // namespace
QtTrayMenu::QtTrayMenu(QObject *parent, const bool debug):
@@ -401,6 +416,7 @@ void QtTrayMenu::clearMessageCallback() const {
notificationCallback = nullptr;
}
#ifdef TRAY_ENABLE_TEST_HOOKS
bool QtTrayMenu::positionMouseOverIcon() {
if (!trayIcon) {
return false;
@@ -442,3 +458,4 @@ bool QtTrayMenu::restoreMousePosition() {
}
return restored;
}
#endif
+9 -1
View File
@@ -12,10 +12,14 @@
// qt includes
#include <QMenu>
#include <QObject>
#include <QPoint>
#include <QString>
#include <QSystemTrayIcon>
// conditional includes
#ifdef TRAY_ENABLE_TEST_HOOKS
#include <QPoint>
#endif
// local includes
#include "tray.h"
@@ -111,6 +115,7 @@ public:
*/
void clearMessageCallback() const;
#ifdef TRAY_ENABLE_TEST_HOOKS
/**
* @brief Move the mouse cursor to the center of the tray icon.
* @return true if the tray icon has valid screen geometry and the cursor was moved
@@ -122,6 +127,7 @@ public:
* @return true if a saved position existed and the cursor was restored
*/
bool restoreMousePosition();
#endif
/**
* @brief Check if QtTrayMenu supports messages
@@ -163,8 +169,10 @@ private:
bool blockingEventLoop = false;
struct tray_menu *getTrayMenuItem(const QAction *action);
mutable std::function<void()> notificationCallback = nullptr;
#ifdef TRAY_ENABLE_TEST_HOOKS
QPoint savedMousePosition;
bool mousePositionSaved = false;
#endif
private slots:
void onExitRequested();
+2
View File
@@ -70,6 +70,7 @@ extern "C" {
*/
void tray_show_menu(void);
#ifdef TRAY_ENABLE_TEST_HOOKS
/**
* @brief Position the mouse over the tray icon (for testing purposes).
* @return 0 on success, -1 if the tray icon geometry is unavailable.
@@ -81,6 +82,7 @@ extern "C" {
* @return 0 on success, -1 if no saved position exists or the cursor could not be restored.
*/
int tray_restore_mouse_position(void);
#endif
/**
* @brief Simulate a notification click, invoking the notification callback (for testing purposes).
+2
View File
@@ -221,6 +221,7 @@ extern "C" {
tray_qt::state().trayMenu->showMenu();
}
#ifdef TRAY_ENABLE_TEST_HOOKS
int tray_position_mouse_over_icon(void) {
if (tray_qt::state().trayMenu == nullptr) {
return -1;
@@ -234,6 +235,7 @@ extern "C" {
}
return tray_qt::state().trayMenu->restoreMousePosition() ? 0 : -1;
}
#endif
void tray_simulate_menu_item_click(int index) {
if (tray_qt::state().trayMenu == nullptr) {
+1
View File
@@ -53,6 +53,7 @@ target_link_libraries(${PROJECT_NAME}
gtest
gtest_main # if we use this we don't need our own main function
)
target_compile_definitions(${PROJECT_NAME} PRIVATE TRAY_ENABLE_TEST_HOOKS)
target_compile_definitions(${PROJECT_NAME} PUBLIC ${TEST_DEFINITIONS})
target_link_options(${PROJECT_NAME} PRIVATE)
+9 -4
View File
@@ -249,6 +249,14 @@ protected:
}
}
// Native tray tooltips are displayed asynchronously by the desktop shell.
void WaitForTooltipReady() const {
for (int i = 0; i < 40; ++i) {
tray_loop(0);
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
}
void WaitForNotificationReady() const {
WaitForTrayReady();
#if defined(_WIN32) || defined(__APPLE__)
@@ -478,10 +486,7 @@ TEST_F(TrayTest, TestTooltipDisplayOnHover) {
WaitForTrayReady();
ASSERT_EQ(tray_position_mouse_over_icon(), 0);
for (int i = 0; i < 20; ++i) {
tray_loop(0);
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
WaitForTooltipReady();
EXPECT_TRUE(captureScreenshot("tray_tooltip_hover"));
EXPECT_EQ(tray_restore_mouse_position(), 0);
}