Add option for short circuit evaluation of conditions

This commit is contained in:
WarmUpTill 2024-08-30 21:21:21 +02:00 committed by WarmUpTill
parent 0906c6bb3f
commit c7c48d03e9
9 changed files with 168 additions and 46 deletions

View File

@ -194,7 +194,10 @@ AdvSceneSwitcher.macroTab.highlightExecutedMacros="Highlight recently executed m
AdvSceneSwitcher.macroTab.highlightTrueConditions="Highlight conditions of currently selected macro that evaluated to true recently" AdvSceneSwitcher.macroTab.highlightTrueConditions="Highlight conditions of currently selected macro that evaluated to true recently"
AdvSceneSwitcher.macroTab.highlightPerformedActions="Highlight recently performed actions of currently selected macro" AdvSceneSwitcher.macroTab.highlightPerformedActions="Highlight recently performed actions of currently selected macro"
AdvSceneSwitcher.macroTab.newMacroRegisterHotkey="Register hotkeys to control the pause state of new macros" AdvSceneSwitcher.macroTab.newMacroRegisterHotkey="Register hotkeys to control the pause state of new macros"
AdvSceneSwitcher.macroTab.newMacroUseShortCircuitEvaluation="Enable short circuit evaluation of macro conditions for new macros"
AdvSceneSwitcher.macroTab.currentDisableHotkeys="Register hotkeys to control the pause state of selected macro" AdvSceneSwitcher.macroTab.currentDisableHotkeys="Register hotkeys to control the pause state of selected macro"
AdvSceneSwitcher.macroTab.currentUseShortCircuitEvaluation="Enable short circuit evaluation of macro conditions for currently selected macro"
AdvSceneSwitcher.macroTab.shortCircuit.tooltip="Enabling short circuit evaluation might improve the performance, as some condition checks are skipped, if the overall macro cannot be evaluated to \"true\" anymore.\nHowever, please note that condition checks, which are skipped over, will also not update their duration modifier checks."
AdvSceneSwitcher.macroTab.currentSkipExecutionOnStartup="Skip execution of actions of current macro on startup" AdvSceneSwitcher.macroTab.currentSkipExecutionOnStartup="Skip execution of actions of current macro on startup"
AdvSceneSwitcher.macroTab.currentStopActionsIfNotDone="Stop and rerun actions of the currently selected macro, if the actions are still running, when a new execution is triggered" AdvSceneSwitcher.macroTab.currentStopActionsIfNotDone="Stop and rerun actions of the currently selected macro, if the actions are still running, when a new execution is triggered"
AdvSceneSwitcher.macroTab.currentRegisterDock="Register dock widget to control the pause state of selected macro or run it manually" AdvSceneSwitcher.macroTab.currentRegisterDock="Register dock widget to control the pause state of selected macro or run it manually"

View File

