From 21cbac3ba9ee90310cbf682ed0488ee19d17373d Mon Sep 17 00:00:00 2001 From: Dan Dennedy Date: Fri, 8 May 2026 17:17:08 -0700 Subject: [PATCH 1/3] Add basic unit tests for MainWindow --- CMakeLists.txt | 2 + src/CMakeLists.txt | 44 ++-- tests/CMakeLists.txt | 1 + tests/mainwindow/CMakeLists.txt | 10 + tests/mainwindow/mainwindowtest.cpp | 374 ++++++++++++++++++++++++++++ 5 files changed, 410 insertions(+), 21 deletions(-) create mode 100644 tests/CMakeLists.txt create mode 100644 tests/mainwindow/CMakeLists.txt create mode 100644 tests/mainwindow/mainwindowtest.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 750e143441..5f7a16a9fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,8 @@ endif() add_subdirectory(CuteLogger) add_subdirectory(src) add_subdirectory(translations) +enable_testing() +add_subdirectory(tests) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1662ae669f..f551c64ab7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,6 @@ find_package(Qt6 REQUIRED COMPONENTS Core) -add_executable(shotcut WIN32 MACOSX_BUNDLE +add_library(shotcut_objects OBJECT abstractproducerwidget.cpp abstractproducerwidget.h actions.cpp actions.h autosavefile.cpp autosavefile.h @@ -79,7 +79,6 @@ add_executable(shotcut WIN32 MACOSX_BUNDLE jobs/screencapturejob.cpp jobs/screencapturejob.h jobs/videoqualityjob.cpp jobs/videoqualityjob.h jobs/whisperjob.cpp jobs/whisperjob.h - main.cpp mainwindow.cpp mainwindow.h mainwindow.ui mltcontroller.cpp mltcontroller.h @@ -233,6 +232,9 @@ add_executable(shotcut WIN32 MACOSX_BUNDLE ../icons/resources.qrc ) +add_executable(shotcut WIN32 MACOSX_BUNDLE main.cpp) +target_link_libraries(shotcut PRIVATE shotcut_objects) + add_custom_target(OTHER_FILES SOURCES ../.github/ISSUE_TEMPLATE.md @@ -266,8 +268,8 @@ add_custom_target(OTHER_FILES ../scripts/staple.sh ) -target_link_libraries(shotcut - PRIVATE +target_link_libraries(shotcut_objects + PUBLIC CuteLogger PkgConfig::mlt++ PkgConfig::FFTW @@ -284,22 +286,22 @@ target_link_libraries(shotcut Qt6::Xml ) if(UNIX AND NOT APPLE) - target_link_libraries(shotcut PRIVATE Qt6::DBus X11::X11) - target_sources(shotcut PRIVATE linuxtools.cpp linuxtools.h) + target_link_libraries(shotcut_objects PUBLIC Qt6::DBus X11::X11) + target_sources(shotcut_objects PRIVATE linuxtools.cpp linuxtools.h) endif() file(GLOB_RECURSE QML_SRC "qml/*") -target_sources(shotcut PRIVATE ${QML_SRC}) +target_sources(shotcut_objects PRIVATE ${QML_SRC}) -target_include_directories(shotcut PRIVATE ${CMAKE_SOURCE_DIR}/CuteLogger/include) -target_compile_definitions(shotcut PRIVATE SHOTCUT_VERSION="${SHOTCUT_VERSION}") +target_include_directories(shotcut_objects PUBLIC ${CMAKE_SOURCE_DIR}/CuteLogger/include) +target_compile_definitions(shotcut_objects PUBLIC SHOTCUT_VERSION="${SHOTCUT_VERSION}") # Add compile definitions when certain custom cache variables are ON if(EXTERNAL_LAUNCHERS) - target_compile_definitions(shotcut PRIVATE EXTERNAL_LAUNCHERS) + target_compile_definitions(shotcut_objects PUBLIC EXTERNAL_LAUNCHERS) endif() if(USE_VULKAN) - target_compile_definitions(shotcut PRIVATE USE_VULKAN) + target_compile_definitions(shotcut_objects PUBLIC USE_VULKAN) endif() if(WIN32) @@ -309,22 +311,22 @@ if(WIN32) target_sources(shotcut PRIVATE ${CMAKE_SOURCE_DIR}/packaging/windows/shotcut.rc) # Windows integration features - target_sources(shotcut PRIVATE windowstools.cpp windowstools.h) - target_sources(shotcut PRIVATE widgets/d3dvideowidget.h widgets/d3dvideowidget.cpp) - target_sources(shotcut PRIVATE widgets/openglvideowidget.h widgets/openglvideowidget.cpp) - target_link_libraries(shotcut PRIVATE d3d11 d3dcompiler ole32) + target_sources(shotcut_objects PRIVATE windowstools.cpp windowstools.h) + target_sources(shotcut_objects PRIVATE widgets/d3dvideowidget.h widgets/d3dvideowidget.cpp) + target_sources(shotcut_objects PRIVATE widgets/openglvideowidget.h widgets/openglvideowidget.cpp) + target_link_libraries(shotcut_objects PUBLIC d3d11 d3dcompiler ole32) # Runtime exception handler for debug only if(CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64") - target_include_directories(shotcut PRIVATE ${CMAKE_SOURCE_DIR}/drmingw/include) - target_link_directories(shotcut PRIVATE ${CMAKE_SOURCE_DIR}/drmingw/x64/lib) + target_include_directories(shotcut_objects PUBLIC ${CMAKE_SOURCE_DIR}/drmingw/include) + target_link_directories(shotcut_objects PUBLIC ${CMAKE_SOURCE_DIR}/drmingw/x64/lib) target_link_libraries(shotcut PRIVATE debug exchndl) endif() if(WINDOWS_DEPLOY) install(TARGETS shotcut RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}) else() - target_compile_definitions(shotcut PRIVATE NODEPLOY) + target_compile_definitions(shotcut_objects PUBLIC NODEPLOY) install(TARGETS shotcut RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() @@ -332,18 +334,18 @@ if(WIN32) install(DIRECTORY ${CMAKE_SOURCE_DIR}/filter-sets DESTINATION ${CMAKE_INSTALL_PREFIX}/share/shotcut/) install(DIRECTORY ${CMAKE_SOURCE_DIR}/voices DESTINATION ${CMAKE_INSTALL_PREFIX}/share/shotcut/) else() - target_sources(shotcut PRIVATE widgets/openglvideowidget.h widgets/openglvideowidget.cpp) + target_sources(shotcut_objects PRIVATE widgets/openglvideowidget.h widgets/openglvideowidget.cpp) endif() if(APPLE) - target_sources(shotcut PRIVATE macos.mm macos.h + target_sources(shotcut_objects PRIVATE macos.mm macos.h widgets/metalvideowidget.h widgets/metalvideowidget.mm) set_target_properties(shotcut PROPERTIES OUTPUT_NAME "Shotcut" MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/packaging/macos/Info.plist.in) find_library(FOUNDATION Foundation) find_library(COCOA Cocoa) - target_link_libraries(shotcut PRIVATE ${FOUNDATION} ${COCOA}) + target_link_libraries(shotcut_objects PUBLIC ${FOUNDATION} ${COCOA}) set(APP_ICON ${CMAKE_SOURCE_DIR}/packaging/macos/shotcut.icns) target_sources(shotcut PRIVATE ${APP_ICON}) set_source_files_properties(${APP_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000000..b009d087e4 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(mainwindow) diff --git a/tests/mainwindow/CMakeLists.txt b/tests/mainwindow/CMakeLists.txt new file mode 100644 index 0000000000..a4f7855fd3 --- /dev/null +++ b/tests/mainwindow/CMakeLists.txt @@ -0,0 +1,10 @@ +find_package(Qt6 REQUIRED COMPONENTS Test) + +add_executable(test_mainwindow mainwindowtest.cpp) +target_link_libraries(test_mainwindow PRIVATE shotcut_objects Qt6::Test) +target_include_directories(test_mainwindow PRIVATE ${CMAKE_SOURCE_DIR}/src) + +add_test(NAME MainWindowTest COMMAND test_mainwindow) +set_tests_properties(MainWindowTest PROPERTIES + ENVIRONMENT "QT_QPA_PLATFORM=offscreen" +) diff --git a/tests/mainwindow/mainwindowtest.cpp b/tests/mainwindow/mainwindowtest.cpp new file mode 100644 index 0000000000..f72a856203 --- /dev/null +++ b/tests/mainwindow/mainwindowtest.cpp @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2026 Meltytech, LLC + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ + +#include "actions.h" +#include "mainwindow.h" +#include "mltcontroller.h" + +#include +#include + +#include +#include +#include +#include + +class TestMainWindow : public QObject +{ + Q_OBJECT +private slots: + void initTestCase() + { + // Mirror the setup done by Application in main.cpp + QCoreApplication::setOrganizationName("Meltytech"); + QCoreApplication::setOrganizationDomain("shotcut.org"); + QCoreApplication::setApplicationName("Shotcut"); + QCoreApplication::setApplicationVersion(SHOTCUT_VERSION); + + // Suppress CuteLogger output: register an appender at Fatal level only + // so the "no appenders" fallback to stderr is never triggered. + auto *appender = new ConsoleAppender; + appender->setDetailsLevel(Logger::Fatal); + cuteLogger->registerAppender(appender); + } + + // ── LayoutMode enum ────────────────────────────────────────────────────── + void test_layoutModeEnumValues() + { + QCOMPARE(static_cast(MainWindow::Custom), 0); + QCOMPARE(static_cast(MainWindow::Logging), 1); + QCOMPARE(static_cast(MainWindow::Editing), 2); + QCOMPARE(static_cast(MainWindow::Effects), 3); + QCOMPARE(static_cast(MainWindow::Color), 4); + QCOMPARE(static_cast(MainWindow::Audio), 5); + QCOMPARE(static_cast(MainWindow::PlayerOnly), 6); + } + + // ── Singleton ──────────────────────────────────────────────────────────── + void test_singletonReturnsSameInstance() + { + MainWindow &w1 = MAIN; + MainWindow &w2 = MAIN; + QVERIFY(&w1 == &w2); + } + + // ── Initial file / project state ───────────────────────────────────────── + void test_initialFileNameIsEmpty() + { + QVERIFY(MAIN.fileName().isEmpty()); + } + + void test_initialMultitrackNotValid() + { + QVERIFY(!MAIN.isMultitrackValid()); + } + + void test_initialPlaylistNotValid() + { + QVERIFY(!MAIN.isPlaylistValid()); + } + + void test_initialClipboardNotNewer() + { + QVERIFY(!MAIN.isClipboardNewer()); + } + + // ── Undo stack ─────────────────────────────────────────────────────────── + void test_undoStackNotNull() + { + QVERIFY(MAIN.undoStack() != nullptr); + } + + void test_undoStackInitiallyClean() + { + QVERIFY(MAIN.undoStack()->isClean()); + } + + void test_undoStackCannotUndoInitially() + { + QVERIFY(!MAIN.undoStack()->canUndo()); + } + + void test_undoStackCannotRedoInitially() + { + QVERIFY(!MAIN.undoStack()->canRedo()); + } + + // ── Dock and controller pointers ───────────────────────────────────────── + void test_playlistDockNotNull() + { + QVERIFY(MAIN.playlistDock() != nullptr); + } + + void test_timelineDockNotNull() + { + QVERIFY(MAIN.timelineDock() != nullptr); + } + + void test_filterControllerNotNull() + { + QVERIFY(MAIN.filterController() != nullptr); + } + + void test_customProfileMenuNotNull() + { + QVERIFY(MAIN.customProfileMenu() != nullptr); + } + + void test_actionAddCustomProfileNotNull() + { + QVERIFY(MAIN.actionAddCustomProfile() != nullptr); + } + + void test_actionProfileRemoveNotNull() + { + QVERIFY(MAIN.actionProfileRemove() != nullptr); + } + + void test_profileGroupNotNull() + { + QVERIFY(MAIN.profileGroup() != nullptr); + } + + // ── Window properties ──────────────────────────────────────────────────── + void test_windowAcceptDrops() + { + QVERIFY(MAIN.acceptDrops()); + } + + void test_windowNotModifiedInitially() + { + QVERIFY(!MAIN.isWindowModified()); + } + + void test_windowDockNestingEnabled() + { + QVERIFY(MAIN.isDockNestingEnabled()); + } + + void test_windowTitleContainsApplicationName() + { + QVERIFY(MAIN.windowTitle().contains("Shotcut")); + } + + // ── File path helpers ───────────────────────────────────────────────────── + void test_untitledFileNameEndsWithUntitledMlt() + { + QVERIFY(MAIN.untitledFileName().endsWith("__untitled__.mlt")); + } + + void test_untitledFileNameIsAbsolutePath() + { + QVERIFY(QFileInfo(MAIN.untitledFileName()).isAbsolute()); + } + + // ── Dock visibility ─────────────────────────────────────────────────────── + void test_keyframesDockNotVisibleInitially() + { + QVERIFY(!MAIN.keyframesDockIsVisible()); + } + + // ── Player actions registered ───────────────────────────────────────────── + void test_actionPlayerPlayPauseRegistered() + { + QVERIFY(Actions["playerPlayPauseAction"] != nullptr); + } + + void test_actionPlayerLoopRegistered() + { + QVERIFY(Actions["playerLoopAction"] != nullptr); + } + + void test_actionPlayerFastForwardRegistered() + { + QVERIFY(Actions["playerFastForwardAction"] != nullptr); + } + + void test_actionPlayerRewindRegistered() + { + QVERIFY(Actions["playerRewindAction"] != nullptr); + } + + void test_actionPlayerSkipNextRegistered() + { + QVERIFY(Actions["playerSkipNextAction"] != nullptr); + } + + void test_actionPlayerSkipPreviousRegistered() + { + QVERIFY(Actions["playerSkipPreviousAction"] != nullptr); + } + + void test_actionPlayerSeekStartRegistered() + { + QVERIFY(Actions["playerSeekStartAction"] != nullptr); + } + + void test_actionPlayerSeekEndRegistered() + { + QVERIFY(Actions["playerSeekEndAction"] != nullptr); + } + + void test_actionPlayerNextFrameRegistered() + { + QVERIFY(Actions["playerNextFrameAction"] != nullptr); + } + + void test_actionPlayerPreviousFrameRegistered() + { + QVERIFY(Actions["playerPreviousFrameAction"] != nullptr); + } + + // ── MainWindow actions registered ───────────────────────────────────────── + void test_actionTimelineReloadRegistered() + { + QVERIFY(Actions["timelineReload"] != nullptr); + } + + void test_actionPropertiesRenameClipRegistered() + { + QVERIFY(Actions["propertiesRenameClipAction"] != nullptr); + } + + void test_actionRecentFindRegistered() + { + QVERIFY(Actions["recentFindAction"] != nullptr); + } + + void test_actionAnalyzeFiltersRegistered() + { + QVERIFY(Actions["analyzeFilters"] != nullptr); + } + + // ── Timeline dock actions registered ───────────────────────────────────── + void test_actionTimelineAddAudioTrackRegistered() + { + QVERIFY(Actions["timelineAddAudioTrackAction"] != nullptr); + } + + void test_actionTimelineAddVideoTrackRegistered() + { + QVERIFY(Actions["timelineAddVideoTrackAction"] != nullptr); + } + + void test_actionTimelineInsertTrackRegistered() + { + QVERIFY(Actions["timelineInsertTrackAction"] != nullptr); + } + + void test_actionTimelineSelectAllRegistered() + { + QVERIFY(Actions["timelineSelectAllAction"] != nullptr); + } + + void test_actionTimelineSelectNoneRegistered() + { + QVERIFY(Actions["timelineSelectNoneAction"] != nullptr); + } + + void test_actionTimelineToggleTrackLockedRegistered() + { + QVERIFY(Actions["timelineToggleTrackLockedAction"] != nullptr); + } + + void test_actionTimelineToggleTrackMuteRegistered() + { + QVERIFY(Actions["timelineToggleTrackMuteAction"] != nullptr); + } + + // ── Filters dock actions registered ────────────────────────────────────── + void test_actionFiltersAddFilterRegistered() + { + QVERIFY(Actions["filtersAddFilterAction"] != nullptr); + } + + void test_actionFiltersRemoveFilterRegistered() + { + QVERIFY(Actions["filtersRemoveFilterAction"] != nullptr); + } + + void test_actionFiltersCopyFiltersRegistered() + { + QVERIFY(Actions["filtersCopyFiltersAction"] != nullptr); + } + + void test_actionFiltersPasteFiltersRegistered() + { + QVERIFY(Actions["filtersPasteFiltersAction"] != nullptr); + } + + // ── Files and playlist dock actions registered ──────────────────────────── + void test_actionFilesSearchRegistered() + { + QVERIFY(Actions["filesSearch"] != nullptr); + } + + void test_actionPlaylistSearchRegistered() + { + QVERIFY(Actions["playlistSearch"] != nullptr); + } + + // ── MLT profile ─────────────────────────────────────────────────────────── + void test_mltProfileWidthPositive() + { + QVERIFY(MLT.profile().width() > 0); + } + + void test_mltProfileHeightPositive() + { + QVERIFY(MLT.profile().height() > 0); + } + + void test_mltProfileFpsPositive() + { + QVERIFY(MLT.profile().fps() > 0.0); + } + + // ── Timeline empty-state helpers ────────────────────────────────────────── + void test_bottomVideoTrackIndexNegativeWithEmptyTimeline() + { + QCOMPARE(MAIN.bottomVideoTrackIndex(), -1); + } + + void test_mltIndexForTrackNegativeWithEmptyTimeline() + { + QCOMPARE(MAIN.mltIndexForTrack(0), -1); + } + + // ── isSourceClipMyProject ───────────────────────────────────────────────── + void test_isSourceClipMyProjectReturnsFalseForEmptyPath() + { + QVERIFY(!MAIN.isSourceClipMyProject("", false)); + } + + void test_isSourceClipMyProjectReturnsFalseForNonMatchingPath() + { + QVERIFY(!MAIN.isSourceClipMyProject("/nonexistent/file.mp4", false)); + } + + // ── Signal emission ─────────────────────────────────────────────────────── + void test_setProfileEmitsProfileChanged() + { + QSignalSpy spy(&MAIN, &MainWindow::profileChanged); + MAIN.setProfile("dv_pal"); + QCOMPARE(spy.count(), 1); + MAIN.setProfile("automatic"); // restore to automatic + } +}; + +QTEST_MAIN(TestMainWindow) +#include "mainwindowtest.moc" From b80567d1586fc518ac018809fe2fbe1fae5bded9 Mon Sep 17 00:00:00 2001 From: Dan Dennedy Date: Fri, 8 May 2026 17:37:58 -0700 Subject: [PATCH 2/3] Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- CMakeLists.txt | 6 ++++-- tests/mainwindow/mainwindowtest.cpp | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f7a16a9fa..120b85596c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,8 +66,10 @@ endif() add_subdirectory(CuteLogger) add_subdirectory(src) add_subdirectory(translations) -enable_testing() -add_subdirectory(tests) +include(CTest) +if(BUILD_TESTING) + add_subdirectory(tests) +endif() feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/tests/mainwindow/mainwindowtest.cpp b/tests/mainwindow/mainwindowtest.cpp index f72a856203..788ec8013a 100644 --- a/tests/mainwindow/mainwindowtest.cpp +++ b/tests/mainwindow/mainwindowtest.cpp @@ -162,7 +162,7 @@ private slots: void test_windowTitleContainsApplicationName() { - QVERIFY(MAIN.windowTitle().contains("Shotcut")); + QVERIFY(MAIN.windowTitle().contains(QCoreApplication::applicationName())); } // ── File path helpers ───────────────────────────────────────────────────── @@ -366,7 +366,7 @@ private slots: QSignalSpy spy(&MAIN, &MainWindow::profileChanged); MAIN.setProfile("dv_pal"); QCOMPARE(spy.count(), 1); - MAIN.setProfile("automatic"); // restore to automatic + MAIN.setProfile(""); // restore to automatic } }; From 2234ab5cfc3ac11ce426cb9c4cb00e9bc5255962 Mon Sep 17 00:00:00 2001 From: Dan Dennedy Date: Fri, 8 May 2026 17:53:09 -0700 Subject: [PATCH 3/3] Enable test mode for QStandardPaths in MainWindow tests --- scripts/build-shotcut-msys2.sh | 2 +- scripts/build-shotcut.sh | 2 +- tests/mainwindow/mainwindowtest.cpp | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/build-shotcut-msys2.sh b/scripts/build-shotcut-msys2.sh index 639cdd722b..0a494db701 100755 --- a/scripts/build-shotcut-msys2.sh +++ b/scripts/build-shotcut-msys2.sh @@ -615,7 +615,7 @@ function set_globals { ##### # shotcut - CONFIG[4]="cmake -G Ninja -D CMAKE_INSTALL_PREFIX=$FINAL_INSTALL_DIR -DCMAKE_PREFIX_PATH=$QTDIR -D SHOTCUT_VERSION=$SHOTCUT_VERSION $CMAKE_DEBUG_FLAG" + CONFIG[4]="cmake -G Ninja -D CMAKE_INSTALL_PREFIX=$FINAL_INSTALL_DIR -DCMAKE_PREFIX_PATH=$QTDIR -D SHOTCUT_VERSION=$SHOTCUT_VERSION -D BUILD_TESTING=OFF $CMAKE_DEBUG_FLAG" CFLAGS_[4]="$ASAN_CFLAGS $CFLAGS" LDFLAGS_[4]="$ASAN_LDFLAGS $LDFLAGS" BUILD[4]="ninja -j $MAKEJ" diff --git a/scripts/build-shotcut.sh b/scripts/build-shotcut.sh index c5209f8e72..6c7d4d7c4c 100755 --- a/scripts/build-shotcut.sh +++ b/scripts/build-shotcut.sh @@ -918,7 +918,7 @@ function set_globals { ##### # shotcut - CONFIG[7]="cmake -G Ninja -D CMAKE_PREFIX_PATH=$QTDIR -D SHOTCUT_VERSION=$SHOTCUT_VERSION $CMAKE_DEBUG_FLAG" + CONFIG[7]="cmake -G Ninja -D CMAKE_PREFIX_PATH=$QTDIR -D SHOTCUT_VERSION=$SHOTCUT_VERSION -D BUILD_TESTING=OFF $CMAKE_DEBUG_FLAG" if test "$TARGET_OS" = "Darwin" ; then CONFIG[7]="${CONFIG[7]} -D CMAKE_INSTALL_PREFIX=." CONFIG[7]="${CONFIG[7]} -D CMAKE_OSX_ARCHITECTURES='arm64;x86_64'" diff --git a/tests/mainwindow/mainwindowtest.cpp b/tests/mainwindow/mainwindowtest.cpp index 788ec8013a..35235855aa 100644 --- a/tests/mainwindow/mainwindowtest.cpp +++ b/tests/mainwindow/mainwindowtest.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -33,6 +34,8 @@ class TestMainWindow : public QObject private slots: void initTestCase() { + QStandardPaths::setTestModeEnabled(true); + // Mirror the setup done by Application in main.cpp QCoreApplication::setOrganizationName("Meltytech"); QCoreApplication::setOrganizationDomain("shotcut.org");