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 
SetUp()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 
TEST_F(TestOnChangeThreshold,initializeThresholdExpectAllSensorsAreRegistered)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 
TEST_F(TestOnChangeThreshold,thresholdIsNotInitializeExpectNoActionCommit)61f763c9e3SSzymon Dompke TEST_F(TestOnChangeThreshold, thresholdIsNotInitializeExpectNoActionCommit)
62f763c9e3SSzymon Dompke {
63*b7b7e1b6SSzymon Dompke     EXPECT_CALL(actionMock, commit(_, _, _, _, _)).Times(0);
64f763c9e3SSzymon Dompke }
65f763c9e3SSzymon Dompke 
TEST_F(TestOnChangeThreshold,getLabeledParamsReturnsCorrectly)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 
TEST_F(TestOnChangeThreshold,firstReadingDoesNoActionCommit)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 
UpdatesOnChangeParams85f763c9e3SSzymon Dompke     OnChangeParams& Updates(std::vector<UpdateParams> val)
86f763c9e3SSzymon Dompke     {
87f763c9e3SSzymon Dompke         updates = std::move(val);
88f763c9e3SSzymon Dompke         return *this;
89f763c9e3SSzymon Dompke     }
90f763c9e3SSzymon Dompke 
ExpectedOnChangeParams91f763c9e3SSzymon Dompke     OnChangeParams& Expected(std::vector<ExpectedParams> val)
92f763c9e3SSzymon Dompke     {
93f763c9e3SSzymon Dompke         expected = std::move(val);
94f763c9e3SSzymon Dompke         return *this;
95f763c9e3SSzymon Dompke     }
96f763c9e3SSzymon Dompke 
PrintTo(const OnChangeParams & o,std::ostream * os)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 
TEST_P(TestOnChangeThresholdUpdates,senorsIsUpdatedMultipleTimes)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