@ -20,6 +20,8 @@ void GlobalMacroSettings::Save(obs_data_t *obj) const
obs_data_set_bool(data, "highlightActions", _highlightActions); obs_data_set_bool(data, "highlightActions", _highlightActions);
obs_data_set_bool(data, "newMacroRegisterHotkey", obs_data_set_bool(data, "newMacroRegisterHotkey",
_newMacroRegisterHotkeys); _newMacroRegisterHotkeys);
obs_data_set_bool(data, "newMacroUseShortCircuitEvaluation",
_newMacroUseShortCircuitEvaluation);
obs_data_set_obj(obj, "macroSettings", data); obs_data_set_obj(obj, "macroSettings", data);
obs_data_release(data); obs_data_release(data);
} }
@ -38,6 +40,8 @@ void GlobalMacroSettings::Load(obs_data_t *obj)
_highlightActions = obs_data_get_bool(data, "highlightActions"); _highlightActions = obs_data_get_bool(data, "highlightActions");
_newMacroRegisterHotkeys = _newMacroRegisterHotkeys =
obs_data_get_bool(data, "newMacroRegisterHotkey"); obs_data_get_bool(data, "newMacroRegisterHotkey");
_newMacroUseShortCircuitEvaluation =
obs_data_get_bool(data, "newMacroUseShortCircuitEvaluation");
obs_data_release(data); obs_data_release(data);
} }
@ -45,16 +49,20 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
const GlobalMacroSettings &settings, const GlobalMacroSettings &settings,
Macro *macro) Macro *macro)
: QDialog(parent), : QDialog(parent),
_executed(new QCheckBox(obs_module_text( _highlightExecutedMacros(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.macroTab.highlightExecutedMacros"))), "AdvSceneSwitcher.macroTab.highlightExecutedMacros"))),
_conditions(new QCheckBox(obs_module_text( _highlightConditions(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.macroTab.highlightTrueConditions"))), "AdvSceneSwitcher.macroTab.highlightTrueConditions"))),
_actions(new QCheckBox(obs_module_text( _highlightActions(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.macroTab.highlightPerformedActions"))), "AdvSceneSwitcher.macroTab.highlightPerformedActions"))),
_newMacroRegisterHotkeys(new QCheckBox(obs_module_text( _newMacroRegisterHotkeys(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.macroTab.newMacroRegisterHotkey"))), "AdvSceneSwitcher.macroTab.newMacroRegisterHotkey"))),
_newMacroUseShortCircuitEvaluation(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.macroTab.newMacroUseShortCircuitEvaluation"))),
_currentMacroRegisterHotkeys(new QCheckBox(obs_module_text( _currentMacroRegisterHotkeys(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.macroTab.currentDisableHotkeys"))), "AdvSceneSwitcher.macroTab.currentDisableHotkeys"))),
_currentUseShortCircuitEvaluation(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.macroTab.currentUseShortCircuitEvaluation"))),
_currentSkipOnStartup(new QCheckBox(obs_module_text( _currentSkipOnStartup(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.macroTab.currentSkipExecutionOnStartup"))), "AdvSceneSwitcher.macroTab.currentSkipExecutionOnStartup"))),
_currentStopActionsIfNotDone(new QCheckBox(obs_module_text( _currentStopActionsIfNotDone(new QCheckBox(obs_module_text(
@ -83,12 +91,17 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
setWindowModality(Qt::WindowModality::WindowModal); setWindowModality(Qt::WindowModality::WindowModal);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
_newMacroUseShortCircuitEvaluation->setToolTip(obs_module_text(
"AdvSceneSwitcher.macroTab.shortCircuit.tooltip"));
_currentUseShortCircuitEvaluation->setToolTip(obs_module_text(
"AdvSceneSwitcher.macroTab.shortCircuit.tooltip"));
auto highlightOptions = new QGroupBox( auto highlightOptions = new QGroupBox(
obs_module_text("AdvSceneSwitcher.macroTab.highlightSettings")); obs_module_text("AdvSceneSwitcher.macroTab.highlightSettings"));
auto highlightLayout = new QVBoxLayout; auto highlightLayout = new QVBoxLayout;
highlightLayout->addWidget(_executed); highlightLayout->addWidget(_highlightExecutedMacros);
highlightLayout->addWidget(_conditions); highlightLayout->addWidget(_highlightConditions);
highlightLayout->addWidget(_actions); highlightLayout->addWidget(_highlightActions);
highlightOptions->setLayout(highlightLayout); highlightOptions->setLayout(highlightLayout);
auto hotkeyOptions = new QGroupBox( auto hotkeyOptions = new QGroupBox(
@ -103,6 +116,8 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
auto generalLayout = new QVBoxLayout; auto generalLayout = new QVBoxLayout;
generalLayout->addWidget(_currentSkipOnStartup); generalLayout->addWidget(_currentSkipOnStartup);
generalLayout->addWidget(_currentStopActionsIfNotDone); generalLayout->addWidget(_currentStopActionsIfNotDone);
generalLayout->addWidget(_currentUseShortCircuitEvaluation);
generalLayout->addWidget(_newMacroUseShortCircuitEvaluation);
generalOptions->setLayout(generalLayout); generalOptions->setLayout(generalLayout);
auto inputOptions = new QGroupBox( auto inputOptions = new QGroupBox(
@ -198,10 +213,12 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
dialogLayout->addWidget(buttonbox); dialogLayout->addWidget(buttonbox);
setLayout(dialogLayout); setLayout(dialogLayout);
_executed->setChecked(settings._highlightExecuted); _highlightExecutedMacros->setChecked(settings._highlightExecuted);
_conditions->setChecked(settings._highlightConditions); _highlightConditions->setChecked(settings._highlightConditions);
_actions->setChecked(settings._highlightActions); _highlightActions->setChecked(settings._highlightActions);
_newMacroRegisterHotkeys->setChecked(settings._newMacroRegisterHotkeys); _newMacroRegisterHotkeys->setChecked(settings._newMacroRegisterHotkeys);
_newMacroUseShortCircuitEvaluation->setChecked(
settings._newMacroUseShortCircuitEvaluation);
if (!macro || macro->IsGroup()) { if (!macro || macro->IsGroup()) {
hotkeyOptions->hide(); hotkeyOptions->hide();
@ -212,6 +229,8 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
} }
_currentMacroRegisterHotkeys->setChecked(macro->PauseHotkeysEnabled()); _currentMacroRegisterHotkeys->setChecked(macro->PauseHotkeysEnabled());
_currentUseShortCircuitEvaluation->setChecked(
macro->ShortCircuitEvaluationEnabled());
_currentSkipOnStartup->setChecked(macro->SkipExecOnStart()); _currentSkipOnStartup->setChecked(macro->SkipExecOnStart());
_currentStopActionsIfNotDone->setChecked(macro->StopActionsIfNotDone()); _currentStopActionsIfNotDone->setChecked(macro->StopActionsIfNotDone());
_currentInputs->SetInputs(macro->GetInputVariables()); _currentInputs->SetInputs(macro->GetInputVariables());
@ -322,17 +341,23 @@ bool MacroSettingsDialog::AskForSettings(QWidget *parent,
if (dialog.exec() != DialogCode::Accepted) { if (dialog.exec() != DialogCode::Accepted) {
return false; return false;
} }
userInput._highlightExecuted = dialog._executed->isChecked(); userInput._highlightExecuted =
userInput._highlightConditions = dialog._conditions->isChecked(); dialog._highlightExecutedMacros->isChecked();
userInput._highlightActions = dialog._actions->isChecked(); userInput._highlightConditions =
dialog._highlightConditions->isChecked();
userInput._highlightActions = dialog._highlightActions->isChecked();
userInput._newMacroRegisterHotkeys = userInput._newMacroRegisterHotkeys =
dialog._newMacroRegisterHotkeys->isChecked(); dialog._newMacroRegisterHotkeys->isChecked();
userInput._newMacroUseShortCircuitEvaluation =
dialog._newMacroUseShortCircuitEvaluation->isChecked();
if (!macro) { if (!macro) {
return true; return true;
} }
macro->EnablePauseHotkeys( macro->EnablePauseHotkeys(
dialog._currentMacroRegisterHotkeys->isChecked()); dialog._currentMacroRegisterHotkeys->isChecked());
macro->SetShortCircuitEvaluation(
dialog._currentUseShortCircuitEvaluation->isChecked());
macro->SetSkipExecOnStart(dialog._currentSkipOnStartup->isChecked()); macro->SetSkipExecOnStart(dialog._currentSkipOnStartup->isChecked());
macro->SetStopActionsIfNotDone( macro->SetStopActionsIfNotDone(
dialog._currentStopActionsIfNotDone->isChecked()); dialog._currentStopActionsIfNotDone->isChecked());

View File

@ -23,6 +23,7 @@ public:
bool _highlightConditions = false; bool _highlightConditions = false;
bool _highlightActions = false; bool _highlightActions = false;
bool _newMacroRegisterHotkeys = true; bool _newMacroRegisterHotkeys = true;
bool _newMacroUseShortCircuitEvaluation = false;
}; };
// Dialog for configuring global and individual macro specific settings // Dialog for configuring global and individual macro specific settings
@ -44,12 +45,15 @@ private slots:
private: private:
void Resize(); void Resize();
QCheckBox *_executed; // Global macro settings
QCheckBox *_conditions; QCheckBox *_highlightExecutedMacros;
QCheckBox *_actions; QCheckBox *_highlightConditions;
QCheckBox *_highlightActions;
QCheckBox *_newMacroRegisterHotkeys; QCheckBox *_newMacroRegisterHotkeys;
QCheckBox *_newMacroUseShortCircuitEvaluation;
// Current macro specific settings // Current macro specific settings
QCheckBox *_currentMacroRegisterHotkeys; QCheckBox *_currentMacroRegisterHotkeys;
QCheckBox *_currentUseShortCircuitEvaluation;
QCheckBox *_currentSkipOnStartup; QCheckBox *_currentSkipOnStartup;
QCheckBox *_currentStopActionsIfNotDone; QCheckBox *_currentStopActionsIfNotDone;
MacroInputSelection *_currentInputs; MacroInputSelection *_currentInputs;

View File

@ -87,7 +87,8 @@ bool AdvSceneSwitcher::AddNewMacro(std::shared_ptr<Macro> &res,
} }
res = std::make_shared<Macro>( res = std::make_shared<Macro>(
name, GetGlobalMacroSettings()._newMacroRegisterHotkeys); name, GetGlobalMacroSettings()._newMacroRegisterHotkeys,
GetGlobalMacroSettings()._newMacroUseShortCircuitEvaluation);
return true; return true;
} }

View File

@ -76,13 +76,15 @@ namespace advss {
static std::deque<std::shared_ptr<Macro>> macros; static std::deque<std::shared_ptr<Macro>> macros;
Macro::Macro(const std::string &name, const bool addHotkey) Macro::Macro(const std::string &name, const bool addHotkey,
const bool shortCircuitEvaluation)
{ {
SetName(name); SetName(name);
if (addHotkey) { if (addHotkey) {
SetupHotkeys(); SetupHotkeys();
} }
_registerHotkeys = addHotkey; _registerHotkeys = addHotkey;
_useShortCircuitEvaluation = shortCircuitEvaluation;
} }
Macro::~Macro() Macro::~Macro()
@ -181,6 +183,61 @@ static bool checkCondition(const std::shared_ptr<MacroCondition> &condition)
return conditionMatched; return conditionMatched;
} }
bool Macro::CheckConditionHelper(
const std::shared_ptr<MacroCondition> &condition) const
{
bool conditionMatched = false;
bool wasEvaluated = false;
const auto evaluateCondition = [&condition, &conditionMatched,
&wasEvaluated]() -> bool {
conditionMatched = checkCondition(condition);
conditionMatched =
condition->CheckDurationModifier(conditionMatched);
wasEvaluated = true;
return conditionMatched;
};
const auto logicType = condition->GetLogicType();
if (logicType == Logic::Type::NONE) {
vblog(LOG_INFO, "ignoring condition '%s' for '%s'",
condition->GetId().c_str(), _name.c_str());
if (!_useShortCircuitEvaluation) {
(void)evaluateCondition();
}
return _matched;
}
bool result = _useShortCircuitEvaluation
// Evaluate the condition result if needed
? Logic::ApplyConditionLogic(logicType, _matched,
evaluateCondition,
_name.c_str())
// Evaluate the condition result right away
: Logic::ApplyConditionLogic(logicType, _matched,
evaluateCondition(),
_name.c_str());
const bool isNegativeLogicType = Logic::IsNegationType(logicType);
if (wasEvaluated && ((conditionMatched && !isNegativeLogicType) ||
(!conditionMatched && isNegativeLogicType))) {
condition->EnableHighlight();
}
if (VerboseLoggingEnabled()) {
if (wasEvaluated) {
blog(LOG_INFO, "condition %s returned %d",
condition->GetId().c_str(), conditionMatched);
} else {
blog(LOG_INFO,
"condition %s evaluation skipped (short circuit)",
condition->GetId().c_str());
}
}
return result;
}
bool Macro::CeckMatch(bool ignorePause) bool Macro::CeckMatch(bool ignorePause)
{ {
if (_isGroup) { if (_isGroup) {
@ -194,28 +251,7 @@ bool Macro::CeckMatch(bool ignorePause)
return false; return false;
} }
bool conditionMatched = checkCondition(condition); _matched = CheckConditionHelper(condition);
conditionMatched =
condition->CheckDurationModifier(conditionMatched);
const auto logicType = condition->GetLogicType();
if (logicType == Logic::Type::NONE) {
vblog(LOG_INFO, "ignoring condition '%s' for '%s'",
condition->GetId().c_str(), _name.c_str());
continue;
}
vblog(LOG_INFO, "condition %s returned %d",
condition->GetId().c_str(), conditionMatched);
const bool isNegativeLogicType =
Logic::IsNegationType(logicType);
if ((conditionMatched && !isNegativeLogicType) ||
(!conditionMatched && isNegativeLogicType)) {
condition->EnableHighlight();
}
_matched = Logic::ApplyConditionLogic(
logicType, _matched, conditionMatched, _name.c_str());
} }
vblog(LOG_INFO, "Macro %s returned %d", _name.c_str(), _matched); vblog(LOG_INFO, "Macro %s returned %d", _name.c_str(), _matched);
@ -394,6 +430,16 @@ void Macro::SetStopActionsIfNotDone(bool stopActionsIfNotDone)
_stopActionsIfNotDone = stopActionsIfNotDone; _stopActionsIfNotDone = stopActionsIfNotDone;
} }
void Macro::SetShortCircuitEvaluation(bool useShortCircuitEvaluation)
{
_useShortCircuitEvaluation = useShortCircuitEvaluation;
}
bool Macro::ShortCircuitEvaluationEnabled() const
{
return _useShortCircuitEvaluation;
}
void Macro::SetPaused(bool pause) void Macro::SetPaused(bool pause)
{ {
if (_paused && !pause) { if (_paused && !pause) {
@ -618,6 +664,8 @@ bool Macro::Save(obs_data_t *obj, bool saveForCopy) const
obs_data_set_bool(obj, "onChange", _performActionsOnChange); obs_data_set_bool(obj, "onChange", _performActionsOnChange);
obs_data_set_bool(obj, "skipExecOnStart", _skipExecOnStart); obs_data_set_bool(obj, "skipExecOnStart", _skipExecOnStart);
obs_data_set_bool(obj, "stopActionsIfNotDone", _stopActionsIfNotDone); obs_data_set_bool(obj, "stopActionsIfNotDone", _stopActionsIfNotDone);
obs_data_set_bool(obj, "useShortCircuitEvaluation",
_useShortCircuitEvaluation);
obs_data_set_bool(obj, "group", _isGroup); obs_data_set_bool(obj, "group", _isGroup);
if (_isGroup) { if (_isGroup) {
@ -681,6 +729,8 @@ bool Macro::Load(obs_data_t *obj)
_performActionsOnChange = obs_data_get_bool(obj, "onChange"); _performActionsOnChange = obs_data_get_bool(obj, "onChange");
_skipExecOnStart = obs_data_get_bool(obj, "skipExecOnStart"); _skipExecOnStart = obs_data_get_bool(obj, "skipExecOnStart");
_stopActionsIfNotDone = obs_data_get_bool(obj, "stopActionsIfNotDone"); _stopActionsIfNotDone = obs_data_get_bool(obj, "stopActionsIfNotDone");
_useShortCircuitEvaluation =
obs_data_get_bool(obj, "useShortCircuitEvaluation");
_isGroup = obs_data_get_bool(obj, "group"); _isGroup = obs_data_get_bool(obj, "group");
if (_isGroup) { if (_isGroup) {

View File

@ -23,7 +23,8 @@ class MacroDock;
class Macro { class Macro {
public: public:
Macro(const std::string &name = "", const bool addHotkey = false); Macro(const std::string &name = "", const bool addHotkey = false,
const bool shortCircuitEvaluation = false);
virtual ~Macro(); virtual ~Macro();
std::string Name() const { return _name; } std::string Name() const { return _name; }
@ -54,6 +55,9 @@ public:
void SetStopActionsIfNotDone(bool stopActionsIfNotDone); void SetStopActionsIfNotDone(bool stopActionsIfNotDone);
bool StopActionsIfNotDone() const { return _stopActionsIfNotDone; } bool StopActionsIfNotDone() const { return _stopActionsIfNotDone; }
void SetShortCircuitEvaluation(bool useShortCircuitEvaluation);
bool ShortCircuitEvaluationEnabled() const;
int RunCount() const { return _runCount; }; int RunCount() const { return _runCount; };
void ResetRunCount() { _runCount = 0; }; void ResetRunCount() { _runCount = 0; };
@ -149,6 +153,9 @@ private:
void ClearHotkeys() const; void ClearHotkeys() const;
void SetHotkeysDesc() const; void SetHotkeysDesc() const;
bool
CheckConditionHelper(const std::shared_ptr<MacroCondition> &) const;
bool RunActionsHelper( bool RunActionsHelper(
const std::deque<std::shared_ptr<MacroAction>> &actions, const std::deque<std::shared_ptr<MacroAction>> &actions,
bool ignorePause); bool ignorePause);
@ -179,6 +186,7 @@ private:
bool _isGroup = false; bool _isGroup = false;
bool _isCollapsed = false; bool _isCollapsed = false;
bool _useShortCircuitEvaluation = false;
bool _runInParallel = false; bool _runInParallel = false;
bool _matched = false; bool _matched = false;
bool _lastMatched = false; bool _lastMatched = false;

View File

@ -19,6 +19,15 @@ const std::map<Logic::Type, const char *> Logic::localeMap = {
bool Logic::ApplyConditionLogic(Type type, bool currentMatchResult, bool Logic::ApplyConditionLogic(Type type, bool currentMatchResult,
bool conditionMatched, const char *context) bool conditionMatched, const char *context)
{
return ApplyConditionLogic(
type, currentMatchResult,
[conditionMatched]() { return conditionMatched; }, context);
}
bool Logic::ApplyConditionLogic(Type type, bool currentMatchResult,
const std::function<bool()> &evaluateCondition,
const char *context)
{ {
if (!context) { if (!context) {
context = ""; context = "";
@ -26,22 +35,22 @@ bool Logic::ApplyConditionLogic(Type type, bool currentMatchResult,
switch (type) { switch (type) {
case Type::ROOT_NONE: case Type::ROOT_NONE:
return conditionMatched; return evaluateCondition();
case Type::ROOT_NOT: case Type::ROOT_NOT:
return !conditionMatched; return !evaluateCondition();
case Type::ROOT_LAST: case Type::ROOT_LAST:
break; break;
case Type::NONE: case Type::NONE:
vblog(LOG_INFO, "skipping condition check for '%s'", context); vblog(LOG_INFO, "skipping condition check for '%s'", context);
return currentMatchResult; return currentMatchResult;
case Type::AND: case Type::AND:
return currentMatchResult && conditionMatched; return currentMatchResult && evaluateCondition();
case Type::OR: case Type::OR:
return currentMatchResult || conditionMatched; return currentMatchResult || evaluateCondition();
case Type::AND_NOT: case Type::AND_NOT:
return currentMatchResult && !conditionMatched; return currentMatchResult && !evaluateCondition();
case Type::OR_NOT: case Type::OR_NOT:
return currentMatchResult || !conditionMatched; return currentMatchResult || !evaluateCondition();
case Type::LAST: case Type::LAST:
default: default:
blog(LOG_WARNING, "ignoring invalid logic check (%s)", context); blog(LOG_WARNING, "ignoring invalid logic check (%s)", context);

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include <functional>
#include <map> #include <map>
#include <obs-data.h> #include <obs-data.h>
#include <string> #include <string>
@ -39,6 +40,10 @@ public:
static bool ApplyConditionLogic(Type, bool currentMatchResult, static bool ApplyConditionLogic(Type, bool currentMatchResult,
bool conditionMatched, bool conditionMatched,
const char *context); const char *context);
static bool
ApplyConditionLogic(Type, bool currentMatchResult,
const std::function<bool()> &evaluateCondition,
const char *context);
static void PopulateLogicTypeSelection(QComboBox *list, static void PopulateLogicTypeSelection(QComboBox *list,
bool isRootCondition); bool isRootCondition);

View File

@ -171,3 +171,20 @@ TEST_CASE("Logic", "[conditon-logic]")
REQUIRE(advss::Logic::ApplyConditionLogic(logic, true, false, "")); REQUIRE(advss::Logic::ApplyConditionLogic(logic, true, false, ""));
REQUIRE(advss::Logic::ApplyConditionLogic(logic, true, true, "")); REQUIRE(advss::Logic::ApplyConditionLogic(logic, true, true, ""));
} }
TEST_CASE("Short circuit", "[conditon-logic]")
{
bool functionWasRun = false;
const auto testFunction = [&functionWasRun]() {
functionWasRun = true;
return true;
};
advss::Logic::ApplyConditionLogic(advss::Logic::Type::AND, false,
testFunction, "");
REQUIRE_FALSE(functionWasRun);
advss::Logic::ApplyConditionLogic(advss::Logic::Type::OR, false,
testFunction, "");
REQUIRE(functionWasRun);
}