Skip to content

Commit 60b4930

Browse files
committed
Add Qt tests
1 parent 27085f2 commit 60b4930

9 files changed

Lines changed: 419 additions & 31 deletions

File tree

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ find_package(PkgConfig QUIET)
8888

8989
# Qt6 for dialogs and future UI migration
9090
find_package(Qt6 REQUIRED COMPONENTS Core Widgets Svg)
91+
if(GECK_BUILD_TESTS)
92+
find_package(Qt6 REQUIRED COMPONENTS Test)
93+
endif()
9194
set(CMAKE_AUTOMOC ON)
9295
set(CMAKE_AUTORCC ON)
9396
set(CMAKE_AUTOUIC ON)

TODO.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,6 @@ Detailed progress dialog with task descriptions and completion estimates for lon
5252
- [ ] Refactor hex rendering into dedicated HexRenderer class
5353
- [ ] Improve separation of concerns between HexagonGrid and EditorWidget
5454

55-
### Review Follow-ups
56-
- [ ] Add Qt/UI tests around `Pro*Widget`, inventory UI flows, and panel toggles before larger refactors
57-
5855
### Presets
5956
- [ ] TBD: paint a pattern of tiles
6057
- [ ] TBD: paste a preset into the map, e.g. hut from Arroyo. Presets should be stored in a JSON/YAML/...

src/CMakeLists.txt

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44
###################################
55

66
# Define source files
7-
set(GECK_SOURCES
8-
main.cpp
9-
7+
set(GECK_APP_SOURCES
108
Application.h
119
Application.cpp
1210

@@ -188,17 +186,21 @@ set(GECK_SOURCES
188186
${CMAKE_SOURCE_DIR}/resources/icons.qrc
189187
)
190188

189+
# Reusable application library for the executable and UI tests
190+
add_library(gecko_app STATIC ${GECK_APP_SOURCES})
191+
add_library(gecko::app ALIAS gecko_app)
192+
191193
# Platform-specific executable settings
192194
if(WIN32)
193-
add_executable(${PROJECT_NAME} WIN32 ${GECK_SOURCES})
195+
add_executable(${PROJECT_NAME} WIN32 main.cpp)
194196
# Add Windows resource file for icon
195197
target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/resources/gecko.rc)
196198
elseif(APPLE)
197199
# Add icon to bundle
198200
set(MACOSX_BUNDLE_ICON_FILE gecko.icns)
199201
set(APP_ICON_MACOSX ${CMAKE_SOURCE_DIR}/resources/gecko.icns)
200202
set_source_files_properties(${APP_ICON_MACOSX} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
201-
add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${GECK_SOURCES} ${APP_ICON_MACOSX})
203+
add_executable(${PROJECT_NAME} MACOSX_BUNDLE main.cpp ${APP_ICON_MACOSX})
202204

203205
# Set bundle properties
204206
set_target_properties(${PROJECT_NAME} PROPERTIES
@@ -209,7 +211,7 @@ elseif(APPLE)
209211
MACOSX_BUNDLE_BUNDLE_VERSION "1"
210212
)
211213
else()
212-
add_executable(${PROJECT_NAME} ${GECK_SOURCES})
214+
add_executable(${PROJECT_NAME} main.cpp)
213215
endif()
214216

215217
###################################
@@ -333,7 +335,7 @@ PRIVATE
333335
gecko::spdlog
334336
)
335337

