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