diff --git a/libnymea-core/stateevaluator.cpp b/libnymea-core/stateevaluator.cpp index 3edf56f7..3719a896 100644 --- a/libnymea-core/stateevaluator.cpp +++ b/libnymea-core/stateevaluator.cpp @@ -99,28 +99,44 @@ void StateEvaluator::setOperatorType(Types::StateOperator operatorType) /*! Returns true, if all child evaluator conditions are true depending on the \l {Types::StateOperator}{StateOperator}.*/ bool StateEvaluator::evaluate() const { + qCDebug(dcRuleEngineDebug()) << "Evaluating StateEvaluator." << this << "Operator type" << m_operatorType << "Valid descriptor:" << m_stateDescriptor.isValid() << "Childs:" << m_childEvaluators.count(); + bool descriptorMatching = true; if (m_stateDescriptor.isValid()) { Device *device = NymeaCore::instance()->deviceManager()->findConfiguredDevice(m_stateDescriptor.deviceId()); if (!device) { qCWarning(dcRuleEngine) << "Device not existing!"; - return false; - } - if (!device->hasState(m_stateDescriptor.stateTypeId())) { - qCWarning(dcRuleEngine) << "Device found, but it does not appear to have such a state!"; - return false; - } - if (m_stateDescriptor != device->state(m_stateDescriptor.stateTypeId())) { - // state not matching - return false; + descriptorMatching = false; + } else { + DeviceClass deviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(device->deviceClassId()); + if (!device->hasState(m_stateDescriptor.stateTypeId())) { + qCWarning(dcRuleEngine) << "Device found, but it does not appear to have such a state!"; + descriptorMatching = false; + } + if (m_stateDescriptor != device->state(m_stateDescriptor.stateTypeId())) { + // state not matching + qCDebug(dcRuleEngineDebug()) << "State" << device->name() << deviceClass.stateTypes().findById(m_stateDescriptor.stateTypeId()).name() << "not matching:" << m_stateDescriptor.stateValue() << "!=" << device->stateValue(m_stateDescriptor.stateTypeId()); + descriptorMatching = false; + } } } if (m_operatorType == Types::StateOperatorOr) { + if (m_stateDescriptor.isValid() && descriptorMatching) { + qCDebug(dcRuleEngineDebug()) << "Descriptor is matching. Operator is OR => Evaluation result: true"; + return true; + } foreach (const StateEvaluator &stateEvaluator, m_childEvaluators) { if (stateEvaluator.evaluate()) { + qCDebug(dcRuleEngineDebug()) << "Child evaluator evaluated to true. Operator is OR => Evaluation result: true"; return true; } } + qCDebug(dcRuleEngineDebug()) << "No child evaluator evaluated to true => Evaluation result: false"; + return false; + } + + if (!descriptorMatching) { + qCDebug(dcRuleEngineDebug()) << "Operator is AND => Evaluation result: false"; return false; } diff --git a/libnymea/types/deviceclass.cpp b/libnymea/types/deviceclass.cpp index c0e90449..743f8f24 100644 --- a/libnymea/types/deviceclass.cpp +++ b/libnymea/types/deviceclass.cpp @@ -300,7 +300,7 @@ void DeviceClass::setBasicTags(const QList &basicTags) /*! Returns the statesTypes of this DeviceClass. \{Device}{Devices} created from this \l{DeviceClass} must have their states matching to this template. */ -QList DeviceClass::stateTypes() const +StateTypes DeviceClass::stateTypes() const { return m_stateTypes; } diff --git a/libnymea/types/deviceclass.h b/libnymea/types/deviceclass.h index 2c12f5bc..5f015c7c 100644 --- a/libnymea/types/deviceclass.h +++ b/libnymea/types/deviceclass.h @@ -147,7 +147,7 @@ public: QList basicTags() const; void setBasicTags(const QList &basicTags); - QList stateTypes() const; + StateTypes stateTypes() const; StateType getStateType(const StateTypeId &stateTypeId); void setStateTypes(const QList &stateTypes); bool hasStateType(const StateTypeId &stateTypeId); diff --git a/libnymea/typeutils.h b/libnymea/typeutils.h index 602f218a..1a83b51f 100644 --- a/libnymea/typeutils.h +++ b/libnymea/typeutils.h @@ -63,10 +63,6 @@ DECLARE_TYPE_ID(PairingTransaction) class LIBNYMEA_EXPORT Types { Q_GADGET - Q_ENUMS(InputType) - Q_ENUMS(Unit) - Q_ENUMS(StateOperator) - Q_ENUMS(ValueOperator) public: enum InputType { @@ -81,6 +77,7 @@ public: InputTypeUrl, InputTypeMacAddress }; + Q_ENUM(InputType) enum Unit { UnitNone, @@ -134,6 +131,7 @@ public: UnitVoltAmpereReactive, UnitAmpereHour }; + Q_ENUM(Unit) enum ValueOperator { ValueOperatorEquals, @@ -143,10 +141,13 @@ public: ValueOperatorLessOrEqual, ValueOperatorGreaterOrEqual }; + Q_ENUM(ValueOperator) + enum StateOperator { StateOperatorAnd, StateOperatorOr }; + Q_ENUM(StateOperator) }; diff --git a/tests/auto/rules/testrules.cpp b/tests/auto/rules/testrules.cpp index 6b724001..49421001 100644 --- a/tests/auto/rules/testrules.cpp +++ b/tests/auto/rules/testrules.cpp @@ -86,6 +86,9 @@ private slots: void testStateEvaluator2_data(); void testStateEvaluator2(); + void testStateEvaluator3_data(); + void testStateEvaluator3(); + void testChildEvaluator_data(); void testChildEvaluator(); @@ -1647,6 +1650,34 @@ void TestRules::testStateEvaluator2() QVERIFY2(mainEvaluator.evaluate() == shouldMatch, shouldMatch ? "State should match" : "State shouldn't match"); } +void TestRules::testStateEvaluator3_data() +{ + testStateEvaluator2_data(); +} + +void TestRules::testStateEvaluator3() +{ + QFETCH(int, intValue); + QFETCH(Types::ValueOperator, intOperator); + QFETCH(bool, boolValue); + QFETCH(Types::ValueOperator, boolOperator); + QFETCH(Types::StateOperator, stateOperator); + QFETCH(bool, shouldMatch); + + StateDescriptor descriptor1(mockIntStateId, m_mockDeviceId, intValue, intOperator); + StateEvaluator childEvaluator(descriptor1); + + QList childEvaluators; + childEvaluators.append(childEvaluator); + + StateDescriptor descriptor2(mockBoolStateId, m_mockDeviceId, boolValue, boolOperator); + StateEvaluator mainEvaluator(descriptor2); + mainEvaluator.setChildEvaluators(childEvaluators); + mainEvaluator.setOperatorType(stateOperator); + + QVERIFY2(mainEvaluator.evaluate() == shouldMatch, shouldMatch ? "State should match" : "State shouldn't match"); +} + void TestRules::testChildEvaluator_data() { cleanup();