336-
target_link_libraries(${PROJECT_NAME} PRIVATE
338+
target_link_libraries(gecko_app PUBLIC
337339
SFML::System SFML::Graphics SFML::Window
338340
Qt6::Core
339341
Qt6::Widgets
@@ -343,9 +345,12 @@ target_link_libraries(${PROJECT_NAME} PRIVATE
343345
vault
344346
)
345347

346-
target_include_directories(${PROJECT_NAME} PRIVATE
347-
"${CMAKE_SOURCE_DIR}/vendor/vfspp/include"
348-
"${CMAKE_BINARY_DIR}/generated")
348+
target_include_directories(gecko_app PUBLIC
349+
${CMAKE_CURRENT_SOURCE_DIR}
350+
"${CMAKE_BINARY_DIR}/generated"
351+
)
352+
353+
target_link_libraries(${PROJECT_NAME} PRIVATE gecko_app)
349354

350355
# copy shared external libraries to the build directory for Windows builds
351356
if(WIN32)

src/ui/dialogs/InventoryViewerDialog.cpp

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
namespace geck {
1515

1616
InventoryViewerDialog::InventoryViewerDialog(std::shared_ptr<Object> object, QWidget* parent)
17+
: InventoryViewerDialog(object ? object->getMapObjectPtr() : nullptr, parent) {
18+
}
19+
20+
InventoryViewerDialog::InventoryViewerDialog(std::shared_ptr<MapObject> mapObject, QWidget* parent)
1721
: QDialog(parent)
1822
, _mainLayout(nullptr)
1923
, _splitter(nullptr)
@@ -38,21 +42,12 @@ InventoryViewerDialog::InventoryViewerDialog(std::shared_ptr<Object> object, QWi
3842
, _removeButton(nullptr)
3943
, _editButton(nullptr)
4044
, _closeButton(nullptr)
41-
, _object(object)
42-
, _mapObject(nullptr) {
45+
, _mapObject(std::move(mapObject)) {
4346

4447
spdlog::debug("InventoryViewerDialog: Constructor called");
4548

46-
if (!_object) {
47-
spdlog::error("InventoryViewerDialog: Invalid object provided");
48-
reject();
49-
return;
50-
}
51-
52-
_mapObject = _object->getMapObjectPtr();
5349
if (!_mapObject) {
54-
spdlog::error("InventoryViewerDialog: Object has no MapObject");
55-
QMessageBox::warning(this, "Error", "Selected object has no map data.");
50+
spdlog::error("InventoryViewerDialog: Invalid map object provided");
5651
reject();
5752
return;
5853
}

src/ui/dialogs/InventoryViewerDialog.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class InventoryViewerDialog : public QDialog {
3232

3333
public:
3434
explicit InventoryViewerDialog(std::shared_ptr<Object> object, QWidget* parent = nullptr);
35+
explicit InventoryViewerDialog(std::shared_ptr<MapObject> mapObject, QWidget* parent = nullptr);
3536
~InventoryViewerDialog() = default;
3637

3738
private slots:
@@ -80,7 +81,6 @@ private slots:
8081
QPushButton* _closeButton;
8182

8283
// Data
83-
std::shared_ptr<Object> _object;
8484
std::shared_ptr<MapObject> _mapObject;
8585

8686
// Tree widget columns

src/util/Settings.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,18 @@ Settings& Settings::getInstance() {
2525

2626
QString Settings::getSettingsFilePath() const {
2727
QString configPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
28-
QDir configDir(configPath);
28+
QDir configDir;
2929

30-
// Create organization directory if it doesn't exist
31-
if (!configDir.exists(ORGANIZATION_NAME)) {
32-
configDir.mkpath(ORGANIZATION_NAME);
30+
if (!configDir.mkpath(configPath)) {
31+
return QDir(configPath).filePath(SETTINGS_FILENAME);
3332
}
3433

35-
configDir.cd(ORGANIZATION_NAME);
36-
return configDir.absoluteFilePath(SETTINGS_FILENAME);
34+
const QString organizationPath = QDir(configPath).filePath(ORGANIZATION_NAME);
35+
if (!configDir.mkpath(organizationPath)) {
36+
return QDir(configPath).filePath(SETTINGS_FILENAME);
37+
}
38+
39+
return QDir(organizationPath).filePath(SETTINGS_FILENAME);
3740
}
3841

3942
bool Settings::exists() const {

tests/CMakeLists.txt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ add_executable(performance_tests
1919
performance/test_reader_performance.cpp
2020
)
2121

22+
add_executable(qt_tests
23+
qt/qt_test_main.cpp
24+
qt/test_ui_regressions.cpp
25+
)
26+
2227
target_link_libraries(general_tests PRIVATE
2328
Catch2::Catch2WithMain
2429
gecko::spdlog
@@ -37,6 +42,15 @@ target_link_libraries(performance_tests PRIVATE
3742
SFML::System SFML::Graphics
3843
)
3944

45+
target_link_libraries(qt_tests PRIVATE
46+
Catch2::Catch2
47+
Qt6::Test
48+
gecko::app
49+
)
50+
51+
target_include_directories(qt_tests PRIVATE
52+
${CMAKE_SOURCE_DIR}/src
53+
)
4054

4155
# Enable testing
4256
include(CTest)
@@ -55,6 +69,8 @@ else()
5569
catch_discover_tests(performance_tests)
5670
endif()
5771

72+
add_test(NAME qt_tests COMMAND qt_tests)
73+
5874

5975
# copy shared external libraries to the build directory for Windows builds
6076
if(WIN32)
@@ -68,6 +84,11 @@ if(WIN32)
6884
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:performance_tests> $<TARGET_FILE_DIR:performance_tests>
6985
COMMAND_EXPAND_LISTS
7086
)
87+
add_custom_command(
88+
TARGET qt_tests POST_BUILD
89+
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:qt_tests> $<TARGET_FILE_DIR:qt_tests>
90+
COMMAND_EXPAND_LISTS
91+
)
7192
endif()
7293

7394
# Copy test data to both the executable directory and the test working directory
@@ -82,3 +103,8 @@ add_custom_command(
82103
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/tests/data $<TARGET_FILE_DIR:performance_tests>/data
83104
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/tests/data ${CMAKE_CURRENT_BINARY_DIR}/data
84105
)
106+
107+
add_custom_command(
108+
TARGET qt_tests POST_BUILD
109+
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/resources $<TARGET_FILE_DIR:qt_tests>/resources
110+
)

tests/qt/qt_test_main.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#include <QByteArray>
2+
#include <QApplication>
3+
#include <QStandardPaths>
4+
#include <QTemporaryDir>
5+
6+
#include <catch2/catch_session.hpp>
7+
8+
#include "util/ResourceManager.h"
9+
10+
int main(int argc, char** argv) {
11+
QTemporaryDir testHome;
12+
if (!testHome.isValid()) {
13+
return 1;
14+
}
15+
16+
qputenv("HOME", testHome.path().toUtf8());
17+
QStandardPaths::setTestModeEnabled(true);
18+
19+
#if defined(Q_OS_MACOS)
20+
if (qEnvironmentVariableIsEmpty("QT_QPA_PLATFORM")) {
21+
qputenv("QT_QPA_PLATFORM", QByteArray("offscreen"));
22+
}
23+
#elif defined(Q_OS_LINUX)
24+
if (qEnvironmentVariableIsEmpty("QT_QPA_PLATFORM")
25+
&& qEnvironmentVariableIsEmpty("DISPLAY")
26+
&& qEnvironmentVariableIsEmpty("WAYLAND_DISPLAY")) {
27+
qputenv("QT_QPA_PLATFORM", QByteArray("offscreen"));
28+
}
29+
#endif
30+
31+
QApplication app(argc, argv);
32+
app.setApplicationName("gecko-qt-tests");
33+
app.setOrganizationName("gecko");
34+
Q_INIT_RESOURCE(icons);
35+
36+
Catch::Session session;
37+
const int result = session.run(argc, argv);
38+
39+
geck::ResourceManager::getInstance().clearAllDataPaths();
40+
geck::ResourceManager::getInstance().cleanup();
41+
42+
return result;
43+
}

0 commit comments

Comments
 (0)