1f763c9e3SSzymon Dompke #include "dbus_environment.hpp" 2f763c9e3SSzymon Dompke #include "helpers.hpp" 3*b7b7e1b6SSzymon Dompke #include "mocks/clock_mock.hpp" 4f763c9e3SSzymon Dompke #include "mocks/sensor_mock.hpp" 5f763c9e3SSzymon Dompke #include "mocks/trigger_action_mock.hpp" 6f763c9e3SSzymon Dompke #include "on_change_threshold.hpp" 7f763c9e3SSzymon Dompke #include "utils/conv_container.hpp" 8f763c9e3SSzymon Dompke 9f763c9e3SSzymon Dompke #include <gmock/gmock.h> 10f763c9e3SSzymon Dompke 11f763c9e3SSzymon Dompke using namespace testing; 12f763c9e3SSzymon Dompke using namespace std::chrono_literals; 13f763c9e3SSzymon Dompke 14f763c9e3SSzymon Dompke class TestOnChangeThreshold : public Test 15f763c9e3SSzymon Dompke { 16f763c9e3SSzymon Dompke public: 17f763c9e3SSzymon Dompke std::vector<std::shared_ptr<SensorMock>> sensorMocks = { 18f763c9e3SSzymon Dompke std::make_shared<NiceMock<SensorMock>>(), 19f763c9e3SSzymon Dompke std::make_shared<NiceMock<SensorMock>>()}; 20f763c9e3SSzymon Dompke std::vector<std::string> sensorNames = {"Sensor1", "Sensor2"}; 21f763c9e3SSzymon Dompke std::unique_ptr<TriggerActionMock> actionMockPtr = 22f763c9e3SSzymon Dompke std::make_unique<StrictMock<TriggerActionMock>>(); 23f763c9e3SSzymon Dompke TriggerActionMock& actionMock = *actionMockPtr; 24f763c9e3SSzymon Dompke std::shared_ptr<OnChangeThreshold> sut; 25*b7b7e1b6SSzymon Dompke std::string triggerId = "MyTrigger"; 26*b7b7e1b6SSzymon Dompke std::unique_ptr<NiceMock<ClockMock>> clockMockPtr = 27*b7b7e1b6SSzymon Dompke std::make_unique<NiceMock<ClockMock>>(); 28f763c9e3SSzymon Dompke 29f763c9e3SSzymon Dompke void SetUp() override 30f763c9e3SSzymon Dompke { 31f763c9e3SSzymon Dompke std::vector<std::unique_ptr<interfaces::TriggerAction>> actions; 32f763c9e3SSzymon Dompke actions.push_back(std::move(actionMockPtr)); 33f763c9e3SSzymon Dompke 3494f71c51SSzymon Dompke for (size_t idx = 0; idx < sensorMocks.size(); idx++) 3594f71c51SSzymon Dompke { 3694f71c51SSzymon Dompke ON_CALL(*sensorMocks.at(idx), getName()) 3794f71c51SSzymon Dompke .WillByDefault(Return(sensorNames[idx])); 3894f71c51SSzymon Dompke } 3994f71c51SSzymon Dompke 40f763c9e3SSzymon Dompke sut = std::make_shared<OnChangeThreshold>( 41*b7b7e1b6SSzymon Dompke triggerId, 42f763c9e3SSzymon Dompke utils::convContainer<std::shared_ptr<interfaces::Sensor>>( 43f763c9e3SSzymon Dompke sensorMocks), 44*b7b7e1b6SSzymon Dompke std::move(actions), std::move(clockMockPtr)); 45f763c9e3SSzymon Dompke } 46f763c9e3SSzymon Dompke }; 47f763c9e3SSzymon Dompke 48f763c9e3SSzymon Dompke TEST_F(TestOnChangeThreshold, initializeThresholdExpectAllSensorsAreRegistered) 49f763c9e3SSzymon Dompke { 50f763c9e3SSzymon Dompke for (auto& sensor : sensorMocks) 51f763c9e3SSzymon Dompke { 52f763c9e3SSzymon Dompke EXPECT_CALL(*sensor, 53f763c9e3SSzymon Dompke registerForUpdates(Truly([sut = sut.get()](const auto& x) { 54f763c9e3SSzymon Dompke return x.lock().get() == sut; 55f763c9e3SSzymon Dompke }))); 56f763c9e3SSzymon Dompke } 57f763c9e3SSzymon Dompke 58f763c9e3SSzymon Dompke sut->initialize(); 59f763c9e3SSzymon Dompke } 60f763c9e3SSzymon Dompke 61f763c9e3SSzymon Dompke TEST_F(TestOnChangeThreshold, thresholdIsNotInitializeExpectNoActionCommit) 62f763c9e3SSzymon Dompke { 63*b7b7e1b6SSzymon Dompke EXPECT_CALL(actionMock, commit(_, _, _, _, _)).Times(0); 64f763c9e3SSzymon Dompke } 65f763c9e3SSzymon Dompke 6694f71c51SSzymon Dompke TEST_F(TestOnChangeThreshold, getLabeledParamsReturnsCorrectly) 6794f71c51SSzymon Dompke { 6894f71c51SSzymon Dompke LabeledThresholdParam expected = std::monostate(); 6994f71c51SSzymon Dompke EXPECT_EQ(sut->getThresholdParam(), expected); 7094f71c51SSzymon Dompke } 7194f71c51SSzymon Dompke 72620c65adSSzymon Dompke TEST_F(TestOnChangeThreshold, firstReadingDoesNoActionCommit) 73620c65adSSzymon Dompke { 74*b7b7e1b6SSzymon Dompke EXPECT_CALL(actionMock, commit(_, _, _, _, _)).Times(0); 75620c65adSSzymon Dompke 76620c65adSSzymon Dompke sut->initialize(); 77620c65adSSzymon Dompke sut->sensorUpdated(*sensorMocks.front(), 0ms, 42); 78620c65adSSzymon Dompke } 79620c65adSSzymon Dompke 80f763c9e3SSzymon Dompke struct OnChangeParams 81f763c9e3SSzymon Dompke { 82*b7b7e1b6SSzymon Dompke using UpdateParams = std::tuple<size_t, double>; 83*b7b7e1b6SSzymon Dompke using ExpectedParams = std::tuple<size_t, double>; 84f763c9e3SSzymon Dompke 85f763c9e3SSzymon Dompke OnChangeParams& Updates(std::vector<UpdateParams> val) 86f763c9e3SSzymon Dompke { 87f763c9e3SSzymon Dompke updates = std::move(val); 88f763c9e3SSzymon Dompke return *this; 89f763c9e3SSzymon Dompke } 90f763c9e3SSzymon Dompke 91f763c9e3SSzymon Dompke OnChangeParams& Expected(std::vector<ExpectedParams> val) 92f763c9e3SSzymon Dompke { 93f763c9e3SSzymon Dompke expected = std::move(val); 94f763c9e3SSzymon Dompke return *this; 95f763c9e3SSzymon Dompke } 96f763c9e3SSzymon Dompke 97f763c9e3SSzymon Dompke friend void PrintTo(const OnChangeParams& o, std::ostream* os) 98f763c9e3SSzymon Dompke { 99*b7b7e1b6SSzymon Dompke *os << "{ Updates: [ "; 100*b7b7e1b6SSzymon Dompke for (const auto& [index, value] : o.updates) 101f763c9e3SSzymon Dompke { 102*b7b7e1b6SSzymon Dompke *os << "{ SensorIndex: " << index << ", Value: " << value << " }, "; 103f763c9e3SSzymon Dompke } 104*b7b7e1b6SSzymon Dompke *os << " ] Expected: [ "; 105*b7b7e1b6SSzymon Dompke for (const auto& [index, value] : o.expected) 106f763c9e3SSzymon Dompke { 107*b7b7e1b6SSzymon Dompke *os << "{ SensorIndex: " << index << ", Value: " << value << " }, "; 108f763c9e3SSzymon Dompke } 109*b7b7e1b6SSzymon Dompke *os << " ] }"; 110f763c9e3SSzymon Dompke } 111f763c9e3SSzymon Dompke 112f763c9e3SSzymon Dompke std::vector<UpdateParams> updates; 113f763c9e3SSzymon Dompke std::vector<ExpectedParams> expected; 114f763c9e3SSzymon Dompke }; 115f763c9e3SSzymon Dompke 116f763c9e3SSzymon Dompke class TestOnChangeThresholdUpdates : 117f763c9e3SSzymon Dompke public TestOnChangeThreshold, 118f763c9e3SSzymon Dompke public WithParamInterface<OnChangeParams> 119f763c9e3SSzymon Dompke {}; 120f763c9e3SSzymon Dompke 121f763c9e3SSzymon Dompke INSTANTIATE_TEST_SUITE_P( 122f763c9e3SSzymon Dompke _, TestOnChangeThresholdUpdates, 123*b7b7e1b6SSzymon Dompke Values(OnChangeParams().Updates({{0, 80.0}}).Expected({{0, 80.0}}), 124f763c9e3SSzymon Dompke OnChangeParams() 125*b7b7e1b6SSzymon Dompke .Updates({{0, 80.0}, {1, 81.0}}) 126*b7b7e1b6SSzymon Dompke .Expected({{0, 80.0}, {1, 81.0}}), 127f763c9e3SSzymon Dompke OnChangeParams() 128*b7b7e1b6SSzymon Dompke .Updates({{0, 80.0}, {0, 90.0}}) 129*b7b7e1b6SSzymon Dompke .Expected({{0, 80.0}, {0, 90.0}}), 130f763c9e3SSzymon Dompke OnChangeParams() 131*b7b7e1b6SSzymon Dompke .Updates({{0, 80.0}, {1, 90.0}, {0, 90.0}}) 132*b7b7e1b6SSzymon Dompke .Expected({{0, 80.0}, {1, 90.0}, {0, 90.0}}), 133f763c9e3SSzymon Dompke OnChangeParams() 134*b7b7e1b6SSzymon Dompke .Updates({{0, 80.0}, {1, 80.0}, {1, 90.0}, {0, 90.0}}) 135*b7b7e1b6SSzymon Dompke .Expected({{0, 80.0}, {1, 80.0}, {1, 90.0}, {0, 90.0}}))); 136f763c9e3SSzymon Dompke 137f763c9e3SSzymon Dompke TEST_P(TestOnChangeThresholdUpdates, senorsIsUpdatedMultipleTimes) 138f763c9e3SSzymon Dompke { 139f763c9e3SSzymon Dompke InSequence seq; 140*b7b7e1b6SSzymon Dompke for (const auto& [index, value] : GetParam().expected) 141f763c9e3SSzymon Dompke { 142*b7b7e1b6SSzymon Dompke EXPECT_CALL(actionMock, 143*b7b7e1b6SSzymon Dompke commit(triggerId, Eq(std::nullopt), sensorNames[index], _, 144*b7b7e1b6SSzymon Dompke TriggerValue(value))); 145f763c9e3SSzymon Dompke } 146f763c9e3SSzymon Dompke 147f763c9e3SSzymon Dompke sut->initialize(); 148620c65adSSzymon Dompke 149620c65adSSzymon Dompke // First reading will be skipped 150620c65adSSzymon Dompke sut->sensorUpdated(*sensorMocks.front(), 0ms, 42); 151620c65adSSzymon Dompke 152*b7b7e1b6SSzymon Dompke for (const auto& [index, value] : GetParam().updates) 153f763c9e3SSzymon Dompke { 154*b7b7e1b6SSzymon Dompke sut->sensorUpdated(*sensorMocks[index], 42ms, value); 155f763c9e3SSzymon Dompke } 156f763c9e3SSzymon Dompke } 157