From 7a0e08b0d8428822baff3db725151cc3e5583897 Mon Sep 17 00:00:00 2001 From: WarmUpTill <19472752+WarmUpTill@users.noreply.github.com> Date: Tue, 10 Mar 2026 21:34:03 +0100 Subject: [PATCH] Adapt to enable testing and add more tests --- lib/macro/macro-edit.hpp | 3 - lib/macro/macro-selection.cpp | 2 + lib/macro/macro.cpp | 2 + lib/utils/export-symbol-helper.hpp | 9 - lib/utils/log-helper.hpp | 3 +- lib/utils/splitter-helpers.cpp | 4 +- lib/utils/sync-helpers.cpp | 14 + lib/utils/sync-helpers.hpp | 1 - lib/variables/variable-spinbox.cpp | 4 +- tests/CMakeLists.txt | 156 ++++++-- tests/mocks/obs-data.cpp | 502 ------------------------ tests/mocks/obs-data.h | 253 ------------ tests/stubs/macro-action-macro.cpp | 123 ++++++ tests/stubs/macro-dock-settings.cpp | 77 ++++ tests/stubs/macro-edit.cpp | 134 +++++++ tests/{mocks => stubs}/path-helpers.cpp | 0 tests/stubs/plugin-state-helpers.cpp | 86 ++++ tests/{mocks => stubs}/ui-helpers.cpp | 5 + tests/test-macro-condition.cpp | 351 +++++++++++++++++ tests/test-macro.cpp | 416 ++++++++++++++++++++ 20 files changed, 1346 insertions(+), 799 deletions(-) delete mode 100644 tests/mocks/obs-data.cpp delete mode 100644 tests/mocks/obs-data.h create mode 100644 tests/stubs/macro-action-macro.cpp create mode 100644 tests/stubs/macro-dock-settings.cpp create mode 100644 tests/stubs/macro-edit.cpp rename tests/{mocks => stubs}/path-helpers.cpp (100%) create mode 100644 tests/stubs/plugin-state-helpers.cpp rename tests/{mocks => stubs}/ui-helpers.cpp (93%) create mode 100644 tests/test-macro-condition.cpp create mode 100644 tests/test-macro.cpp diff --git a/lib/macro/macro-edit.hpp b/lib/macro/macro-edit.hpp index 48bef675..7a748c38 100644 --- a/lib/macro/macro-edit.hpp +++ b/lib/macro/macro-edit.hpp @@ -8,9 +8,6 @@ namespace advss { class Macro; class MacroSegment; -/******************************************************************************* - * Advanced Scene Switcher window - *******************************************************************************/ class MacroEdit : public QWidget { Q_OBJECT diff --git a/lib/macro/macro-selection.cpp b/lib/macro/macro-selection.cpp index d58a8df1..0b14121f 100644 --- a/lib/macro/macro-selection.cpp +++ b/lib/macro/macro-selection.cpp @@ -51,6 +51,7 @@ void MacroSelection::HideSelectedMacro() return; } +#ifndef UNIT_TEST const auto m = ssWindow->ui->macros->GetCurrentMacro(); if (!m) { return; @@ -61,6 +62,7 @@ void MacroSelection::HideSelectedMacro() } qobject_cast(view())->setRowHidden(idx, true); +#endif // !UNIT_TEST } void MacroSelection::HideGroups() diff --git a/lib/macro/macro.cpp b/lib/macro/macro.cpp index c061e6c0..0e00ab17 100644 --- a/lib/macro/macro.cpp +++ b/lib/macro/macro.cpp @@ -1141,9 +1141,11 @@ void Macro::ClearHotkeys() const void setHotkeyDescriptionHelper(const char *formatModuleText, const std::string name, const obs_hotkey_id id) { +#ifndef UNIT_TEST QString format{obs_module_text(formatModuleText)}; QString hotkeyDesc = format.arg(QString::fromStdString(name)); obs_hotkey_set_description(id, hotkeyDesc.toStdString().c_str()); +#endif // !UNIT_TEST } void Macro::SetHotkeysDesc() const diff --git a/lib/utils/export-symbol-helper.hpp b/lib/utils/export-symbol-helper.hpp index d5f4e2b9..151614f7 100644 --- a/lib/utils/export-symbol-helper.hpp +++ b/lib/utils/export-symbol-helper.hpp @@ -1,12 +1,5 @@ #pragma once -#ifdef UNIT_TEST - -#define EXPORT -#define ADVSS_EXPORT - -#else - #ifdef _MSC_VER #define EXPORT __declspec(dllexport) #else @@ -19,5 +12,3 @@ #else #define ADVSS_EXPORT Q_DECL_IMPORT #endif - -#endif // UNIT_TEST diff --git a/lib/utils/log-helper.hpp b/lib/utils/log-helper.hpp index 011a6eee..de611a78 100644 --- a/lib/utils/log-helper.hpp +++ b/lib/utils/log-helper.hpp @@ -1,7 +1,5 @@ #pragma once -#ifndef UNIT_TEST #include -#endif namespace advss { @@ -9,6 +7,7 @@ namespace advss { #define blog(level, msg, ...) #define vblog(level, msg, ...) #define ablog(level, msg, ...) +#define mblog(level, msg, ...) #else // Print log with "[adv-ss] " prefix diff --git a/lib/utils/splitter-helpers.cpp b/lib/utils/splitter-helpers.cpp index a77c7b6f..a065ffda 100644 --- a/lib/utils/splitter-helpers.cpp +++ b/lib/utils/splitter-helpers.cpp @@ -37,8 +37,8 @@ void CenterSplitterPosition(QSplitter *splitter) void SetSplitterPositionByFraction(QSplitter *splitter, double fraction) { - int value1 = (double)QWIDGETSIZE_MAX * fraction; - int value2 = (double)QWIDGETSIZE_MAX * (1.0 - fraction); + int value1 = (int)((double)QWIDGETSIZE_MAX * fraction); + int value2 = (int)((double)QWIDGETSIZE_MAX * (1.0 - fraction)); splitter->setSizes(QList() << value1 << value2); } diff --git a/lib/utils/sync-helpers.cpp b/lib/utils/sync-helpers.cpp index 71c59cf5..b7052b87 100644 --- a/lib/utils/sync-helpers.cpp +++ b/lib/utils/sync-helpers.cpp @@ -2,8 +2,22 @@ namespace advss { +#ifdef UNIT_TEST +std::mutex *GetSwitcherMutex() +{ + static std::mutex m; + return &m; +} +std::unique_lock *GetSwitcherLoopLock() +{ + static std::mutex m; + static std::unique_lock lock(m); + return &lock; +} +#else std::mutex *GetSwitcherMutex(); std::unique_lock *GetSwitcherLoopLock(); +#endif std::mutex *GetMutex() { diff --git a/lib/utils/sync-helpers.hpp b/lib/utils/sync-helpers.hpp index df531bc1..bd23c1a0 100644 --- a/lib/utils/sync-helpers.hpp +++ b/lib/utils/sync-helpers.hpp @@ -2,7 +2,6 @@ #include "export-symbol-helper.hpp" #include -#include #include namespace advss { diff --git a/lib/variables/variable-spinbox.cpp b/lib/variables/variable-spinbox.cpp index 2d9830b1..048b5b11 100644 --- a/lib/variables/variable-spinbox.cpp +++ b/lib/variables/variable-spinbox.cpp @@ -81,13 +81,13 @@ void GenericVariableSpinbox::DisableVariableSelection() void GenericVariableSpinbox::setMinimum(double value) { - _fixedValueInt->setMinimum(value); + _fixedValueInt->setMinimum((int)value); _fixedValueDouble->setMinimum(value); } void GenericVariableSpinbox::setMaximum(double value) { - _fixedValueInt->setMaximum(value); + _fixedValueInt->setMaximum((int)value); _fixedValueDouble->setMaximum(value); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7bac03a8..9fab07eb 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,22 +1,27 @@ cmake_minimum_required(VERSION 3.14) project(advanced-scene-switcher-tests) -get_target_property(ADVSS_SOURCE_DIR advanced-scene-switcher-lib SOURCE_DIR) +set(CMAKE_AUTOUIC ON) + add_executable(${PROJECT_NAME}) -target_compile_definitions(${PROJECT_NAME} PRIVATE UNIT_TEST) +target_compile_definitions(${PROJECT_NAME} PRIVATE UNIT_TEST + ADVSS_EXPORT_SYMBOLS=1) target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17) -target_sources( - ${PROJECT_NAME} PRIVATE test-main.cpp mocks/obs-data.cpp - mocks/path-helpers.cpp mocks/ui-helpers.cpp) +target_sources(${PROJECT_NAME} PRIVATE test-main.cpp) + +get_target_property(ADVSS_SOURCE_DIR advanced-scene-switcher-lib SOURCE_DIR) +get_target_property(ADVSS_BINARY_DIR advanced-scene-switcher-lib BINARY_DIR) + target_include_directories( ${PROJECT_NAME} - PRIVATE mocks ${ADVSS_SOURCE_DIR}/lib/utils ${ADVSS_SOURCE_DIR}/lib/variables + PRIVATE ${ADVSS_SOURCE_DIR}/lib ${ADVSS_SOURCE_DIR}/lib/macro + ${ADVSS_SOURCE_DIR}/lib/utils ${ADVSS_SOURCE_DIR}/lib/variables ${ADVSS_SOURCE_DIR}/plugins/base/utils) -# --- Qt --- # +setup_obs_lib_dependency(${PROJECT_NAME}) -target_link_libraries(${PROJECT_NAME} PUBLIC Qt::Core Qt::Widgets) +# --- Qt --- # if(TARGET Qt6::Core) set(_QT_VERSION @@ -28,25 +33,26 @@ elseif(TARGET Qt5::Core) CACHE INTERNAL "") endif() -macro(add_qt_lib lib_name) - add_custom_command( - TARGET ${PROJECT_NAME} - POST_BUILD - COMMAND - ${CMAKE_COMMAND} -E copy_if_different - $ - $) -endmacro() +# Include autogen headers so that generated ui_*.h files are found +target_include_directories( + ${PROJECT_NAME} + PRIVATE "${ADVSS_BINARY_DIR}/advanced-scene-switcher-lib_autogen/include") +foreach(_conf Release RelWithDebInfo Debug MinSizeRe) + target_include_directories( + ${PROJECT_NAME} + PRIVATE + "${ADVSS_BINARY_DIR}/advanced-scene-switcher-lib_autogen/include_${_conf}" + ) +endforeach() -add_qt_lib(Core) -add_qt_lib(Gui) -add_qt_lib(Widgets) +target_link_libraries(${PROJECT_NAME} PUBLIC Qt::Core Qt::Widgets) set_target_properties( ${PROJECT_NAME} PROPERTIES AUTOMOC ON AUTOUIC ON - AUTORCC ON) + AUTORCC ON + AUTOUIC_SEARCH_PATHS "${ADVSS_SOURCE_DIR}/forms") # --- condition-logic --- # @@ -83,12 +89,11 @@ target_include_directories(${PROJECT_NAME} PRIVATE ${ADVSS_SOURCE_DIR}/deps/exprtk) if(MSVC) - target_compile_options(${PROJECT_NAME} PUBLIC /MP /d2FH4- /wd4267 /wd4267 - /bigobj) + target_compile_options(${PROJECT_NAME} PUBLIC /MP /d2FH4- /wd4267 /bigobj) else() target_compile_options( ${PROJECT_NAME} PUBLIC -Wno-error=unused-parameter -Wno-error=conversion - -Wno-error=unused-value) + -Wno-error=unused-value -Wno-error=unused-variable) endif() # --- regex --- # @@ -122,6 +127,107 @@ target_sources( ${ADVSS_SOURCE_DIR}/lib/utils/resizing-text-edit.cpp ${ADVSS_SOURCE_DIR}/lib/variables/variable.cpp) -# --- # +# --- macro / macro-condition --- # + +target_sources( + ${PROJECT_NAME} + PRIVATE test-macro.cpp + test-macro-condition.cpp + stubs/path-helpers.cpp + stubs/ui-helpers.cpp + stubs/plugin-state-helpers.cpp + stubs/macro-action-macro.cpp + stubs/macro-edit.cpp + stubs/macro-dock-settings.cpp + ${ADVSS_SOURCE_DIR}/lib/utils/temp-variable.cpp + ${ADVSS_SOURCE_DIR}/lib/utils/sync-helpers.cpp + ${ADVSS_SOURCE_DIR}/lib/utils/help-icon.cpp + ${ADVSS_SOURCE_DIR}/lib/utils/auto-update-tooltip-label.cpp + ${ADVSS_SOURCE_DIR}/lib/utils/duration-control.cpp + ${ADVSS_SOURCE_DIR}/lib/utils/duration-control.hpp + ${ADVSS_SOURCE_DIR}/lib/utils/duration-modifier.cpp + ${ADVSS_SOURCE_DIR}/lib/utils/duration-modifier.hpp + ${ADVSS_SOURCE_DIR}/lib/utils/duration.cpp + ${ADVSS_SOURCE_DIR}/lib/utils/duration.hpp + ${ADVSS_SOURCE_DIR}/lib/utils/list-controls.cpp + ${ADVSS_SOURCE_DIR}/lib/utils/list-editor.cpp + ${ADVSS_SOURCE_DIR}/lib/utils/layout-helpers.cpp + ${ADVSS_SOURCE_DIR}/lib/utils/log-helper.cpp + ${ADVSS_SOURCE_DIR}/lib/utils/mouse-wheel-guard.cpp + ${ADVSS_SOURCE_DIR}/lib/utils/section.cpp + ${ADVSS_SOURCE_DIR}/lib/utils/splitter-helpers.cpp + ${ADVSS_SOURCE_DIR}/lib/utils/resizable-widget.cpp + ${ADVSS_SOURCE_DIR}/lib/utils/string-list.cpp + ${ADVSS_SOURCE_DIR}/lib/macro/macro-action.cpp + ${ADVSS_SOURCE_DIR}/lib/macro/macro-action-macro.hpp + ${ADVSS_SOURCE_DIR}/lib/macro/macro-action-factory.cpp + ${ADVSS_SOURCE_DIR}/lib/macro/macro-condition.cpp + ${ADVSS_SOURCE_DIR}/lib/macro/macro-condition-factory.cpp + ${ADVSS_SOURCE_DIR}/lib/macro/macro-edit.hpp + ${ADVSS_SOURCE_DIR}/lib/macro/macro-helpers.cpp + ${ADVSS_SOURCE_DIR}/lib/macro/macro-input.cpp + ${ADVSS_SOURCE_DIR}/lib/macro/macro-ref.cpp + ${ADVSS_SOURCE_DIR}/lib/macro/macro-segment.cpp + ${ADVSS_SOURCE_DIR}/lib/macro/macro-selection.cpp + ${ADVSS_SOURCE_DIR}/lib/macro/macro-signals.cpp + ${ADVSS_SOURCE_DIR}/lib/macro/macro.cpp + ${ADVSS_SOURCE_DIR}/lib/variables/variable-line-edit.cpp + ${ADVSS_SOURCE_DIR}/lib/variables/variable-spinbox.cpp + ${ADVSS_SOURCE_DIR}/lib/variables/variable-string.cpp) + +# --- Testing --- # enable_testing() +add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME}) + +if(WIN32) + # Copy all CMake-known transitive DLLs (Qt, OBS, etc.) next to the binary. + # This makes the test executable runnable directly without PATH changes. + add_custom_command( + TARGET ${PROJECT_NAME} + POST_BUILD + COMMAND + ${CMAKE_COMMAND} -E copy_if_different + $ $ + COMMAND_EXPAND_LISTS) + + # Copy remaining OBS deps (zlib, srt, librist, ffmpeg, etc.) that are not + # CMake targets but are required at runtime. Derive the path from ZLIB::ZLIB + # which lives in the same deps directory. + get_target_property(_zlib_lib ZLIB::ZLIB IMPORTED_LOCATION_RELWITHDEBINFO) + if(NOT _zlib_lib) + get_target_property(_zlib_lib ZLIB::ZLIB IMPORTED_LOCATION_RELEASE) + endif() + if(_zlib_lib) + get_filename_component(_obs_deps_bin "${_zlib_lib}" DIRECTORY) + get_filename_component(_obs_deps_bin "${_obs_deps_bin}/../bin" ABSOLUTE) + add_custom_command( + TARGET ${PROJECT_NAME} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory "${_obs_deps_bin}" + $) + else() + message( + WARNING "Could not determine OBS deps bin directory from ZLIB::ZLIB - " + "some DLLs may be missing at runtime") + endif() + +elseif(APPLE) + # On macOS, binaries use RPATH so copying is usually not needed. Fall back to + # DYLD_LIBRARY_PATH in case RPATH is not set correctly. + set_tests_properties( + ${PROJECT_NAME} + PROPERTIES + ENVIRONMENT + "DYLD_LIBRARY_PATH=$:$" + ) + +else() + # On Linux, same approach using LD_LIBRARY_PATH. + set_tests_properties( + ${PROJECT_NAME} + PROPERTIES + ENVIRONMENT + "LD_LIBRARY_PATH=$:$" + ) +endif() diff --git a/tests/mocks/obs-data.cpp b/tests/mocks/obs-data.cpp deleted file mode 100644 index 534802d1..00000000 --- a/tests/mocks/obs-data.cpp +++ /dev/null @@ -1,502 +0,0 @@ -#include "obs-data.h" - -struct obs_data_item {}; - -struct obs_data {}; - -struct obs_data_array {}; - -struct obs_data_number {}; - -obs_data_t *obs_data_create() -{ - return nullptr; -} - -obs_data_t *obs_data_create_from_json(const char *json_string) -{ - return nullptr; -} - -obs_data_t *obs_data_create_from_json_file(const char *json_file) -{ - return nullptr; -} - -obs_data_t *obs_data_create_from_json_file_safe(const char *json_file, - const char *backup_ext) -{ - return nullptr; -} - -void obs_data_addref(obs_data_t *data) {} - -void obs_data_release(obs_data_t *data) {} - -const char *obs_data_get_json(obs_data_t *data) -{ - return ""; -} - -const char *obs_data_get_json_pretty(obs_data_t *data) -{ - return ""; -} - -const char *obs_data_get_last_json(obs_data_t *data) -{ - return ""; -} - -bool obs_data_save_json(obs_data_t *data, const char *file) -{ - return false; -} - -bool obs_data_save_json_safe(obs_data_t *data, const char *file, - const char *temp_ext, const char *backup_ext) -{ - return false; -} - -bool obs_data_save_json_pretty_safe(obs_data_t *data, const char *file, - const char *temp_ext, - const char *backup_ext) -{ - return false; -} - -obs_data_t *obs_data_get_defaults(obs_data_t *data) -{ - return nullptr; -} - -void obs_data_apply(obs_data_t *target, obs_data_t *apply_data) {} - -void obs_data_erase(obs_data_t *data, const char *name) {} - -void obs_data_clear(obs_data_t *target) {} - -void obs_data_set_string(obs_data_t *data, const char *name, const char *val) {} - -void obs_data_set_int(obs_data_t *data, const char *name, long long val) {} - -void obs_data_set_double(obs_data_t *data, const char *name, double val) {} - -void obs_data_set_bool(obs_data_t *data, const char *name, bool val) {} - -void obs_data_set_obj(obs_data_t *data, const char *name, obs_data_t *obj) {} - -void obs_data_set_array(obs_data_t *data, const char *name, - obs_data_array_t *array) -{ -} - -void obs_data_set_default_string(obs_data_t *data, const char *name, - const char *val) -{ -} - -void obs_data_set_default_int(obs_data_t *data, const char *name, long long val) -{ -} - -void obs_data_set_default_double(obs_data_t *data, const char *name, double val) -{ -} - -void obs_data_set_default_bool(obs_data_t *data, const char *name, bool val) {} - -void obs_data_set_default_obj(obs_data_t *data, const char *name, - obs_data_t *obj) -{ -} - -void obs_data_set_default_array(obs_data_t *data, const char *name, - obs_data_array_t *arr) -{ -} - -void obs_data_set_autoselect_string(obs_data_t *data, const char *name, - const char *val) -{ -} - -void obs_data_set_autoselect_int(obs_data_t *data, const char *name, - long long val) -{ -} - -void obs_data_set_autoselect_double(obs_data_t *data, const char *name, - double val) -{ -} - -void obs_data_set_autoselect_bool(obs_data_t *data, const char *name, bool val) -{ -} - -void obs_data_set_autoselect_obj(obs_data_t *data, const char *name, - obs_data_t *obj) -{ -} - -void obs_data_set_autoselect_array(obs_data_t *data, const char *name, - obs_data_array_t *arr) -{ -} - -const char *obs_data_get_string(obs_data_t *data, const char *name) -{ - return ""; -} - -long long obs_data_get_int(obs_data_t *data, const char *name) -{ - return 0; -} - -double obs_data_get_double(obs_data_t *data, const char *name) -{ - return 0.0; -} - -bool obs_data_get_bool(obs_data_t *data, const char *name) -{ - return false; -} - -obs_data_t *obs_data_get_obj(obs_data_t *data, const char *name) -{ - return nullptr; -} - -obs_data_array_t *obs_data_get_array(obs_data_t *data, const char *name) -{ - return nullptr; -} - -const char *obs_data_get_default_string(obs_data_t *data, const char *name) -{ - return ""; -} - -long long obs_data_get_default_int(obs_data_t *data, const char *name) -{ - return 0; -} - -double obs_data_get_default_double(obs_data_t *data, const char *name) -{ - return 0.0; -} - -bool obs_data_get_default_bool(obs_data_t *data, const char *name) -{ - return false; -} - -obs_data_t *obs_data_get_default_obj(obs_data_t *data, const char *name) -{ - return nullptr; -} - -obs_data_array_t *obs_data_get_default_array(obs_data_t *data, const char *name) -{ - return nullptr; -} - -const char *obs_data_get_autoselect_string(obs_data_t *data, const char *name) -{ - return ""; -} - -long long obs_data_get_autoselect_int(obs_data_t *data, const char *name) -{ - return 0; -} - -double obs_data_get_autoselect_double(obs_data_t *data, const char *name) -{ - return 0.0; -} - -bool obs_data_get_autoselect_bool(obs_data_t *data, const char *name) -{ - return false; -} - -obs_data_t *obs_data_get_autoselect_obj(obs_data_t *data, const char *name) -{ - return nullptr; -} - -obs_data_array_t *obs_data_get_autoselect_array(obs_data_t *data, - const char *name) -{ - return nullptr; -} - -obs_data_array_t *obs_data_array_create() -{ - return nullptr; -} - -void obs_data_array_addref(obs_data_array_t *array) {} - -void obs_data_array_release(obs_data_array_t *array) {} - -size_t obs_data_array_count(obs_data_array_t *array) -{ - return 0; -} - -obs_data_t *obs_data_array_item(obs_data_array_t *array, size_t idx) -{ - return nullptr; -} - -size_t obs_data_array_push_back(obs_data_array_t *array, obs_data_t *obj) -{ - return 0; -} - -void obs_data_array_insert(obs_data_array_t *array, size_t idx, obs_data_t *obj) -{ -} - -void obs_data_array_push_back_array(obs_data_array_t *array, - obs_data_array_t *array2) -{ -} - -void obs_data_array_erase(obs_data_array_t *array, size_t idx) {} - -void obs_data_array_enum(obs_data_array_t *array, - void (*cb)(obs_data_t *data, void *param), void *param) -{ -} - -/* ------------------------------------------------------------------------- */ -/* Item status inspection */ - -bool obs_data_has_user_value(obs_data_t *data, const char *name) -{ - return false; -} - -bool obs_data_has_default_value(obs_data_t *data, const char *name) -{ - return false; -} - -bool obs_data_has_autoselect_value(obs_data_t *data, const char *name) -{ - return false; -} - -bool obs_data_item_has_user_value(obs_data_item_t *item) -{ - return false; -} - -bool obs_data_item_has_default_value(obs_data_item_t *item) -{ - return false; -} - -bool obs_data_item_has_autoselect_value(obs_data_item_t *item) -{ - return false; -} - -/* ------------------------------------------------------------------------- */ -/* Clearing data values */ - -void obs_data_unset_user_value(obs_data_t *data, const char *name) {} - -void obs_data_unset_default_value(obs_data_t *data, const char *name) {} - -void obs_data_unset_autoselect_value(obs_data_t *data, const char *name) {} - -void obs_data_item_unset_user_value(obs_data_item_t *item) {} - -void obs_data_item_unset_default_value(obs_data_item_t *item) {} - -void obs_data_item_unset_autoselect_value(obs_data_item_t *item) {} - -/* ------------------------------------------------------------------------- */ -/* Item iteration */ - -obs_data_item_t *obs_data_first(obs_data_t *data) -{ - return nullptr; -} - -obs_data_item_t *obs_data_item_byname(obs_data_t *data, const char *name) -{ - return nullptr; -} - -bool obs_data_item_next(obs_data_item_t **item) -{ - return false; -} - -void obs_data_item_release(obs_data_item_t **item) {} - -void obs_data_item_remove(obs_data_item_t **item) {} - -enum obs_data_type obs_data_item_gettype(obs_data_item_t *item) -{ - return OBS_DATA_NULL; -} - -enum obs_data_number_type obs_data_item_numtype(obs_data_item_t *item) -{ - return OBS_DATA_NUM_INVALID; -} - -const char *obs_data_item_get_name(obs_data_item_t *item) -{ - return nullptr; -} - -void obs_data_item_set_string(obs_data_item_t **item, const char *val) {} - -void obs_data_item_set_int(obs_data_item_t **item, long long val) {} - -void obs_data_item_set_double(obs_data_item_t **item, double val) {} - -void obs_data_item_set_bool(obs_data_item_t **item, bool val) {} - -void obs_data_item_set_obj(obs_data_item_t **item, obs_data_t *val) {} - -void obs_data_item_set_array(obs_data_item_t **item, obs_data_array_t *val) {} - -void obs_data_item_set_default_string(obs_data_item_t **item, const char *val) -{ -} - -void obs_data_item_set_default_int(obs_data_item_t **item, long long val) {} - -void obs_data_item_set_default_double(obs_data_item_t **item, double val) {} - -void obs_data_item_set_default_bool(obs_data_item_t **item, bool val) {} - -void obs_data_item_set_default_obj(obs_data_item_t **item, obs_data_t *val) {} - -void obs_data_item_set_default_array(obs_data_item_t **item, - obs_data_array_t *val) -{ -} - -void obs_data_item_set_autoselect_string(obs_data_item_t **item, - const char *val) -{ -} - -void obs_data_item_set_autoselect_int(obs_data_item_t **item, long long val) {} - -void obs_data_item_set_autoselect_double(obs_data_item_t **item, double val) {} - -void obs_data_item_set_autoselect_bool(obs_data_item_t **item, bool val) {} - -void obs_data_item_set_autoselect_obj(obs_data_item_t **item, obs_data_t *val) -{ -} - -void obs_data_item_set_autoselect_array(obs_data_item_t **item, - obs_data_array_t *val) -{ -} - -const char *obs_data_item_get_string(obs_data_item_t *item) -{ - return ""; -} - -long long obs_data_item_get_int(obs_data_item_t *item) -{ - return 0; -} - -double obs_data_item_get_double(obs_data_item_t *item) -{ - return 0.0; -} - -bool obs_data_item_get_bool(obs_data_item_t *item) -{ - return false; -} - -obs_data_t *obs_data_item_get_obj(obs_data_item_t *item) -{ - return nullptr; -} - -obs_data_array_t *obs_data_item_get_array(obs_data_item_t *item) -{ - return nullptr; -} - -const char *obs_data_item_get_default_string(obs_data_item_t *item) -{ - return ""; -} - -long long obs_data_item_get_default_int(obs_data_item_t *item) -{ - return 0; -} - -double obs_data_item_get_default_double(obs_data_item_t *item) -{ - return 0.0; -} - -bool obs_data_item_get_default_bool(obs_data_item_t *item) -{ - return false; -} - -obs_data_t *obs_data_item_get_default_obj(obs_data_item_t *item) -{ - return nullptr; -} - -obs_data_array_t *obs_data_item_get_default_array(obs_data_item_t *item) -{ - return nullptr; -} - -const char *obs_data_item_get_autoselect_string(obs_data_item_t *item) -{ - return ""; -} - -long long obs_data_item_get_autoselect_int(obs_data_item_t *item) -{ - return 0; -} - -double obs_data_item_get_autoselect_double(obs_data_item_t *item) -{ - return 0.0; -} - -bool obs_data_item_get_autoselect_bool(obs_data_item_t *item) -{ - return false; -} - -obs_data_t *obs_data_item_get_autoselect_obj(obs_data_item_t *item) -{ - return nullptr; -} - -obs_data_array_t *obs_data_item_get_autoselect_array(obs_data_item_t *item) -{ - return nullptr; -} diff --git a/tests/mocks/obs-data.h b/tests/mocks/obs-data.h deleted file mode 100644 index 71b5ce59..00000000 --- a/tests/mocks/obs-data.h +++ /dev/null @@ -1,253 +0,0 @@ -#pragma once -#include "export-symbol-helper.hpp" - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct obs_data; -struct obs_data_item; -struct obs_data_array; -typedef struct obs_data obs_data_t; -typedef struct obs_data_item obs_data_item_t; -typedef struct obs_data_array obs_data_array_t; - -enum obs_data_type { - OBS_DATA_NULL, - OBS_DATA_STRING, - OBS_DATA_NUMBER, - OBS_DATA_BOOLEAN, - OBS_DATA_OBJECT, - OBS_DATA_ARRAY -}; - -enum obs_data_number_type { - OBS_DATA_NUM_INVALID, - OBS_DATA_NUM_INT, - OBS_DATA_NUM_DOUBLE -}; - -/* ------------------------------------------------------------------------- */ -/* Main usage functions */ - -EXPORT obs_data_t *obs_data_create(); -EXPORT obs_data_t *obs_data_create_from_json(const char *json_string); -EXPORT obs_data_t *obs_data_create_from_json_file(const char *json_file); -EXPORT obs_data_t *obs_data_create_from_json_file_safe(const char *json_file, - const char *backup_ext); -EXPORT void obs_data_addref(obs_data_t *data); -EXPORT void obs_data_release(obs_data_t *data); - -EXPORT const char *obs_data_get_json(obs_data_t *data); -EXPORT const char *obs_data_get_json_pretty(obs_data_t *data); -EXPORT const char *obs_data_get_last_json(obs_data_t *data); -EXPORT bool obs_data_save_json(obs_data_t *data, const char *file); -EXPORT bool obs_data_save_json_safe(obs_data_t *data, const char *file, - const char *temp_ext, - const char *backup_ext); -EXPORT bool obs_data_save_json_pretty_safe(obs_data_t *data, const char *file, - const char *temp_ext, - const char *backup_ext); - -EXPORT void obs_data_apply(obs_data_t *target, obs_data_t *apply_data); - -EXPORT void obs_data_erase(obs_data_t *data, const char *name); -EXPORT void obs_data_clear(obs_data_t *data); - -/* Set functions */ -EXPORT void obs_data_set_string(obs_data_t *data, const char *name, - const char *val); -EXPORT void obs_data_set_int(obs_data_t *data, const char *name, long long val); -EXPORT void obs_data_set_double(obs_data_t *data, const char *name, double val); -EXPORT void obs_data_set_bool(obs_data_t *data, const char *name, bool val); -EXPORT void obs_data_set_obj(obs_data_t *data, const char *name, - obs_data_t *obj); -EXPORT void obs_data_set_array(obs_data_t *data, const char *name, - obs_data_array_t *array); - -/* - * Creates an obs_data_t * filled with all default values. - */ -EXPORT obs_data_t *obs_data_get_defaults(obs_data_t *data); - -/* - * Default value functions. - */ -EXPORT void obs_data_set_default_string(obs_data_t *data, const char *name, - const char *val); -EXPORT void obs_data_set_default_int(obs_data_t *data, const char *name, - long long val); -EXPORT void obs_data_set_default_double(obs_data_t *data, const char *name, - double val); -EXPORT void obs_data_set_default_bool(obs_data_t *data, const char *name, - bool val); -EXPORT void obs_data_set_default_obj(obs_data_t *data, const char *name, - obs_data_t *obj); -EXPORT void obs_data_set_default_array(obs_data_t *data, const char *name, - obs_data_array_t *arr); - -/* - * Application overrides - * Use these to communicate the actual values of settings in case the user - * settings aren't appropriate - */ -EXPORT void obs_data_set_autoselect_string(obs_data_t *data, const char *name, - const char *val); -EXPORT void obs_data_set_autoselect_int(obs_data_t *data, const char *name, - long long val); -EXPORT void obs_data_set_autoselect_double(obs_data_t *data, const char *name, - double val); -EXPORT void obs_data_set_autoselect_bool(obs_data_t *data, const char *name, - bool val); -EXPORT void obs_data_set_autoselect_obj(obs_data_t *data, const char *name, - obs_data_t *obj); -EXPORT void obs_data_set_autoselect_array(obs_data_t *data, const char *name, - obs_data_array_t *arr); - -/* - * Get functions - */ -EXPORT const char *obs_data_get_string(obs_data_t *data, const char *name); -EXPORT long long obs_data_get_int(obs_data_t *data, const char *name); -EXPORT double obs_data_get_double(obs_data_t *data, const char *name); -EXPORT bool obs_data_get_bool(obs_data_t *data, const char *name); -EXPORT obs_data_t *obs_data_get_obj(obs_data_t *data, const char *name); -EXPORT obs_data_array_t *obs_data_get_array(obs_data_t *data, const char *name); - -EXPORT const char *obs_data_get_default_string(obs_data_t *data, - const char *name); -EXPORT long long obs_data_get_default_int(obs_data_t *data, const char *name); -EXPORT double obs_data_get_default_double(obs_data_t *data, const char *name); -EXPORT bool obs_data_get_default_bool(obs_data_t *data, const char *name); -EXPORT obs_data_t *obs_data_get_default_obj(obs_data_t *data, const char *name); -EXPORT obs_data_array_t *obs_data_get_default_array(obs_data_t *data, - const char *name); - -EXPORT const char *obs_data_get_autoselect_string(obs_data_t *data, - const char *name); -EXPORT long long obs_data_get_autoselect_int(obs_data_t *data, - const char *name); -EXPORT double obs_data_get_autoselect_double(obs_data_t *data, - const char *name); -EXPORT bool obs_data_get_autoselect_bool(obs_data_t *data, const char *name); -EXPORT obs_data_t *obs_data_get_autoselect_obj(obs_data_t *data, - const char *name); -EXPORT obs_data_array_t *obs_data_get_autoselect_array(obs_data_t *data, - const char *name); - -/* Array functions */ -EXPORT obs_data_array_t *obs_data_array_create(); -EXPORT void obs_data_array_addref(obs_data_array_t *array); -EXPORT void obs_data_array_release(obs_data_array_t *array); - -EXPORT size_t obs_data_array_count(obs_data_array_t *array); -EXPORT obs_data_t *obs_data_array_item(obs_data_array_t *array, size_t idx); -EXPORT size_t obs_data_array_push_back(obs_data_array_t *array, - obs_data_t *obj); -EXPORT void obs_data_array_insert(obs_data_array_t *array, size_t idx, - obs_data_t *obj); -EXPORT void obs_data_array_push_back_array(obs_data_array_t *array, - obs_data_array_t *array2); -EXPORT void obs_data_array_erase(obs_data_array_t *array, size_t idx); -EXPORT void obs_data_array_enum(obs_data_array_t *array, - void (*cb)(obs_data_t *data, void *param), - void *param); - -/* ------------------------------------------------------------------------- */ -/* Item status inspection */ - -EXPORT bool obs_data_has_user_value(obs_data_t *data, const char *name); -EXPORT bool obs_data_has_default_value(obs_data_t *data, const char *name); -EXPORT bool obs_data_has_autoselect_value(obs_data_t *data, const char *name); - -EXPORT bool obs_data_item_has_user_value(obs_data_item_t *data); -EXPORT bool obs_data_item_has_default_value(obs_data_item_t *data); -EXPORT bool obs_data_item_has_autoselect_value(obs_data_item_t *data); - -/* ------------------------------------------------------------------------- */ -/* Clearing data values */ - -EXPORT void obs_data_unset_user_value(obs_data_t *data, const char *name); -EXPORT void obs_data_unset_default_value(obs_data_t *data, const char *name); -EXPORT void obs_data_unset_autoselect_value(obs_data_t *data, const char *name); - -EXPORT void obs_data_item_unset_user_value(obs_data_item_t *data); -EXPORT void obs_data_item_unset_default_value(obs_data_item_t *data); -EXPORT void obs_data_item_unset_autoselect_value(obs_data_item_t *data); - -/* ------------------------------------------------------------------------- */ -/* Item iteration */ - -EXPORT obs_data_item_t *obs_data_first(obs_data_t *data); -EXPORT obs_data_item_t *obs_data_item_byname(obs_data_t *data, - const char *name); -EXPORT bool obs_data_item_next(obs_data_item_t **item); -EXPORT void obs_data_item_release(obs_data_item_t **item); -EXPORT void obs_data_item_remove(obs_data_item_t **item); - -/* Gets Item type */ -EXPORT enum obs_data_type obs_data_item_gettype(obs_data_item_t *item); -EXPORT enum obs_data_number_type obs_data_item_numtype(obs_data_item_t *item); -EXPORT const char *obs_data_item_get_name(obs_data_item_t *item); - -/* Item set functions */ -EXPORT void obs_data_item_set_string(obs_data_item_t **item, const char *val); -EXPORT void obs_data_item_set_int(obs_data_item_t **item, long long val); -EXPORT void obs_data_item_set_double(obs_data_item_t **item, double val); -EXPORT void obs_data_item_set_bool(obs_data_item_t **item, bool val); -EXPORT void obs_data_item_set_obj(obs_data_item_t **item, obs_data_t *val); -EXPORT void obs_data_item_set_array(obs_data_item_t **item, - obs_data_array_t *val); - -EXPORT void obs_data_item_set_default_string(obs_data_item_t **item, - const char *val); -EXPORT void obs_data_item_set_default_int(obs_data_item_t **item, - long long val); -EXPORT void obs_data_item_set_default_double(obs_data_item_t **item, - double val); -EXPORT void obs_data_item_set_default_bool(obs_data_item_t **item, bool val); -EXPORT void obs_data_item_set_default_obj(obs_data_item_t **item, - obs_data_t *val); -EXPORT void obs_data_item_set_default_array(obs_data_item_t **item, - obs_data_array_t *val); - -EXPORT void obs_data_item_set_autoselect_string(obs_data_item_t **item, - const char *val); -EXPORT void obs_data_item_set_autoselect_int(obs_data_item_t **item, - long long val); -EXPORT void obs_data_item_set_autoselect_double(obs_data_item_t **item, - double val); -EXPORT void obs_data_item_set_autoselect_bool(obs_data_item_t **item, bool val); -EXPORT void obs_data_item_set_autoselect_obj(obs_data_item_t **item, - obs_data_t *val); -EXPORT void obs_data_item_set_autoselect_array(obs_data_item_t **item, - obs_data_array_t *val); - -/* Item get functions */ -EXPORT const char *obs_data_item_get_string(obs_data_item_t *item); -EXPORT long long obs_data_item_get_int(obs_data_item_t *item); -EXPORT double obs_data_item_get_double(obs_data_item_t *item); -EXPORT bool obs_data_item_get_bool(obs_data_item_t *item); -EXPORT obs_data_t *obs_data_item_get_obj(obs_data_item_t *item); -EXPORT obs_data_array_t *obs_data_item_get_array(obs_data_item_t *item); - -EXPORT const char *obs_data_item_get_default_string(obs_data_item_t *item); -EXPORT long long obs_data_item_get_default_int(obs_data_item_t *item); -EXPORT double obs_data_item_get_default_double(obs_data_item_t *item); -EXPORT bool obs_data_item_get_default_bool(obs_data_item_t *item); -EXPORT obs_data_t *obs_data_item_get_default_obj(obs_data_item_t *item); -EXPORT obs_data_array_t *obs_data_item_get_default_array(obs_data_item_t *item); - -EXPORT const char *obs_data_item_get_autoselect_string(obs_data_item_t *item); -EXPORT long long obs_data_item_get_autoselect_int(obs_data_item_t *item); -EXPORT double obs_data_item_get_autoselect_double(obs_data_item_t *item); -EXPORT bool obs_data_item_get_autoselect_bool(obs_data_item_t *item); -EXPORT obs_data_t *obs_data_item_get_autoselect_obj(obs_data_item_t *item); -EXPORT obs_data_array_t * -obs_data_item_get_autoselect_array(obs_data_item_t *item); - -#ifdef __cplusplus -} -#endif diff --git a/tests/stubs/macro-action-macro.cpp b/tests/stubs/macro-action-macro.cpp new file mode 100644 index 00000000..09ba2dec --- /dev/null +++ b/tests/stubs/macro-action-macro.cpp @@ -0,0 +1,123 @@ +#include "macro-action-macro.hpp" + +namespace advss { + +bool MacroActionMacro::_registered = false; +const std::string MacroActionMacro::id = "macro"; + +bool MacroActionMacro::PerformAction() +{ + return false; +} + +void MacroActionMacro::LogAction() const {} + +bool MacroActionMacro::Save(obs_data_t *obj) const +{ + return false; +} + +bool MacroActionMacro::Load(obs_data_t *obj) +{ + return false; +} + +bool MacroActionMacro::PostLoad() +{ + return false; +} + +std::string MacroActionMacro::GetShortDesc() const +{ + return ""; +} + +std::shared_ptr MacroActionMacro::Create(Macro *m) +{ + return std::make_shared(m); +} + +std::shared_ptr MacroActionMacro::Copy() const +{ + return std::make_shared(*this); +} + +void MacroActionMacro::ResolveVariablesToFixedValues() {} + +void MacroActionMacro::RunOptions::Save(obs_data_t *obj) const {} + +void MacroActionMacro::RunOptions::Load(obs_data_t *obj) {} + +void MacroActionMacro::RunActions(Macro *actionMacro) const {} + +void MacroActionMacro::AdjustActionState(Macro *macro) const {} + +MacroActionMacroEdit::MacroActionMacroEdit( + QWidget *parent, std::shared_ptr entryData) + : ResizableWidget(parent), + _actions(new QComboBox(this)), + _macros(new MacroSelection(this)), + _actionSelectionType(new QComboBox(this)), + _label(new VariableLineEdit(this)), + _actionTypes(new FilterComboBox(this)), + _regex(new RegexConfigWidget(this)), + _conditionMacros(new MacroSelection(this)), + _conditionBehaviors(new QComboBox(this)), + _reevaluateConditionState(new QCheckBox(this)), + _actionSections(new QComboBox(this)), + _skipWhenPaused(new QCheckBox(this)), + _setInputs(new QCheckBox(this)), + _inputs(new MacroInputEdit(this)), + _entryLayout(new QHBoxLayout()), + _conditionLayout(new QHBoxLayout()), + _reevaluateConditionStateLayout(new QHBoxLayout()), + _setInputsLayout(new QHBoxLayout()), + _nestedMacro(new MacroEdit(this)), + _entryData(entryData) +{ +} + +MacroActionMacroEdit::~MacroActionMacroEdit() {} + +void MacroActionMacroEdit::UpdateEntryData() {} + +QWidget *MacroActionMacroEdit::Create(QWidget *parent, + std::shared_ptr action) +{ + return new MacroActionMacroEdit( + parent, std::dynamic_pointer_cast(action)); +} + +void MacroActionMacroEdit::MacroChanged(const QString &text) {} + +void MacroActionMacroEdit::ActionChanged(int value) {} + +void MacroActionMacroEdit::ActionSelectionTypeChanged(int value) {} + +void MacroActionMacroEdit::ActionIndexChanged(const IntVariable &value) {} + +void MacroActionMacroEdit::LabelChanged() {} + +void MacroActionMacroEdit::ActionTypeChanged(int value) {} + +void MacroActionMacroEdit::RegexChanged(const RegexConfig &config) {} + +void MacroActionMacroEdit::ConditionMacroChanged(const QString &text) {} + +void MacroActionMacroEdit::ConditionBehaviorChanged(int value) {} + +void MacroActionMacroEdit::ReevaluateConditionStateChanged(int value) {} + +void MacroActionMacroEdit::ActionSectionChanged(int value) {} + +void MacroActionMacroEdit::SkipWhenPausedChanged(int value) {} + +void MacroActionMacroEdit::SetInputsChanged(int value) {} + +void MacroActionMacroEdit::InputsChanged(const StringList &inputs) {} + +void MacroActionMacroEdit::SetWidgetVisibility() {} + +void MacroActionMacroEdit::SetupMacroInput(Macro *macro) const {} + +} // namespace advss diff --git a/tests/stubs/macro-dock-settings.cpp b/tests/stubs/macro-dock-settings.cpp new file mode 100644 index 00000000..3e753864 --- /dev/null +++ b/tests/stubs/macro-dock-settings.cpp @@ -0,0 +1,77 @@ +#include "macro-dock-settings.hpp" + +namespace advss { + +MacroDockSettings::MacroDockSettings(Macro *macro) : _macro(macro) {} +MacroDockSettings::~MacroDockSettings() {} + +void MacroDockSettings::Save(obs_data_t *, bool) const {} +void MacroDockSettings::Load(obs_data_t *) {} +void MacroDockSettings::EnableDock(bool value) +{ + _registerDock = value; +} +void MacroDockSettings::SetIsStandaloneDock(bool value) +{ + _standaloneDock = value; +} +void MacroDockSettings::SetDockWindowName(const std::string &name) +{ + _dockWindow = name; +} +void MacroDockSettings::SetHasRunButton(bool value) +{ + _hasRunButton = value; +} +void MacroDockSettings::SetHasPauseButton(bool value) +{ + _hasPauseButton = value; +} +void MacroDockSettings::SetHasStatusLabel(bool value) +{ + _hasStatusLabel = value; +} +void MacroDockSettings::SetHighlightEnable(bool value) +{ + _highlight = value; +} +void MacroDockSettings::SetRunButtonText(const std::string &text) +{ + _runButtonText = text; +} +void MacroDockSettings::SetPauseButtonText(const std::string &text) +{ + _pauseButtonText = text; +} +void MacroDockSettings::SetUnpauseButtonText(const std::string &text) +{ + _unpauseButtonText = text; +} +void MacroDockSettings::SetConditionsTrueStatusText(const std::string &text) +{ + _conditionsTrueStatusText = text; +} +void MacroDockSettings::SetConditionsFalseStatusText(const std::string &text) +{ + _conditionsFalseStatusText = text; +} + +StringVariable MacroDockSettings::ConditionsTrueStatusText() const +{ + return _conditionsTrueStatusText; +} +StringVariable MacroDockSettings::ConditionsFalseStatusText() const +{ + return _conditionsFalseStatusText; +} + +void MacroDockSettings::HandleMacroNameChange() {} +void MacroDockSettings::ResetDockIfEnabled() {} +void MacroDockSettings::RemoveDock() {} + +std::string MacroDockSettings::GenerateId() +{ + return ""; +} + +} // namespace advss diff --git a/tests/stubs/macro-edit.cpp b/tests/stubs/macro-edit.cpp new file mode 100644 index 00000000..629040b3 --- /dev/null +++ b/tests/stubs/macro-edit.cpp @@ -0,0 +1,134 @@ +#include "macro-edit.hpp" + +namespace advss { + +MacroEdit::MacroEdit(QWidget *parent, QStringList) + : QWidget(parent), + ui(std::make_unique()) +{ +} + +void MacroEdit::SetMacro(const std::shared_ptr &m) +{ + _currentMacro = m; +} +std::shared_ptr MacroEdit::GetMacro() const +{ + return _currentMacro; +} +void MacroEdit::ClearSegmentWidgetCacheFor(Macro *) const {} +void MacroEdit::SetControlsDisabled(bool) const {} +void MacroEdit::HighlightAction(int, QColor) const {} +void MacroEdit::HighlightElseAction(int, QColor) const {} +void MacroEdit::HighlightCondition(int, QColor) const {} +void MacroEdit::ResetConditionHighlights() {} +void MacroEdit::ResetActionHighlights() {} +void MacroEdit::SetActionData(Macro &) const {} +void MacroEdit::SetElseActionData(Macro &) const {} +void MacroEdit::SetConditionData(Macro &) const {} +void MacroEdit::SwapActions(Macro *, int, int) {} +void MacroEdit::SwapElseActions(Macro *, int, int) {} +void MacroEdit::SwapConditions(Macro *, int, int) {} +void MacroEdit::CopyMacroSegment() {} +void MacroEdit::PasteMacroSegment() {} +bool MacroEdit::IsEmpty() const +{ + return true; +} +void MacroEdit::ShowAllMacroSections() {} + +void MacroEdit::on_conditionAdd_clicked() {} +void MacroEdit::on_conditionRemove_clicked() {} +void MacroEdit::on_conditionTop_clicked() {} +void MacroEdit::on_conditionUp_clicked() {} +void MacroEdit::on_conditionDown_clicked() {} +void MacroEdit::on_conditionBottom_clicked() {} +void MacroEdit::on_actionAdd_clicked() {} +void MacroEdit::on_actionRemove_clicked() {} +void MacroEdit::on_actionTop_clicked() {} +void MacroEdit::on_actionUp_clicked() {} +void MacroEdit::on_actionDown_clicked() {} +void MacroEdit::on_actionBottom_clicked() {} +void MacroEdit::on_toggleElseActions_clicked() const {} +void MacroEdit::on_elseActionAdd_clicked() {} +void MacroEdit::on_elseActionRemove_clicked() {} +void MacroEdit::on_elseActionTop_clicked() {} +void MacroEdit::on_elseActionUp_clicked() {} +void MacroEdit::on_elseActionDown_clicked() {} +void MacroEdit::on_elseActionBottom_clicked() {} +void MacroEdit::UpMacroSegmentHotkey() {} +void MacroEdit::DownMacroSegmentHotkey() {} +void MacroEdit::DeleteMacroSegmentHotkey() {} +void MacroEdit::ShowMacroActionsContextMenu(const QPoint &) {} +void MacroEdit::ShowMacroElseActionsContextMenu(const QPoint &) {} +void MacroEdit::ShowMacroConditionsContextMenu(const QPoint &) {} +void MacroEdit::ExpandAllActions() const {} +void MacroEdit::ExpandAllElseActions() const {} +void MacroEdit::ExpandAllConditions() const {} +void MacroEdit::CollapseAllActions() const {} +void MacroEdit::CollapseAllElseActions() const {} +void MacroEdit::CollapseAllConditions() const {} +void MacroEdit::MinimizeActions() const {} +void MacroEdit::MaximizeActions() const {} +void MacroEdit::MinimizeElseActions() const {} +void MacroEdit::MaximizeElseActions() const {} +void MacroEdit::MinimizeConditions() const {} +void MacroEdit::MaximizeConditions() const {} +void MacroEdit::SetElseActionsStateToHidden() const {} +void MacroEdit::SetElseActionsStateToVisible() const {} +void MacroEdit::MacroActionSelectionChanged(int) {} +void MacroEdit::MacroActionReorder(int, int) {} +void MacroEdit::AddMacroAction(Macro *, int, const std::string &, obs_data_t *) +{ +} +void MacroEdit::AddMacroAction(int) {} +void MacroEdit::RemoveMacroAction(int) {} +void MacroEdit::MoveMacroActionUp(int) {} +void MacroEdit::MoveMacroActionDown(int) {} +void MacroEdit::MacroElseActionSelectionChanged(int) {} +void MacroEdit::MacroElseActionReorder(int, int) {} +void MacroEdit::AddMacroElseAction(Macro *, int, const std::string &, + obs_data_t *) +{ +} +void MacroEdit::AddMacroElseAction(int) {} +void MacroEdit::RemoveMacroElseAction(int) {} +void MacroEdit::MoveMacroElseActionUp(int) {} +void MacroEdit::MoveMacroElseActionDown(int) {} +void MacroEdit::MacroConditionSelectionChanged(int) {} +void MacroEdit::MacroConditionReorder(int, int) {} +void MacroEdit::AddMacroCondition(int) {} +void MacroEdit::AddMacroCondition(Macro *, int, const std::string &, + obs_data_t *, Logic::Type) +{ +} +void MacroEdit::RemoveMacroCondition(int) {} +void MacroEdit::MoveMacroConditionUp(int) {} +void MacroEdit::MoveMacroConditionDown(int) {} +void MacroEdit::HighlightControls() const {} + +void MacroEdit::PopulateMacroActions(Macro &, uint32_t) {} +void MacroEdit::PopulateMacroElseActions(Macro &, uint32_t) {} +void MacroEdit::PopulateMacroConditions(Macro &, uint32_t) {} +void MacroEdit::SetupMacroSegmentSelection(MacroSection, int) {} +void MacroEdit::SetupContextMenu(const QPoint &, + const std::function &, + const std::function &, + const std::function &, + const std::function &, + const std::function &, + MacroSegmentList *) +{ +} +void MacroEdit::RunSegmentHighlightChecks() {} +bool MacroEdit::ElseSectionIsVisible() const +{ + return false; +} + +bool MacroEdit::eventFilter(QObject *, QEvent *) +{ + return false; +} + +} // namespace advss diff --git a/tests/mocks/path-helpers.cpp b/tests/stubs/path-helpers.cpp similarity index 100% rename from tests/mocks/path-helpers.cpp rename to tests/stubs/path-helpers.cpp diff --git a/tests/stubs/plugin-state-helpers.cpp b/tests/stubs/plugin-state-helpers.cpp new file mode 100644 index 00000000..eb94fb8b --- /dev/null +++ b/tests/stubs/plugin-state-helpers.cpp @@ -0,0 +1,86 @@ +#include "plugin-state-helpers.hpp" + +namespace advss { + +void SavePluginSettings(obs_data_t *) {} +void LoadPluginSettings(obs_data_t *) {} +void AddSaveStep(std::function) {} +void AddLoadStep(std::function) {} +void AddPostLoadStep(std::function) {} +void AddIntervalResetStep(std::function) {} +void RunSaveSteps(obs_data_t *) {} +void RunLoadSteps(obs_data_t *) {} +void RunAndClearPostLoadSteps() {} +void ClearPostLoadSteps() {} + +void AddPluginInitStep(std::function) {} +void AddPluginPostLoadStep(std::function) {} +void AddPluginCleanupStep(std::function) {} +void RunPluginInitSteps() {} +void RunPluginPostLoadSteps() {} +void RunPluginCleanupSteps() {} + +void StopPlugin() {} +void StartPlugin() {} +bool PluginIsRunning() +{ + return false; +} +int GetIntervalValue() +{ + return 0; +} +void AddStartStep(std::function) {} +void AddStopStep(std::function) {} +void RunStartSteps() {} +void RunStopSteps() {} +void RunIntervalResetSteps() {} + +void SetPluginNoMatchBehavior(NoMatchBehavior) {} +NoMatchBehavior GetPluginNoMatchBehavior() +{ + return NoMatchBehavior::NO_SWITCH; +} +void SetNoMatchScene(const OBSWeakSource &) {} + +std::string ForegroundWindowTitle() +{ + return ""; +} +std::string PreviousForegroundWindowTitle() +{ + return ""; +} +bool SettingsWindowIsOpened() +{ + return false; +} +bool HighlightUIElementsEnabled() +{ + return false; +} + +bool OBSIsShuttingDown() +{ + return false; +} +bool InitialLoadIsComplete() +{ + return false; +} +bool IsFirstInterval() +{ + return false; +} +bool IsFirstIntervalAfterStop() +{ + return false; +} + +void SetMacroHighlightingEnabled(bool) {} +bool IsMacroHighlightingEnabled() +{ + return false; +} + +} // namespace advss diff --git a/tests/mocks/ui-helpers.cpp b/tests/stubs/ui-helpers.cpp similarity index 93% rename from tests/mocks/ui-helpers.cpp rename to tests/stubs/ui-helpers.cpp index f0675696..fa67dcc0 100644 --- a/tests/mocks/ui-helpers.cpp +++ b/tests/stubs/ui-helpers.cpp @@ -47,4 +47,9 @@ QWidget *GetSettingsWindow() return nullptr; } +bool IsCursorInWidgetArea(QWidget *widget) +{ + return false; +} + } // namespace advss diff --git a/tests/test-macro-condition.cpp b/tests/test-macro-condition.cpp new file mode 100644 index 00000000..1bee3c5b --- /dev/null +++ b/tests/test-macro-condition.cpp @@ -0,0 +1,351 @@ +#include "catch.hpp" + +#include + +namespace { + +class StubCondition : public advss::MacroCondition { +public: + StubCondition(bool initialValue = false) + : MacroCondition(nullptr), + _value(initialValue) + { + } + + void SetValue(bool value) { _value = value; } + bool CheckCondition() override { return _value; } + bool Save(obs_data_t *) const override { return true; } + bool Load(obs_data_t *) override { return true; } + std::string GetId() const override { return "stub"; } + +private: + bool _value; +}; + +} // namespace + +// --------------------------------------------------------------------------- +// HasChanged +// --------------------------------------------------------------------------- + +TEST_CASE("HasChanged is false on first evaluation", "[macro-condition]") +{ + StubCondition cond; + cond.EvaluateCondition(); + REQUIRE_FALSE(cond.HasChanged()); +} + +TEST_CASE("HasChanged is false when value stays false", "[macro-condition]") +{ + StubCondition cond(false); + cond.EvaluateCondition(); + cond.EvaluateCondition(); + REQUIRE_FALSE(cond.HasChanged()); +} + +TEST_CASE("HasChanged is false when value stays true", "[macro-condition]") +{ + StubCondition cond(true); + cond.EvaluateCondition(); + cond.EvaluateCondition(); + REQUIRE_FALSE(cond.HasChanged()); +} + +TEST_CASE("HasChanged is true on rising edge (false to true)", + "[macro-condition]") +{ + StubCondition cond(false); + cond.EvaluateCondition(); + cond.SetValue(true); + cond.EvaluateCondition(); + REQUIRE(cond.HasChanged()); +} + +TEST_CASE("HasChanged is true on falling edge (true to false)", + "[macro-condition]") +{ + StubCondition cond(true); + cond.EvaluateCondition(); + cond.SetValue(false); + cond.EvaluateCondition(); + REQUIRE(cond.HasChanged()); +} + +TEST_CASE("HasChanged resets to false after stable evaluation", + "[macro-condition]") +{ + StubCondition cond(false); + cond.EvaluateCondition(); + + cond.SetValue(true); + cond.EvaluateCondition(); + REQUIRE(cond.HasChanged()); + + cond.EvaluateCondition(); // value unchanged + REQUIRE_FALSE(cond.HasChanged()); +} + +TEST_CASE("EvaluateCondition returns the current condition value", + "[macro-condition]") +{ + StubCondition cond(false); + REQUIRE_FALSE(cond.EvaluateCondition()); + + cond.SetValue(true); + REQUIRE(cond.EvaluateCondition()); + + cond.SetValue(false); + REQUIRE_FALSE(cond.EvaluateCondition()); +} + +TEST_CASE("Multiple alternating changes are each detected", "[macro-condition]") +{ + StubCondition cond(false); + cond.EvaluateCondition(); // baseline + + cond.SetValue(true); + cond.EvaluateCondition(); + REQUIRE(cond.HasChanged()); // false -> true + + cond.SetValue(false); + cond.EvaluateCondition(); + REQUIRE(cond.HasChanged()); // true -> false + + cond.SetValue(true); + cond.EvaluateCondition(); + REQUIRE(cond.HasChanged()); // false -> true again +} + +// --------------------------------------------------------------------------- +// IsRisingEdge +// --------------------------------------------------------------------------- + +TEST_CASE("IsRisingEdge is false on first evaluation", "[macro-condition]") +{ + StubCondition cond(true); + cond.EvaluateCondition(); + REQUIRE_FALSE(cond.IsRisingEdge()); +} + +TEST_CASE("IsRisingEdge is true on false-to-true transition", + "[macro-condition]") +{ + StubCondition cond(false); + cond.EvaluateCondition(); + cond.SetValue(true); + cond.EvaluateCondition(); + REQUIRE(cond.IsRisingEdge()); +} + +TEST_CASE("IsRisingEdge is false on true-to-false transition", + "[macro-condition]") +{ + StubCondition cond(true); + cond.EvaluateCondition(); + cond.SetValue(false); + cond.EvaluateCondition(); + REQUIRE_FALSE(cond.IsRisingEdge()); +} + +TEST_CASE("IsRisingEdge is false when value stays true", "[macro-condition]") +{ + StubCondition cond(true); + cond.EvaluateCondition(); + cond.EvaluateCondition(); + REQUIRE_FALSE(cond.IsRisingEdge()); +} + +TEST_CASE("IsRisingEdge is false when value stays false", "[macro-condition]") +{ + StubCondition cond(false); + cond.EvaluateCondition(); + cond.EvaluateCondition(); + REQUIRE_FALSE(cond.IsRisingEdge()); +} + +TEST_CASE("IsRisingEdge resets to false after stable evaluation", + "[macro-condition]") +{ + StubCondition cond(false); + cond.EvaluateCondition(); + + cond.SetValue(true); + cond.EvaluateCondition(); + REQUIRE(cond.IsRisingEdge()); + + cond.EvaluateCondition(); // value unchanged + REQUIRE_FALSE(cond.IsRisingEdge()); +} + +TEST_CASE("IsRisingEdge fires again after falling then rising", + "[macro-condition]") +{ + StubCondition cond(false); + cond.EvaluateCondition(); + + cond.SetValue(true); + cond.EvaluateCondition(); + REQUIRE(cond.IsRisingEdge()); + + cond.SetValue(false); + cond.EvaluateCondition(); + REQUIRE_FALSE(cond.IsRisingEdge()); + + cond.SetValue(true); + cond.EvaluateCondition(); + REQUIRE(cond.IsRisingEdge()); // second rising edge is detected +} + +// --------------------------------------------------------------------------- +// CheckDurationModifier - NONE (default, no time constraint) +// --------------------------------------------------------------------------- + +TEST_CASE("DurationModifier NONE passes through condition value", + "[duration-modifier]") +{ + StubCondition cond(true); + // Default modifier type is NONE + REQUIRE(cond.CheckDurationModifier(true)); + REQUIRE_FALSE(cond.CheckDurationModifier(false)); +} + +// --------------------------------------------------------------------------- +// CheckDurationModifier - MORE (true only after duration has elapsed) +// --------------------------------------------------------------------------- + +TEST_CASE("DurationModifier MORE returns false before duration elapses", + "[duration-modifier]") +{ + StubCondition cond(true); + cond.SetDurationModifier(advss::DurationModifier::Type::MORE); + cond.SetDuration(advss::Duration(10.0)); // 10 seconds — won't elapse + + REQUIRE_FALSE(cond.CheckDurationModifier(true)); +} + +TEST_CASE("DurationModifier MORE returns true after duration elapses", + "[duration-modifier]") +{ + StubCondition cond(true); + cond.SetDurationModifier(advss::DurationModifier::Type::MORE); + cond.SetDuration( + advss::Duration(0.0)); // 0 seconds — elapses immediately + + // First call starts the timer; with 0s duration it should already pass + REQUIRE(cond.CheckDurationModifier(true)); +} + +TEST_CASE("DurationModifier MORE resets when condition becomes false", + "[duration-modifier]") +{ + StubCondition cond; + cond.SetDurationModifier(advss::DurationModifier::Type::MORE); + cond.SetDuration(advss::Duration(0.0)); + + cond.CheckDurationModifier(true); // start timer + cond.CheckDurationModifier(false); // reset + // After reset a fresh call with true must re-start the timer and still pass + // (duration is 0 so it should pass immediately again) + REQUIRE(cond.CheckDurationModifier(true)); +} + +TEST_CASE("DurationModifier MORE returns false when condition is false", + "[duration-modifier]") +{ + StubCondition cond; + cond.SetDurationModifier(advss::DurationModifier::Type::MORE); + cond.SetDuration(advss::Duration(0.0)); + + REQUIRE_FALSE(cond.CheckDurationModifier(false)); +} + +// --------------------------------------------------------------------------- +// CheckDurationModifier - LESS (true only before duration elapses) +// --------------------------------------------------------------------------- + +TEST_CASE("DurationModifier LESS returns true before duration elapses", + "[duration-modifier]") +{ + StubCondition cond(true); + cond.SetDurationModifier(advss::DurationModifier::Type::LESS); + cond.SetDuration(advss::Duration(10.0)); // won't elapse during test + + REQUIRE(cond.CheckDurationModifier(true)); +} + +TEST_CASE("DurationModifier LESS returns false after duration elapses", + "[duration-modifier]") +{ + StubCondition cond(true); + cond.SetDurationModifier(advss::DurationModifier::Type::LESS); + cond.SetDuration(advss::Duration(0.0)); // elapses immediately + + // First call starts timer; with 0s it is already past + REQUIRE_FALSE(cond.CheckDurationModifier(true)); +} + +TEST_CASE("DurationModifier LESS returns false when condition is false", + "[duration-modifier]") +{ + StubCondition cond; + cond.SetDurationModifier(advss::DurationModifier::Type::LESS); + cond.SetDuration(advss::Duration(10.0)); + + REQUIRE_FALSE(cond.CheckDurationModifier(false)); +} + +// --------------------------------------------------------------------------- +// CheckDurationModifier - WITHIN (true while within window after going false) +// --------------------------------------------------------------------------- + +TEST_CASE("DurationModifier WITHIN returns true while condition is true", + "[duration-modifier]") +{ + StubCondition cond(true); + cond.SetDurationModifier(advss::DurationModifier::Type::WITHIN); + cond.SetDuration(advss::Duration(10.0)); + + REQUIRE(cond.CheckDurationModifier(true)); +} + +TEST_CASE( + "DurationModifier WITHIN returns true immediately after condition goes false", + "[duration-modifier]") +{ + StubCondition cond; + cond.SetDurationModifier(advss::DurationModifier::Type::WITHIN); + cond.SetDuration(advss::Duration(10.0)); + + cond.CheckDurationModifier( + true); // condition was true — sets time remaining + REQUIRE(cond.CheckDurationModifier(false)); // still within window +} + +TEST_CASE("DurationModifier WITHIN returns false before condition was ever true", + "[duration-modifier]") +{ + StubCondition cond; + cond.SetDurationModifier(advss::DurationModifier::Type::WITHIN); + cond.SetDuration(advss::Duration(10.0)); + + // Timer was never started (condition never went true->false) + REQUIRE_FALSE(cond.CheckDurationModifier(false)); +} + +// --------------------------------------------------------------------------- +// ResetDuration +// --------------------------------------------------------------------------- + +TEST_CASE("ResetDuration causes MORE modifier to restart its timer", + "[duration-modifier]") +{ + StubCondition cond(true); + cond.SetDurationModifier(advss::DurationModifier::Type::MORE); + cond.SetDuration(advss::Duration(10.0)); + + cond.CheckDurationModifier(true); // starts timer + cond.ResetDuration(); // reset + + // After reset the timer restarts — 10s duration won't have elapsed + REQUIRE_FALSE(cond.CheckDurationModifier(true)); +} diff --git a/tests/test-macro.cpp b/tests/test-macro.cpp new file mode 100644 index 00000000..7bdecf7d --- /dev/null +++ b/tests/test-macro.cpp @@ -0,0 +1,416 @@ +#include "catch.hpp" + +#include + +#include + +namespace { + +// --------------------------------------------------------------------------- +// Stubs +// --------------------------------------------------------------------------- + +class StubCondition : public advss::MacroCondition { +public: + StubCondition(advss::Macro *m, bool initialValue = false) + : MacroCondition(m), + _value(initialValue) + { + } + + void SetValue(bool value) { _value = value; } + bool CheckCondition() override { return _value; } + bool Save(obs_data_t *) const override { return true; } + bool Load(obs_data_t *) override { return true; } + std::string GetId() const override { return "stub"; } + +private: + bool _value; +}; + +class StubAction : public advss::MacroAction { +public: + StubAction(advss::Macro *m) : MacroAction(m) {} + + bool PerformAction() override + { + _performCount++; + return true; + } + + std::shared_ptr Copy() const override + { + return std::make_shared(*this); + } + + bool Save(obs_data_t *) const override { return true; } + bool Load(obs_data_t *) override { return true; } + std::string GetId() const override { return "stub"; } + + int PerformCount() const { return _performCount; } + +private: + int _performCount = 0; +}; + +// Helpers to wire up conditions and actions onto a macro +std::shared_ptr AddCondition(advss::Macro &m, + bool initialValue = false) +{ + auto cond = std::make_shared(&m, initialValue); + cond->SetLogicType(advss::Logic::Type::ROOT_NONE); + m.Conditions().push_back(cond); + return cond; +} + +std::shared_ptr AddAction(advss::Macro &m) +{ + auto action = std::make_shared(&m); + m.Actions().push_back(action); + return action; +} + +std::shared_ptr AddElseAction(advss::Macro &m) +{ + auto action = std::make_shared(&m); + m.ElseActions().push_back(action); + return action; +} + +} // namespace + +// --------------------------------------------------------------------------- +// CheckConditions - basic matching +// --------------------------------------------------------------------------- + +TEST_CASE("CheckConditions returns false with no conditions", "[macro]") +{ + advss::Macro m("test"); + REQUIRE_FALSE(m.CheckConditions()); +} + +TEST_CASE("CheckConditions returns true when condition is true", "[macro]") +{ + advss::Macro m("test"); + AddCondition(m, true); + REQUIRE(m.CheckConditions()); +} + +TEST_CASE("CheckConditions returns false when condition is false", "[macro]") +{ + advss::Macro m("test"); + AddCondition(m, false); + REQUIRE_FALSE(m.CheckConditions()); +} + +TEST_CASE("ConditionsMatched reflects last CheckConditions result", "[macro]") +{ + advss::Macro m("test"); + auto cond = AddCondition(m, false); + + m.CheckConditions(); + REQUIRE_FALSE(m.ConditionsMatched()); + + cond->SetValue(true); + m.CheckConditions(); + REQUIRE(m.ConditionsMatched()); +} + +TEST_CASE("CheckConditions returns false for group macros", "[macro]") +{ + std::vector> children; + auto group = advss::Macro::CreateGroup("group", children); + REQUIRE_FALSE(group->CheckConditions()); +} + +// --------------------------------------------------------------------------- +// Pause +// --------------------------------------------------------------------------- + +TEST_CASE("CheckConditions respects pause", "[macro]") +{ + advss::Macro m("test"); + auto cond = AddCondition(m, true); + + m.SetPaused(true); + // When paused, conditions are not evaluated — _matched stays false + REQUIRE_FALSE(m.CheckConditions()); +} + +TEST_CASE("CheckConditions runs when ignorePause is true while paused", + "[macro]") +{ + advss::Macro m("test"); + AddCondition(m, true); + + m.SetPaused(true); + REQUIRE(m.CheckConditions(/*ignorePause=*/true)); +} + +// --------------------------------------------------------------------------- +// ShouldRunActions - ActionTriggerMode::MACRO_RESULT_CHANGED (default) +// --------------------------------------------------------------------------- + +TEST_CASE("ShouldRunActions is false before first CheckConditions", "[macro]") +{ + advss::Macro m("test"); + AddCondition(m, true); + AddAction(m); + // _actionModeMatch starts false, _matched starts false + REQUIRE_FALSE(m.ShouldRunActions()); +} + +TEST_CASE("ShouldRunActions MACRO_RESULT_CHANGED: true on first match", + "[macro]") +{ + advss::Macro m("test"); + AddCondition(m, true); + AddAction(m); + + // Default mode is MACRO_RESULT_CHANGED. + // _lastMatched starts false, first check sets _matched=true -> changed + m.SetActionTriggerMode( + advss::Macro::ActionTriggerMode::MACRO_RESULT_CHANGED); + m.CheckConditions(); + REQUIRE(m.ShouldRunActions()); +} + +TEST_CASE("ShouldRunActions MACRO_RESULT_CHANGED: false when result unchanged", + "[macro]") +{ + advss::Macro m("test"); + AddCondition(m, true); + AddAction(m); + + m.SetActionTriggerMode( + advss::Macro::ActionTriggerMode::MACRO_RESULT_CHANGED); + m.CheckConditions(); // false -> true: changed + m.CheckConditions(); // true -> true: unchanged + REQUIRE_FALSE(m.ShouldRunActions()); +} + +TEST_CASE( + "ShouldRunActions MACRO_RESULT_CHANGED: true again when result flips back", + "[macro]") +{ + advss::Macro m("test"); + auto cond = AddCondition(m, true); + AddAction(m); + m.SetActionTriggerMode( + advss::Macro::ActionTriggerMode::MACRO_RESULT_CHANGED); + m.CheckConditions(); // false -> true + REQUIRE(m.ShouldRunActions()); + m.CheckConditions(); // true -> true + REQUIRE_FALSE(m.ShouldRunActions()); + cond->SetValue(false); + m.CheckConditions(); // true -> false: changed + cond->SetValue(true); + m.CheckConditions(); // true -> false: changed + REQUIRE(m.ShouldRunActions()); +} + +// --------------------------------------------------------------------------- +// ShouldRunActions - ActionTriggerMode::ALWAYS +// --------------------------------------------------------------------------- + +TEST_CASE("ShouldRunActions ALWAYS: true every time conditions match", + "[macro]") +{ + advss::Macro m("test"); + AddCondition(m, true); + AddAction(m); + + m.SetActionTriggerMode(advss::Macro::ActionTriggerMode::ALWAYS); + m.CheckConditions(); + REQUIRE(m.ShouldRunActions()); + + m.CheckConditions(); + REQUIRE(m.ShouldRunActions()); +} + +TEST_CASE("ShouldRunActions ALWAYS: false when conditions do not match", + "[macro]") +{ + advss::Macro m("test"); + AddCondition(m, false); + // No else actions, so nothing to run + m.SetActionTriggerMode(advss::Macro::ActionTriggerMode::ALWAYS); + m.CheckConditions(); + REQUIRE_FALSE(m.ShouldRunActions()); +} + +// --------------------------------------------------------------------------- +// ShouldRunActions - ActionTriggerMode::ANY_CONDITION_CHANGED +// --------------------------------------------------------------------------- + +TEST_CASE("ShouldRunActions ANY_CONDITION_CHANGED: true when condition changes", + "[macro]") +{ + advss::Macro m("test"); + auto cond = AddCondition(m, false); + AddAction(m); + + m.SetActionTriggerMode( + advss::Macro::ActionTriggerMode::ANY_CONDITION_CHANGED); + m.CheckConditions(); // baseline — no change yet + + cond->SetValue(true); + m.CheckConditions(); // changed: false -> true + REQUIRE(m.ShouldRunActions()); +} + +TEST_CASE("ShouldRunActions ANY_CONDITION_CHANGED: false when condition stable", + "[macro]") +{ + advss::Macro m("test"); + AddCondition(m, true); + AddAction(m); + + m.SetActionTriggerMode( + advss::Macro::ActionTriggerMode::ANY_CONDITION_CHANGED); + m.CheckConditions(); // baseline + m.CheckConditions(); // stable + REQUIRE_FALSE(m.ShouldRunActions()); +} + +// --------------------------------------------------------------------------- +// ShouldRunActions - ActionTriggerMode::ANY_CONDITION_TRIGGERED +// --------------------------------------------------------------------------- + +TEST_CASE("ShouldRunActions ANY_CONDITION_TRIGGERED: true on rising edge", + "[macro]") +{ + advss::Macro m("test"); + auto cond = AddCondition(m, false); + AddAction(m); + + m.SetActionTriggerMode( + advss::Macro::ActionTriggerMode::ANY_CONDITION_TRIGGERED); + m.CheckConditions(); // baseline + + cond->SetValue(true); + m.CheckConditions(); // rising edge + REQUIRE(m.ShouldRunActions()); +} + +TEST_CASE("ShouldRunActions ANY_CONDITION_TRIGGERED: false on falling edge", + "[macro]") +{ + advss::Macro m("test"); + auto cond = AddCondition(m, true); + AddElseAction(m); // need else actions so ShouldRunActions can be true + + m.SetActionTriggerMode( + advss::Macro::ActionTriggerMode::ANY_CONDITION_TRIGGERED); + m.CheckConditions(); // baseline (first eval, no rising edge) + + cond->SetValue(false); + m.CheckConditions(); // falling edge — not a rising edge + REQUIRE_FALSE(m.ShouldRunActions()); +} + +TEST_CASE("ShouldRunActions ANY_CONDITION_TRIGGERED: false when stable true", + "[macro]") +{ + advss::Macro m("test"); + AddCondition(m, true); + AddAction(m); + + m.SetActionTriggerMode( + advss::Macro::ActionTriggerMode::ANY_CONDITION_TRIGGERED); + m.CheckConditions(); // baseline + m.CheckConditions(); // stable true — no rising edge + REQUIRE_FALSE(m.ShouldRunActions()); +} + +// --------------------------------------------------------------------------- +// RunCount +// --------------------------------------------------------------------------- + +TEST_CASE("RunCount increments after PerformActions", "[macro]") +{ + advss::Macro m("test"); + AddCondition(m, true); + AddAction(m); + + m.SetActionTriggerMode(advss::Macro::ActionTriggerMode::ALWAYS); + m.CheckConditions(); + REQUIRE(m.RunCount() == 0); + + m.PerformActions(true); + REQUIRE(m.RunCount() == 1); + + m.PerformActions(true); + REQUIRE(m.RunCount() == 2); +} + +TEST_CASE("ResetRunCount resets to zero", "[macro]") +{ + advss::Macro m("test"); + AddAction(m); + + m.PerformActions(true); + m.PerformActions(true); + REQUIRE(m.RunCount() == 2); + + m.ResetRunCount(); + REQUIRE(m.RunCount() == 0); +} + +// --------------------------------------------------------------------------- +// Pause state +// --------------------------------------------------------------------------- + +TEST_CASE("Paused is false by default", "[macro]") +{ + advss::Macro m("test"); + REQUIRE_FALSE(m.Paused()); +} + +TEST_CASE("SetPaused toggles pause state", "[macro]") +{ + advss::Macro m("test"); + m.SetPaused(true); + REQUIRE(m.Paused()); + m.SetPaused(false); + REQUIRE_FALSE(m.Paused()); +} + +TEST_CASE("Paused macros don't run actions", "[macro]") +{ + advss::Macro m("test"); + m.SetPaused(true); + REQUIRE(m.Paused()); + auto action = AddAction(m); + m.PerformActions(true); + REQUIRE(action->PerformCount() == 0); +} + +TEST_CASE("ShouldRunActions is false while paused", "[macro]") +{ + advss::Macro m("test"); + AddCondition(m, true); + AddAction(m); + + m.SetActionTriggerMode(advss::Macro::ActionTriggerMode::ALWAYS); + m.CheckConditions(/*ignorePause=*/true); + m.SetPaused(true); + REQUIRE_FALSE(m.ShouldRunActions()); +} + +// --------------------------------------------------------------------------- +// ActionTriggerMode getter/setter +// --------------------------------------------------------------------------- + +TEST_CASE("GetActionTriggerMode returns the set mode", "[macro]") +{ + advss::Macro m("test"); + m.SetActionTriggerMode(advss::Macro::ActionTriggerMode::ALWAYS); + REQUIRE(m.GetActionTriggerMode() == + advss::Macro::ActionTriggerMode::ALWAYS); + + m.SetActionTriggerMode( + advss::Macro::ActionTriggerMode::ANY_CONDITION_TRIGGERED); + REQUIRE(m.GetActionTriggerMode() == + advss::Macro::ActionTriggerMode::ANY_CONDITION_TRIGGERED); +}